batman-adv: remove useless find_router look up
[deliverable/linux.git] / net / batman-adv / translation-table.c
CommitLineData
0b873931 1/* Copyright (C) 2007-2013 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
ced72933 30#include <linux/crc32c.h>
a73105b8 31
dec05074
AQ
32/* hash class keys */
33static struct lock_class_key batadv_tt_local_hash_lock_class_key;
34static struct lock_class_key batadv_tt_global_hash_lock_class_key;
35
56303d34
SE
36static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client,
37 struct batadv_orig_node *orig_node);
a513088d
SE
38static void batadv_tt_purge(struct work_struct *work);
39static void
56303d34 40batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry);
30cfd02b
AQ
41static void batadv_tt_global_del(struct batadv_priv *bat_priv,
42 struct batadv_orig_node *orig_node,
43 const unsigned char *addr,
44 const char *message, bool roaming);
c6c8fea2 45
7aadf889 46/* returns 1 if they are the same mac addr */
a513088d 47static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
7aadf889 48{
56303d34 49 const void *data1 = container_of(node, struct batadv_tt_common_entry,
747e4221 50 hash_entry);
7aadf889
ML
51
52 return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
53}
54
56303d34 55static struct batadv_tt_common_entry *
5bf74e9c 56batadv_tt_hash_find(struct batadv_hashtable *hash, const void *data)
7aadf889 57{
7aadf889 58 struct hlist_head *head;
56303d34
SE
59 struct batadv_tt_common_entry *tt_common_entry;
60 struct batadv_tt_common_entry *tt_common_entry_tmp = NULL;
c90681b8 61 uint32_t index;
7aadf889
ML
62
63 if (!hash)
64 return NULL;
65
da641193 66 index = batadv_choose_orig(data, hash->size);
7aadf889
ML
67 head = &hash->table[index];
68
69 rcu_read_lock();
b67bfe0d 70 hlist_for_each_entry_rcu(tt_common_entry, head, hash_entry) {
1eda58bf 71 if (!batadv_compare_eth(tt_common_entry, data))
7aadf889
ML
72 continue;
73
48100bac 74 if (!atomic_inc_not_zero(&tt_common_entry->refcount))
7683fdc1
AQ
75 continue;
76
48100bac 77 tt_common_entry_tmp = tt_common_entry;
7aadf889
ML
78 break;
79 }
80 rcu_read_unlock();
81
48100bac 82 return tt_common_entry_tmp;
7aadf889
ML
83}
84
56303d34
SE
85static struct batadv_tt_local_entry *
86batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const void *data)
7aadf889 87{
56303d34
SE
88 struct batadv_tt_common_entry *tt_common_entry;
89 struct batadv_tt_local_entry *tt_local_entry = NULL;
7aadf889 90
807736f6 91 tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, data);
48100bac
AQ
92 if (tt_common_entry)
93 tt_local_entry = container_of(tt_common_entry,
56303d34
SE
94 struct batadv_tt_local_entry,
95 common);
48100bac
AQ
96 return tt_local_entry;
97}
7aadf889 98
56303d34
SE
99static struct batadv_tt_global_entry *
100batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const void *data)
48100bac 101{
56303d34
SE
102 struct batadv_tt_common_entry *tt_common_entry;
103 struct batadv_tt_global_entry *tt_global_entry = NULL;
7683fdc1 104
807736f6 105 tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, data);
48100bac
AQ
106 if (tt_common_entry)
107 tt_global_entry = container_of(tt_common_entry,
56303d34
SE
108 struct batadv_tt_global_entry,
109 common);
48100bac 110 return tt_global_entry;
7aadf889
ML
111}
112
a513088d 113static void
56303d34 114batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry)
7683fdc1 115{
48100bac
AQ
116 if (atomic_dec_and_test(&tt_local_entry->common.refcount))
117 kfree_rcu(tt_local_entry, common.rcu);
7683fdc1
AQ
118}
119
21026059
AQ
120/**
121 * batadv_tt_global_entry_free_ref - decrement the refcounter for a
122 * tt_global_entry and possibly free it
123 * @tt_global_entry: the object to free
124 */
a513088d 125static void
56303d34 126batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry)
7683fdc1 127{
db08e6e5 128 if (atomic_dec_and_test(&tt_global_entry->common.refcount)) {
a513088d 129 batadv_tt_global_del_orig_list(tt_global_entry);
21026059 130 kfree_rcu(tt_global_entry, common.rcu);
db08e6e5
SW
131 }
132}
133
a513088d 134static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
db08e6e5 135{
56303d34 136 struct batadv_tt_orig_list_entry *orig_entry;
db08e6e5 137
56303d34 138 orig_entry = container_of(rcu, struct batadv_tt_orig_list_entry, rcu);
72822225
LL
139
140 /* We are in an rcu callback here, therefore we cannot use
141 * batadv_orig_node_free_ref() and its call_rcu():
142 * An rcu_barrier() wouldn't wait for that to finish
143 */
144 batadv_orig_node_free_ref_now(orig_entry->orig_node);
db08e6e5
SW
145 kfree(orig_entry);
146}
147
a513088d 148static void
56303d34 149batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry)
db08e6e5 150{
d657e621
AQ
151 if (!atomic_dec_and_test(&orig_entry->refcount))
152 return;
29cb99de
AQ
153 /* to avoid race conditions, immediately decrease the tt counter */
154 atomic_dec(&orig_entry->orig_node->tt_size);
a513088d 155 call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu);
7683fdc1
AQ
156}
157
3abe4adb
AQ
158/**
159 * batadv_tt_local_event - store a local TT event (ADD/DEL)
160 * @bat_priv: the bat priv with all the soft interface information
161 * @tt_local_entry: the TT entry involved in the event
162 * @event_flags: flags to store in the event structure
163 */
56303d34 164static void batadv_tt_local_event(struct batadv_priv *bat_priv,
3abe4adb
AQ
165 struct batadv_tt_local_entry *tt_local_entry,
166 uint8_t event_flags)
a73105b8 167{
56303d34 168 struct batadv_tt_change_node *tt_change_node, *entry, *safe;
3abe4adb
AQ
169 struct batadv_tt_common_entry *common = &tt_local_entry->common;
170 uint8_t flags = common->flags | event_flags;
3b643de5
AQ
171 bool event_removed = false;
172 bool del_op_requested, del_op_entry;
a73105b8
AQ
173
174 tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
a73105b8
AQ
175 if (!tt_change_node)
176 return;
177
ff66c975 178 tt_change_node->change.flags = flags;
e1bf0c14 179 tt_change_node->change.reserved = 0;
3abe4adb 180 memcpy(tt_change_node->change.addr, common->addr, ETH_ALEN);
a73105b8 181
acd34afa 182 del_op_requested = flags & BATADV_TT_CLIENT_DEL;
3b643de5
AQ
183
184 /* check for ADD+DEL or DEL+ADD events */
807736f6
SE
185 spin_lock_bh(&bat_priv->tt.changes_list_lock);
186 list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
3b643de5 187 list) {
3abe4adb 188 if (!batadv_compare_eth(entry->change.addr, common->addr))
3b643de5
AQ
189 continue;
190
191 /* DEL+ADD in the same orig interval have no effect and can be
192 * removed to avoid silly behaviour on the receiver side. The
193 * other way around (ADD+DEL) can happen in case of roaming of
194 * a client still in the NEW state. Roaming of NEW clients is
195 * now possible due to automatically recognition of "temporary"
196 * clients
197 */
acd34afa 198 del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL;
3b643de5
AQ
199 if (!del_op_requested && del_op_entry)
200 goto del;
201 if (del_op_requested && !del_op_entry)
202 goto del;
203 continue;
204del:
205 list_del(&entry->list);
206 kfree(entry);
155e4e12 207 kfree(tt_change_node);
3b643de5
AQ
208 event_removed = true;
209 goto unlock;
210 }
211
a73105b8 212 /* track the change in the OGMinterval list */
807736f6 213 list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list);
3b643de5
AQ
214
215unlock:
807736f6 216 spin_unlock_bh(&bat_priv->tt.changes_list_lock);
a73105b8 217
3b643de5 218 if (event_removed)
807736f6 219 atomic_dec(&bat_priv->tt.local_changes);
3b643de5 220 else
807736f6 221 atomic_inc(&bat_priv->tt.local_changes);
a73105b8
AQ
222}
223
335fbe0f
ML
224/**
225 * batadv_tt_len - compute length in bytes of given number of tt changes
226 * @changes_num: number of tt changes
227 *
228 * Returns computed length in bytes.
229 */
230static int batadv_tt_len(int changes_num)
a73105b8 231{
335fbe0f 232 return changes_num * sizeof(struct batadv_tvlv_tt_change);
a73105b8
AQ
233}
234
56303d34 235static int batadv_tt_local_init(struct batadv_priv *bat_priv)
c6c8fea2 236{
807736f6 237 if (bat_priv->tt.local_hash)
5346c35e 238 return 0;
c6c8fea2 239
807736f6 240 bat_priv->tt.local_hash = batadv_hash_new(1024);
c6c8fea2 241
807736f6 242 if (!bat_priv->tt.local_hash)
5346c35e 243 return -ENOMEM;
c6c8fea2 244
dec05074
AQ
245 batadv_hash_set_lock_class(bat_priv->tt.local_hash,
246 &batadv_tt_local_hash_lock_class_key);
247
5346c35e 248 return 0;
c6c8fea2
SE
249}
250
068ee6e2
AQ
251static void batadv_tt_global_free(struct batadv_priv *bat_priv,
252 struct batadv_tt_global_entry *tt_global,
253 const char *message)
254{
255 batadv_dbg(BATADV_DBG_TT, bat_priv,
256 "Deleting global tt entry %pM: %s\n",
257 tt_global->common.addr, message);
258
259 batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt,
260 batadv_choose_orig, tt_global->common.addr);
261 batadv_tt_global_entry_free_ref(tt_global);
068ee6e2
AQ
262}
263
08c36d3e
SE
264void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
265 int ifindex)
c6c8fea2 266{
56303d34 267 struct batadv_priv *bat_priv = netdev_priv(soft_iface);
170173bf
SE
268 struct batadv_tt_local_entry *tt_local;
269 struct batadv_tt_global_entry *tt_global;
db08e6e5 270 struct hlist_head *head;
56303d34 271 struct batadv_tt_orig_list_entry *orig_entry;
80b3f58c 272 int hash_added;
068ee6e2 273 bool roamed_back = false;
c6c8fea2 274
47c94655 275 tt_local = batadv_tt_local_hash_find(bat_priv, addr);
068ee6e2 276 tt_global = batadv_tt_global_hash_find(bat_priv, addr);
c6c8fea2 277
47c94655
AQ
278 if (tt_local) {
279 tt_local->last_seen = jiffies;
068ee6e2
AQ
280 if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) {
281 batadv_dbg(BATADV_DBG_TT, bat_priv,
282 "Re-adding pending client %pM\n", addr);
283 /* whatever the reason why the PENDING flag was set,
284 * this is a client which was enqueued to be removed in
285 * this orig_interval. Since it popped up again, the
286 * flag can be reset like it was never enqueued
287 */
288 tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING;
289 goto add_event;
290 }
291
292 if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) {
293 batadv_dbg(BATADV_DBG_TT, bat_priv,
294 "Roaming client %pM came back to its original location\n",
295 addr);
296 /* the ROAM flag is set because this client roamed away
297 * and the node got a roaming_advertisement message. Now
298 * that the client popped up again at its original
299 * location such flag can be unset
300 */
301 tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM;
302 roamed_back = true;
303 }
304 goto check_roaming;
c6c8fea2
SE
305 }
306
47c94655
AQ
307 tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC);
308 if (!tt_local)
7683fdc1 309 goto out;
a73105b8 310
39c75a51 311 batadv_dbg(BATADV_DBG_TT, bat_priv,
1eda58bf 312 "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
807736f6 313 (uint8_t)atomic_read(&bat_priv->tt.vn));
c6c8fea2 314
47c94655 315 memcpy(tt_local->common.addr, addr, ETH_ALEN);
8425ec6a
AQ
316 /* The local entry has to be marked as NEW to avoid to send it in
317 * a full table response going out before the next ttvn increment
318 * (consistency check)
319 */
320 tt_local->common.flags = BATADV_TT_CLIENT_NEW;
9563877e 321 if (batadv_is_wifi_iface(ifindex))
47c94655
AQ
322 tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
323 atomic_set(&tt_local->common.refcount, 2);
324 tt_local->last_seen = jiffies;
325 tt_local->common.added_at = tt_local->last_seen;
c6c8fea2
SE
326
327 /* the batman interface mac address should never be purged */
1eda58bf 328 if (batadv_compare_eth(addr, soft_iface->dev_addr))
47c94655 329 tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
c6c8fea2 330
807736f6 331 hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
47c94655
AQ
332 batadv_choose_orig, &tt_local->common,
333 &tt_local->common.hash_entry);
80b3f58c
SW
334
335 if (unlikely(hash_added != 0)) {
336 /* remove the reference for the hash */
47c94655 337 batadv_tt_local_entry_free_ref(tt_local);
80b3f58c
SW
338 goto out;
339 }
340
068ee6e2 341add_event:
3abe4adb 342 batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
ff66c975 343
068ee6e2
AQ
344check_roaming:
345 /* Check whether it is a roaming, but don't do anything if the roaming
346 * process has already been handled
347 */
348 if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) {
db08e6e5 349 /* These node are probably going to update their tt table */
47c94655 350 head = &tt_global->orig_list;
db08e6e5 351 rcu_read_lock();
b67bfe0d 352 hlist_for_each_entry_rcu(orig_entry, head, list) {
47c94655 353 batadv_send_roam_adv(bat_priv, tt_global->common.addr,
a513088d 354 orig_entry->orig_node);
db08e6e5
SW
355 }
356 rcu_read_unlock();
068ee6e2
AQ
357 if (roamed_back) {
358 batadv_tt_global_free(bat_priv, tt_global,
359 "Roaming canceled");
360 tt_global = NULL;
361 } else {
362 /* The global entry has to be marked as ROAMING and
363 * has to be kept for consistency purpose
364 */
365 tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
366 tt_global->roam_at = jiffies;
367 }
7683fdc1 368 }
068ee6e2 369
7683fdc1 370out:
47c94655
AQ
371 if (tt_local)
372 batadv_tt_local_entry_free_ref(tt_local);
373 if (tt_global)
374 batadv_tt_global_entry_free_ref(tt_global);
c6c8fea2
SE
375}
376
e1bf0c14
ML
377/**
378 * batadv_tt_tvlv_container_update - update the translation table tvlv container
379 * after local tt changes have been committed
380 * @bat_priv: the bat priv with all the soft interface information
381 */
382static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
be9aa4c1 383{
e1bf0c14
ML
384 struct batadv_tt_change_node *entry, *safe;
385 struct batadv_tvlv_tt_data *tt_data;
386 struct batadv_tvlv_tt_change *tt_change;
387 int tt_diff_len = 0, tt_change_len = 0;
388 int tt_diff_entries_num = 0, tt_diff_entries_count = 0;
be9aa4c1 389
e1bf0c14 390 tt_diff_len += batadv_tt_len(atomic_read(&bat_priv->tt.local_changes));
be9aa4c1
ML
391
392 /* if we have too many changes for one packet don't send any
393 * and wait for the tt table request which will be fragmented
394 */
e1bf0c14
ML
395 if (tt_diff_len > bat_priv->soft_iface->mtu)
396 tt_diff_len = 0;
be9aa4c1 397
e1bf0c14
ML
398 tt_data = kzalloc(sizeof(*tt_data) + tt_diff_len, GFP_ATOMIC);
399 if (!tt_data)
400 return;
be9aa4c1 401
e1bf0c14
ML
402 tt_data->flags = BATADV_TT_OGM_DIFF;
403 tt_data->ttvn = atomic_read(&bat_priv->tt.vn);
ced72933 404 tt_data->crc = htonl(bat_priv->tt.local_crc);
c6c8fea2 405
e1bf0c14
ML
406 if (tt_diff_len == 0)
407 goto container_register;
be9aa4c1 408
e1bf0c14 409 tt_diff_entries_num = tt_diff_len / batadv_tt_len(1);
c6c8fea2 410
807736f6
SE
411 spin_lock_bh(&bat_priv->tt.changes_list_lock);
412 atomic_set(&bat_priv->tt.local_changes, 0);
c6c8fea2 413
e1bf0c14
ML
414 tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1);
415
807736f6 416 list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
7c64fd98 417 list) {
e1bf0c14
ML
418 if (tt_diff_entries_count < tt_diff_entries_num) {
419 memcpy(tt_change + tt_diff_entries_count,
420 &entry->change,
421 sizeof(struct batadv_tvlv_tt_change));
422 tt_diff_entries_count++;
c6c8fea2 423 }
a73105b8
AQ
424 list_del(&entry->list);
425 kfree(entry);
c6c8fea2 426 }
807736f6 427 spin_unlock_bh(&bat_priv->tt.changes_list_lock);
a73105b8
AQ
428
429 /* Keep the buffer for possible tt_request */
807736f6
SE
430 spin_lock_bh(&bat_priv->tt.last_changeset_lock);
431 kfree(bat_priv->tt.last_changeset);
432 bat_priv->tt.last_changeset_len = 0;
433 bat_priv->tt.last_changeset = NULL;
e1bf0c14 434 tt_change_len = batadv_tt_len(tt_diff_entries_count);
be9aa4c1 435 /* check whether this new OGM has no changes due to size problems */
e1bf0c14 436 if (tt_diff_entries_count > 0) {
be9aa4c1 437 /* if kmalloc() fails we will reply with the full table
a73105b8
AQ
438 * instead of providing the diff
439 */
e1bf0c14 440 bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC);
807736f6 441 if (bat_priv->tt.last_changeset) {
e1bf0c14
ML
442 memcpy(bat_priv->tt.last_changeset,
443 tt_change, tt_change_len);
444 bat_priv->tt.last_changeset_len = tt_diff_len;
a73105b8
AQ
445 }
446 }
807736f6 447 spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
c6c8fea2 448
e1bf0c14
ML
449container_register:
450 batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data,
451 sizeof(*tt_data) + tt_change_len);
452 kfree(tt_data);
c6c8fea2
SE
453}
454
08c36d3e 455int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
c6c8fea2
SE
456{
457 struct net_device *net_dev = (struct net_device *)seq->private;
56303d34 458 struct batadv_priv *bat_priv = netdev_priv(net_dev);
807736f6 459 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
56303d34 460 struct batadv_tt_common_entry *tt_common_entry;
85766a82 461 struct batadv_tt_local_entry *tt_local;
56303d34 462 struct batadv_hard_iface *primary_if;
c6c8fea2 463 struct hlist_head *head;
c90681b8 464 uint32_t i;
85766a82
AQ
465 int last_seen_secs;
466 int last_seen_msecs;
467 unsigned long last_seen_jiffies;
468 bool no_purge;
469 uint16_t np_flag = BATADV_TT_CLIENT_NOPURGE;
c6c8fea2 470
30da63a6
ML
471 primary_if = batadv_seq_print_text_primary_if_get(seq);
472 if (!primary_if)
32ae9b22 473 goto out;
c6c8fea2 474
86ceb360 475 seq_printf(seq,
ced72933 476 "Locally retrieved addresses (from %s) announced via TT (TTVN: %u CRC: %#.8x):\n",
f9d8a537
AQ
477 net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn),
478 bat_priv->tt.local_crc);
85766a82
AQ
479 seq_printf(seq, " %-13s %-7s %-10s\n", "Client", "Flags",
480 "Last seen");
c6c8fea2 481
c6c8fea2
SE
482 for (i = 0; i < hash->size; i++) {
483 head = &hash->table[i];
484
7aadf889 485 rcu_read_lock();
b67bfe0d 486 hlist_for_each_entry_rcu(tt_common_entry,
7aadf889 487 head, hash_entry) {
85766a82
AQ
488 tt_local = container_of(tt_common_entry,
489 struct batadv_tt_local_entry,
490 common);
491 last_seen_jiffies = jiffies - tt_local->last_seen;
492 last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
493 last_seen_secs = last_seen_msecs / 1000;
494 last_seen_msecs = last_seen_msecs % 1000;
495
496 no_purge = tt_common_entry->flags & np_flag;
497
498 seq_printf(seq, " * %pM [%c%c%c%c%c] %3u.%03u\n",
7c64fd98
SE
499 tt_common_entry->addr,
500 (tt_common_entry->flags &
acd34afa 501 BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
85766a82 502 no_purge ? 'P' : '.',
7c64fd98 503 (tt_common_entry->flags &
acd34afa 504 BATADV_TT_CLIENT_NEW ? 'N' : '.'),
7c64fd98 505 (tt_common_entry->flags &
acd34afa 506 BATADV_TT_CLIENT_PENDING ? 'X' : '.'),
7c64fd98 507 (tt_common_entry->flags &
85766a82 508 BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
a7966d90
AQ
509 no_purge ? 0 : last_seen_secs,
510 no_purge ? 0 : last_seen_msecs);
c6c8fea2 511 }
7aadf889 512 rcu_read_unlock();
c6c8fea2 513 }
32ae9b22
ML
514out:
515 if (primary_if)
e5d89254 516 batadv_hardif_free_ref(primary_if);
30da63a6 517 return 0;
c6c8fea2
SE
518}
519
56303d34
SE
520static void
521batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
522 struct batadv_tt_local_entry *tt_local_entry,
523 uint16_t flags, const char *message)
c6c8fea2 524{
3abe4adb 525 batadv_tt_local_event(bat_priv, tt_local_entry, flags);
a73105b8 526
015758d0
AQ
527 /* The local client has to be marked as "pending to be removed" but has
528 * to be kept in the table in order to send it in a full table
9cfc7bd6
SE
529 * response issued before the net ttvn increment (consistency check)
530 */
acd34afa 531 tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
c566dbbe 532
39c75a51 533 batadv_dbg(BATADV_DBG_TT, bat_priv,
1eda58bf
SE
534 "Local tt entry (%pM) pending to be removed: %s\n",
535 tt_local_entry->common.addr, message);
c6c8fea2
SE
536}
537
7f91d06c
AQ
538/**
539 * batadv_tt_local_remove - logically remove an entry from the local table
540 * @bat_priv: the bat priv with all the soft interface information
541 * @addr: the MAC address of the client to remove
542 * @message: message to append to the log on deletion
543 * @roaming: true if the deletion is due to a roaming event
544 *
545 * Returns the flags assigned to the local entry before being deleted
546 */
547uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
548 const uint8_t *addr, const char *message,
549 bool roaming)
c6c8fea2 550{
170173bf 551 struct batadv_tt_local_entry *tt_local_entry;
7f91d06c 552 uint16_t flags, curr_flags = BATADV_NO_FLAGS;
c6c8fea2 553
a513088d 554 tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
7683fdc1
AQ
555 if (!tt_local_entry)
556 goto out;
557
7f91d06c
AQ
558 curr_flags = tt_local_entry->common.flags;
559
acd34afa 560 flags = BATADV_TT_CLIENT_DEL;
068ee6e2
AQ
561 /* if this global entry addition is due to a roaming, the node has to
562 * mark the local entry as "roamed" in order to correctly reroute
563 * packets later
564 */
7c1fd91d 565 if (roaming) {
acd34afa 566 flags |= BATADV_TT_CLIENT_ROAM;
7c1fd91d
AQ
567 /* mark the local client as ROAMed */
568 tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
569 }
42d0b044 570
068ee6e2
AQ
571 if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) {
572 batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags,
573 message);
574 goto out;
575 }
576 /* if this client has been added right now, it is possible to
577 * immediately purge it
578 */
3abe4adb 579 batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
068ee6e2
AQ
580 hlist_del_rcu(&tt_local_entry->common.hash_entry);
581 batadv_tt_local_entry_free_ref(tt_local_entry);
7f91d06c 582
7683fdc1
AQ
583out:
584 if (tt_local_entry)
a513088d 585 batadv_tt_local_entry_free_ref(tt_local_entry);
7f91d06c
AQ
586
587 return curr_flags;
c6c8fea2
SE
588}
589
56303d34 590static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
acd34afa 591 struct hlist_head *head)
c6c8fea2 592{
56303d34
SE
593 struct batadv_tt_local_entry *tt_local_entry;
594 struct batadv_tt_common_entry *tt_common_entry;
b67bfe0d 595 struct hlist_node *node_tmp;
acd34afa 596
b67bfe0d 597 hlist_for_each_entry_safe(tt_common_entry, node_tmp, head,
acd34afa
SE
598 hash_entry) {
599 tt_local_entry = container_of(tt_common_entry,
56303d34
SE
600 struct batadv_tt_local_entry,
601 common);
acd34afa
SE
602 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE)
603 continue;
604
605 /* entry already marked for deletion */
606 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
607 continue;
608
609 if (!batadv_has_timed_out(tt_local_entry->last_seen,
610 BATADV_TT_LOCAL_TIMEOUT))
611 continue;
612
613 batadv_tt_local_set_pending(bat_priv, tt_local_entry,
614 BATADV_TT_CLIENT_DEL, "timed out");
615 }
616}
617
56303d34 618static void batadv_tt_local_purge(struct batadv_priv *bat_priv)
acd34afa 619{
807736f6 620 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
c6c8fea2 621 struct hlist_head *head;
7683fdc1 622 spinlock_t *list_lock; /* protects write access to the hash lists */
c90681b8 623 uint32_t i;
c6c8fea2 624
c6c8fea2
SE
625 for (i = 0; i < hash->size; i++) {
626 head = &hash->table[i];
7683fdc1 627 list_lock = &hash->list_locks[i];
c6c8fea2 628
7683fdc1 629 spin_lock_bh(list_lock);
acd34afa 630 batadv_tt_local_purge_list(bat_priv, head);
7683fdc1 631 spin_unlock_bh(list_lock);
c6c8fea2 632 }
c6c8fea2
SE
633}
634
56303d34 635static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
c6c8fea2 636{
5bf74e9c 637 struct batadv_hashtable *hash;
a73105b8 638 spinlock_t *list_lock; /* protects write access to the hash lists */
56303d34
SE
639 struct batadv_tt_common_entry *tt_common_entry;
640 struct batadv_tt_local_entry *tt_local;
b67bfe0d 641 struct hlist_node *node_tmp;
7683fdc1 642 struct hlist_head *head;
c90681b8 643 uint32_t i;
a73105b8 644
807736f6 645 if (!bat_priv->tt.local_hash)
c6c8fea2
SE
646 return;
647
807736f6 648 hash = bat_priv->tt.local_hash;
a73105b8
AQ
649
650 for (i = 0; i < hash->size; i++) {
651 head = &hash->table[i];
652 list_lock = &hash->list_locks[i];
653
654 spin_lock_bh(list_lock);
b67bfe0d 655 hlist_for_each_entry_safe(tt_common_entry, node_tmp,
a73105b8 656 head, hash_entry) {
b67bfe0d 657 hlist_del_rcu(&tt_common_entry->hash_entry);
56303d34
SE
658 tt_local = container_of(tt_common_entry,
659 struct batadv_tt_local_entry,
660 common);
661 batadv_tt_local_entry_free_ref(tt_local);
a73105b8
AQ
662 }
663 spin_unlock_bh(list_lock);
664 }
665
1a8eaf07 666 batadv_hash_destroy(hash);
a73105b8 667
807736f6 668 bat_priv->tt.local_hash = NULL;
c6c8fea2
SE
669}
670
56303d34 671static int batadv_tt_global_init(struct batadv_priv *bat_priv)
c6c8fea2 672{
807736f6 673 if (bat_priv->tt.global_hash)
5346c35e 674 return 0;
c6c8fea2 675
807736f6 676 bat_priv->tt.global_hash = batadv_hash_new(1024);
c6c8fea2 677
807736f6 678 if (!bat_priv->tt.global_hash)
5346c35e 679 return -ENOMEM;
c6c8fea2 680
dec05074
AQ
681 batadv_hash_set_lock_class(bat_priv->tt.global_hash,
682 &batadv_tt_global_hash_lock_class_key);
683
5346c35e 684 return 0;
c6c8fea2
SE
685}
686
56303d34 687static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv)
c6c8fea2 688{
56303d34 689 struct batadv_tt_change_node *entry, *safe;
c6c8fea2 690
807736f6 691 spin_lock_bh(&bat_priv->tt.changes_list_lock);
c6c8fea2 692
807736f6 693 list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
a73105b8
AQ
694 list) {
695 list_del(&entry->list);
696 kfree(entry);
697 }
c6c8fea2 698
807736f6
SE
699 atomic_set(&bat_priv->tt.local_changes, 0);
700 spin_unlock_bh(&bat_priv->tt.changes_list_lock);
a73105b8 701}
c6c8fea2 702
d657e621
AQ
703/* retrieves the orig_tt_list_entry belonging to orig_node from the
704 * batadv_tt_global_entry list
705 *
706 * returns it with an increased refcounter, NULL if not found
db08e6e5 707 */
d657e621
AQ
708static struct batadv_tt_orig_list_entry *
709batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
710 const struct batadv_orig_node *orig_node)
db08e6e5 711{
d657e621 712 struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL;
db08e6e5 713 const struct hlist_head *head;
db08e6e5
SW
714
715 rcu_read_lock();
716 head = &entry->orig_list;
b67bfe0d 717 hlist_for_each_entry_rcu(tmp_orig_entry, head, list) {
d657e621
AQ
718 if (tmp_orig_entry->orig_node != orig_node)
719 continue;
720 if (!atomic_inc_not_zero(&tmp_orig_entry->refcount))
721 continue;
722
723 orig_entry = tmp_orig_entry;
724 break;
db08e6e5
SW
725 }
726 rcu_read_unlock();
d657e621
AQ
727
728 return orig_entry;
729}
730
731/* find out if an orig_node is already in the list of a tt_global_entry.
732 * returns true if found, false otherwise
733 */
734static bool
735batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
736 const struct batadv_orig_node *orig_node)
737{
738 struct batadv_tt_orig_list_entry *orig_entry;
739 bool found = false;
740
741 orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node);
742 if (orig_entry) {
743 found = true;
744 batadv_tt_orig_list_entry_free_ref(orig_entry);
745 }
746
db08e6e5
SW
747 return found;
748}
749
a513088d 750static void
d657e621 751batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
56303d34 752 struct batadv_orig_node *orig_node, int ttvn)
db08e6e5 753{
56303d34 754 struct batadv_tt_orig_list_entry *orig_entry;
db08e6e5 755
d657e621 756 orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node);
30cfd02b
AQ
757 if (orig_entry) {
758 /* refresh the ttvn: the current value could be a bogus one that
759 * was added during a "temporary client detection"
760 */
761 orig_entry->ttvn = ttvn;
d657e621 762 goto out;
30cfd02b 763 }
d657e621 764
db08e6e5
SW
765 orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC);
766 if (!orig_entry)
d657e621 767 goto out;
db08e6e5
SW
768
769 INIT_HLIST_NODE(&orig_entry->list);
770 atomic_inc(&orig_node->refcount);
771 atomic_inc(&orig_node->tt_size);
772 orig_entry->orig_node = orig_node;
773 orig_entry->ttvn = ttvn;
d657e621 774 atomic_set(&orig_entry->refcount, 2);
db08e6e5 775
d657e621 776 spin_lock_bh(&tt_global->list_lock);
db08e6e5 777 hlist_add_head_rcu(&orig_entry->list,
d657e621
AQ
778 &tt_global->orig_list);
779 spin_unlock_bh(&tt_global->list_lock);
780out:
781 if (orig_entry)
782 batadv_tt_orig_list_entry_free_ref(orig_entry);
db08e6e5
SW
783}
784
d4ff40f6
AQ
785/**
786 * batadv_tt_global_add - add a new TT global entry or update an existing one
787 * @bat_priv: the bat priv with all the soft interface information
788 * @orig_node: the originator announcing the client
789 * @tt_addr: the mac address of the non-mesh client
790 * @flags: TT flags that have to be set for this non-mesh client
791 * @ttvn: the tt version number ever announcing this non-mesh client
792 *
793 * Add a new TT global entry for the given originator. If the entry already
794 * exists add a new reference to the given originator (a global entry can have
795 * references to multiple originators) and adjust the flags attribute to reflect
796 * the function argument.
797 * If a TT local entry exists for this non-mesh client remove it.
798 *
799 * The caller must hold orig_node refcount.
1e5d49fc
AQ
800 *
801 * Return true if the new entry has been added, false otherwise
d4ff40f6 802 */
1e5d49fc
AQ
803static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
804 struct batadv_orig_node *orig_node,
805 const unsigned char *tt_addr, uint16_t flags,
806 uint8_t ttvn)
a73105b8 807{
170173bf
SE
808 struct batadv_tt_global_entry *tt_global_entry;
809 struct batadv_tt_local_entry *tt_local_entry;
1e5d49fc 810 bool ret = false;
80b3f58c 811 int hash_added;
56303d34 812 struct batadv_tt_common_entry *common;
7f91d06c 813 uint16_t local_flags;
c6c8fea2 814
a513088d 815 tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr);
068ee6e2
AQ
816 tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr);
817
818 /* if the node already has a local client for this entry, it has to wait
819 * for a roaming advertisement instead of manually messing up the global
820 * table
821 */
822 if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry &&
823 !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW))
824 goto out;
a73105b8
AQ
825
826 if (!tt_global_entry) {
d4f44692 827 tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC);
a73105b8 828 if (!tt_global_entry)
7683fdc1
AQ
829 goto out;
830
c0a55929
SE
831 common = &tt_global_entry->common;
832 memcpy(common->addr, tt_addr, ETH_ALEN);
db08e6e5 833
d4f44692 834 common->flags = flags;
cc47f66e 835 tt_global_entry->roam_at = 0;
fdf79320
AQ
836 /* node must store current time in case of roaming. This is
837 * needed to purge this entry out on timeout (if nobody claims
838 * it)
839 */
840 if (flags & BATADV_TT_CLIENT_ROAM)
841 tt_global_entry->roam_at = jiffies;
c0a55929 842 atomic_set(&common->refcount, 2);
30cfd02b 843 common->added_at = jiffies;
db08e6e5
SW
844
845 INIT_HLIST_HEAD(&tt_global_entry->orig_list);
846 spin_lock_init(&tt_global_entry->list_lock);
7683fdc1 847
807736f6 848 hash_added = batadv_hash_add(bat_priv->tt.global_hash,
a513088d
SE
849 batadv_compare_tt,
850 batadv_choose_orig, common,
851 &common->hash_entry);
80b3f58c
SW
852
853 if (unlikely(hash_added != 0)) {
854 /* remove the reference for the hash */
a513088d 855 batadv_tt_global_entry_free_ref(tt_global_entry);
80b3f58c
SW
856 goto out_remove;
857 }
a73105b8 858 } else {
068ee6e2 859 common = &tt_global_entry->common;
30cfd02b
AQ
860 /* If there is already a global entry, we can use this one for
861 * our processing.
068ee6e2
AQ
862 * But if we are trying to add a temporary client then here are
863 * two options at this point:
864 * 1) the global client is not a temporary client: the global
865 * client has to be left as it is, temporary information
866 * should never override any already known client state
867 * 2) the global client is a temporary client: purge the
868 * originator list and add the new one orig_entry
30cfd02b 869 */
068ee6e2
AQ
870 if (flags & BATADV_TT_CLIENT_TEMP) {
871 if (!(common->flags & BATADV_TT_CLIENT_TEMP))
872 goto out;
873 if (batadv_tt_global_entry_has_orig(tt_global_entry,
874 orig_node))
875 goto out_remove;
876 batadv_tt_global_del_orig_list(tt_global_entry);
877 goto add_orig_entry;
878 }
30cfd02b
AQ
879
880 /* if the client was temporary added before receiving the first
881 * OGM announcing it, we have to clear the TEMP flag
882 */
068ee6e2 883 common->flags &= ~BATADV_TT_CLIENT_TEMP;
db08e6e5 884
e9c00136
AQ
885 /* the change can carry possible "attribute" flags like the
886 * TT_CLIENT_WIFI, therefore they have to be copied in the
887 * client entry
888 */
889 tt_global_entry->common.flags |= flags;
890
acd34afa
SE
891 /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
892 * one originator left in the list and we previously received a
db08e6e5
SW
893 * delete + roaming change for this originator.
894 *
895 * We should first delete the old originator before adding the
896 * new one.
897 */
068ee6e2 898 if (common->flags & BATADV_TT_CLIENT_ROAM) {
a513088d 899 batadv_tt_global_del_orig_list(tt_global_entry);
068ee6e2 900 common->flags &= ~BATADV_TT_CLIENT_ROAM;
db08e6e5 901 tt_global_entry->roam_at = 0;
a73105b8
AQ
902 }
903 }
068ee6e2 904add_orig_entry:
30cfd02b 905 /* add the new orig_entry (if needed) or update it */
d657e621 906 batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn);
c6c8fea2 907
39c75a51 908 batadv_dbg(BATADV_DBG_TT, bat_priv,
1eda58bf 909 "Creating new global tt entry: %pM (via %pM)\n",
068ee6e2 910 common->addr, orig_node->orig);
1e5d49fc 911 ret = true;
c6c8fea2 912
80b3f58c 913out_remove:
7f91d06c 914
a73105b8 915 /* remove address from local hash if present */
7f91d06c
AQ
916 local_flags = batadv_tt_local_remove(bat_priv, tt_addr,
917 "global tt received",
c1d07431 918 flags & BATADV_TT_CLIENT_ROAM);
7f91d06c
AQ
919 tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI;
920
068ee6e2
AQ
921 if (!(flags & BATADV_TT_CLIENT_ROAM))
922 /* this is a normal global add. Therefore the client is not in a
923 * roaming state anymore.
924 */
925 tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
926
7683fdc1
AQ
927out:
928 if (tt_global_entry)
a513088d 929 batadv_tt_global_entry_free_ref(tt_global_entry);
068ee6e2
AQ
930 if (tt_local_entry)
931 batadv_tt_local_entry_free_ref(tt_local_entry);
7683fdc1 932 return ret;
c6c8fea2
SE
933}
934
981d8900
SE
935/* batadv_transtable_best_orig - Get best originator list entry from tt entry
936 * @tt_global_entry: global translation table entry to be analyzed
937 *
938 * This functon assumes the caller holds rcu_read_lock().
939 * Returns best originator list entry or NULL on errors.
940 */
941static struct batadv_tt_orig_list_entry *
942batadv_transtable_best_orig(struct batadv_tt_global_entry *tt_global_entry)
943{
944 struct batadv_neigh_node *router = NULL;
945 struct hlist_head *head;
981d8900
SE
946 struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL;
947 int best_tq = 0;
948
949 head = &tt_global_entry->orig_list;
b67bfe0d 950 hlist_for_each_entry_rcu(orig_entry, head, list) {
981d8900
SE
951 router = batadv_orig_node_get_router(orig_entry->orig_node);
952 if (!router)
953 continue;
954
955 if (router->tq_avg > best_tq) {
956 best_entry = orig_entry;
957 best_tq = router->tq_avg;
958 }
959
960 batadv_neigh_node_free_ref(router);
961 }
962
963 return best_entry;
964}
965
966/* batadv_tt_global_print_entry - print all orig nodes who announce the address
967 * for this global entry
968 * @tt_global_entry: global translation table entry to be printed
969 * @seq: debugfs table seq_file struct
970 *
971 * This functon assumes the caller holds rcu_read_lock().
db08e6e5 972 */
a513088d 973static void
56303d34 974batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry,
a513088d 975 struct seq_file *seq)
db08e6e5
SW
976{
977 struct hlist_head *head;
981d8900 978 struct batadv_tt_orig_list_entry *orig_entry, *best_entry;
56303d34 979 struct batadv_tt_common_entry *tt_common_entry;
db08e6e5
SW
980 uint16_t flags;
981 uint8_t last_ttvn;
982
983 tt_common_entry = &tt_global_entry->common;
981d8900
SE
984 flags = tt_common_entry->flags;
985
986 best_entry = batadv_transtable_best_orig(tt_global_entry);
987 if (best_entry) {
988 last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn);
f9d8a537 989 seq_printf(seq,
ced72933 990 " %c %pM (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n",
981d8900
SE
991 '*', tt_global_entry->common.addr,
992 best_entry->ttvn, best_entry->orig_node->orig,
f9d8a537 993 last_ttvn, best_entry->orig_node->tt_crc,
981d8900
SE
994 (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
995 (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
996 (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
997 }
db08e6e5
SW
998
999 head = &tt_global_entry->orig_list;
1000
b67bfe0d 1001 hlist_for_each_entry_rcu(orig_entry, head, list) {
981d8900
SE
1002 if (best_entry == orig_entry)
1003 continue;
1004
db08e6e5 1005 last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
981d8900
SE
1006 seq_printf(seq, " %c %pM (%3u) via %pM (%3u) [%c%c%c]\n",
1007 '+', tt_global_entry->common.addr,
1008 orig_entry->ttvn, orig_entry->orig_node->orig,
1009 last_ttvn,
acd34afa 1010 (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
30cfd02b
AQ
1011 (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
1012 (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
db08e6e5
SW
1013 }
1014}
1015
08c36d3e 1016int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset)
c6c8fea2
SE
1017{
1018 struct net_device *net_dev = (struct net_device *)seq->private;
56303d34 1019 struct batadv_priv *bat_priv = netdev_priv(net_dev);
807736f6 1020 struct batadv_hashtable *hash = bat_priv->tt.global_hash;
56303d34
SE
1021 struct batadv_tt_common_entry *tt_common_entry;
1022 struct batadv_tt_global_entry *tt_global;
1023 struct batadv_hard_iface *primary_if;
c6c8fea2 1024 struct hlist_head *head;
c90681b8 1025 uint32_t i;
c6c8fea2 1026
30da63a6
ML
1027 primary_if = batadv_seq_print_text_primary_if_get(seq);
1028 if (!primary_if)
32ae9b22 1029 goto out;
c6c8fea2 1030
2dafb49d
AQ
1031 seq_printf(seq,
1032 "Globally announced TT entries received via the mesh %s\n",
c6c8fea2 1033 net_dev->name);
ced72933 1034 seq_printf(seq, " %-13s %s %-15s %s (%-10s) %s\n",
f9d8a537
AQ
1035 "Client", "(TTVN)", "Originator", "(Curr TTVN)", "CRC",
1036 "Flags");
c6c8fea2 1037
c6c8fea2
SE
1038 for (i = 0; i < hash->size; i++) {
1039 head = &hash->table[i];
1040
7aadf889 1041 rcu_read_lock();
b67bfe0d 1042 hlist_for_each_entry_rcu(tt_common_entry,
7aadf889 1043 head, hash_entry) {
56303d34
SE
1044 tt_global = container_of(tt_common_entry,
1045 struct batadv_tt_global_entry,
1046 common);
1047 batadv_tt_global_print_entry(tt_global, seq);
c6c8fea2 1048 }
7aadf889 1049 rcu_read_unlock();
c6c8fea2 1050 }
32ae9b22
ML
1051out:
1052 if (primary_if)
e5d89254 1053 batadv_hardif_free_ref(primary_if);
30da63a6 1054 return 0;
c6c8fea2
SE
1055}
1056
db08e6e5 1057/* deletes the orig list of a tt_global_entry */
a513088d 1058static void
56303d34 1059batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry)
c6c8fea2 1060{
db08e6e5 1061 struct hlist_head *head;
b67bfe0d 1062 struct hlist_node *safe;
56303d34 1063 struct batadv_tt_orig_list_entry *orig_entry;
a73105b8 1064
db08e6e5
SW
1065 spin_lock_bh(&tt_global_entry->list_lock);
1066 head = &tt_global_entry->orig_list;
b67bfe0d
SL
1067 hlist_for_each_entry_safe(orig_entry, safe, head, list) {
1068 hlist_del_rcu(&orig_entry->list);
a513088d 1069 batadv_tt_orig_list_entry_free_ref(orig_entry);
db08e6e5
SW
1070 }
1071 spin_unlock_bh(&tt_global_entry->list_lock);
db08e6e5
SW
1072}
1073
a513088d 1074static void
56303d34
SE
1075batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv,
1076 struct batadv_tt_global_entry *tt_global_entry,
1077 struct batadv_orig_node *orig_node,
a513088d 1078 const char *message)
db08e6e5
SW
1079{
1080 struct hlist_head *head;
b67bfe0d 1081 struct hlist_node *safe;
56303d34 1082 struct batadv_tt_orig_list_entry *orig_entry;
db08e6e5
SW
1083
1084 spin_lock_bh(&tt_global_entry->list_lock);
1085 head = &tt_global_entry->orig_list;
b67bfe0d 1086 hlist_for_each_entry_safe(orig_entry, safe, head, list) {
db08e6e5 1087 if (orig_entry->orig_node == orig_node) {
39c75a51 1088 batadv_dbg(BATADV_DBG_TT, bat_priv,
1eda58bf
SE
1089 "Deleting %pM from global tt entry %pM: %s\n",
1090 orig_node->orig,
1091 tt_global_entry->common.addr, message);
b67bfe0d 1092 hlist_del_rcu(&orig_entry->list);
a513088d 1093 batadv_tt_orig_list_entry_free_ref(orig_entry);
db08e6e5
SW
1094 }
1095 }
1096 spin_unlock_bh(&tt_global_entry->list_lock);
1097}
1098
db08e6e5 1099/* If the client is to be deleted, we check if it is the last origantor entry
acd34afa
SE
1100 * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the
1101 * timer, otherwise we simply remove the originator scheduled for deletion.
db08e6e5 1102 */
a513088d 1103static void
56303d34
SE
1104batadv_tt_global_del_roaming(struct batadv_priv *bat_priv,
1105 struct batadv_tt_global_entry *tt_global_entry,
1106 struct batadv_orig_node *orig_node,
1107 const char *message)
db08e6e5
SW
1108{
1109 bool last_entry = true;
1110 struct hlist_head *head;
56303d34 1111 struct batadv_tt_orig_list_entry *orig_entry;
db08e6e5
SW
1112
1113 /* no local entry exists, case 1:
1114 * Check if this is the last one or if other entries exist.
1115 */
1116
1117 rcu_read_lock();
1118 head = &tt_global_entry->orig_list;
b67bfe0d 1119 hlist_for_each_entry_rcu(orig_entry, head, list) {
db08e6e5
SW
1120 if (orig_entry->orig_node != orig_node) {
1121 last_entry = false;
1122 break;
1123 }
1124 }
1125 rcu_read_unlock();
1126
1127 if (last_entry) {
1128 /* its the last one, mark for roaming. */
acd34afa 1129 tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
db08e6e5
SW
1130 tt_global_entry->roam_at = jiffies;
1131 } else
1132 /* there is another entry, we can simply delete this
1133 * one and can still use the other one.
1134 */
a513088d
SE
1135 batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry,
1136 orig_node, message);
db08e6e5
SW
1137}
1138
1139
1140
56303d34
SE
1141static void batadv_tt_global_del(struct batadv_priv *bat_priv,
1142 struct batadv_orig_node *orig_node,
a513088d
SE
1143 const unsigned char *addr,
1144 const char *message, bool roaming)
a73105b8 1145{
170173bf 1146 struct batadv_tt_global_entry *tt_global_entry;
56303d34 1147 struct batadv_tt_local_entry *local_entry = NULL;
a73105b8 1148
a513088d 1149 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
db08e6e5 1150 if (!tt_global_entry)
7683fdc1 1151 goto out;
a73105b8 1152
db08e6e5 1153 if (!roaming) {
a513088d
SE
1154 batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry,
1155 orig_node, message);
db08e6e5
SW
1156
1157 if (hlist_empty(&tt_global_entry->orig_list))
be73b488
AQ
1158 batadv_tt_global_free(bat_priv, tt_global_entry,
1159 message);
db08e6e5
SW
1160
1161 goto out;
1162 }
92f90f56
SE
1163
1164 /* if we are deleting a global entry due to a roam
1165 * event, there are two possibilities:
db08e6e5
SW
1166 * 1) the client roamed from node A to node B => if there
1167 * is only one originator left for this client, we mark
acd34afa 1168 * it with BATADV_TT_CLIENT_ROAM, we start a timer and we
92f90f56
SE
1169 * wait for node B to claim it. In case of timeout
1170 * the entry is purged.
db08e6e5
SW
1171 *
1172 * If there are other originators left, we directly delete
1173 * the originator.
92f90f56 1174 * 2) the client roamed to us => we can directly delete
9cfc7bd6
SE
1175 * the global entry, since it is useless now.
1176 */
a513088d
SE
1177 local_entry = batadv_tt_local_hash_find(bat_priv,
1178 tt_global_entry->common.addr);
1179 if (local_entry) {
db08e6e5 1180 /* local entry exists, case 2: client roamed to us. */
a513088d 1181 batadv_tt_global_del_orig_list(tt_global_entry);
be73b488 1182 batadv_tt_global_free(bat_priv, tt_global_entry, message);
db08e6e5
SW
1183 } else
1184 /* no local entry exists, case 1: check for roaming */
a513088d
SE
1185 batadv_tt_global_del_roaming(bat_priv, tt_global_entry,
1186 orig_node, message);
92f90f56 1187
92f90f56 1188
cc47f66e 1189out:
7683fdc1 1190 if (tt_global_entry)
a513088d
SE
1191 batadv_tt_global_entry_free_ref(tt_global_entry);
1192 if (local_entry)
1193 batadv_tt_local_entry_free_ref(local_entry);
a73105b8
AQ
1194}
1195
56303d34
SE
1196void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
1197 struct batadv_orig_node *orig_node,
1198 const char *message)
c6c8fea2 1199{
56303d34
SE
1200 struct batadv_tt_global_entry *tt_global;
1201 struct batadv_tt_common_entry *tt_common_entry;
c90681b8 1202 uint32_t i;
807736f6 1203 struct batadv_hashtable *hash = bat_priv->tt.global_hash;
b67bfe0d 1204 struct hlist_node *safe;
a73105b8 1205 struct hlist_head *head;
7683fdc1 1206 spinlock_t *list_lock; /* protects write access to the hash lists */
c6c8fea2 1207
6e801494
SW
1208 if (!hash)
1209 return;
1210
a73105b8
AQ
1211 for (i = 0; i < hash->size; i++) {
1212 head = &hash->table[i];
7683fdc1 1213 list_lock = &hash->list_locks[i];
c6c8fea2 1214
7683fdc1 1215 spin_lock_bh(list_lock);
b67bfe0d 1216 hlist_for_each_entry_safe(tt_common_entry, safe,
7c64fd98 1217 head, hash_entry) {
56303d34
SE
1218 tt_global = container_of(tt_common_entry,
1219 struct batadv_tt_global_entry,
1220 common);
db08e6e5 1221
56303d34 1222 batadv_tt_global_del_orig_entry(bat_priv, tt_global,
a513088d 1223 orig_node, message);
db08e6e5 1224
56303d34 1225 if (hlist_empty(&tt_global->orig_list)) {
39c75a51 1226 batadv_dbg(BATADV_DBG_TT, bat_priv,
1eda58bf 1227 "Deleting global tt entry %pM: %s\n",
56303d34 1228 tt_global->common.addr, message);
b67bfe0d 1229 hlist_del_rcu(&tt_common_entry->hash_entry);
56303d34 1230 batadv_tt_global_entry_free_ref(tt_global);
7683fdc1 1231 }
a73105b8 1232 }
7683fdc1 1233 spin_unlock_bh(list_lock);
c6c8fea2 1234 }
17071578 1235 orig_node->tt_initialised = false;
c6c8fea2
SE
1236}
1237
30cfd02b
AQ
1238static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
1239 char **msg)
cc47f66e 1240{
30cfd02b
AQ
1241 bool purge = false;
1242 unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT;
1243 unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT;
42d0b044 1244
30cfd02b
AQ
1245 if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
1246 batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
1247 purge = true;
1248 *msg = "Roaming timeout\n";
1249 }
42d0b044 1250
30cfd02b
AQ
1251 if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
1252 batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
1253 purge = true;
1254 *msg = "Temporary client timeout\n";
42d0b044 1255 }
30cfd02b
AQ
1256
1257 return purge;
42d0b044
SE
1258}
1259
30cfd02b 1260static void batadv_tt_global_purge(struct batadv_priv *bat_priv)
42d0b044 1261{
807736f6 1262 struct batadv_hashtable *hash = bat_priv->tt.global_hash;
cc47f66e 1263 struct hlist_head *head;
b67bfe0d 1264 struct hlist_node *node_tmp;
7683fdc1 1265 spinlock_t *list_lock; /* protects write access to the hash lists */
c90681b8 1266 uint32_t i;
30cfd02b
AQ
1267 char *msg = NULL;
1268 struct batadv_tt_common_entry *tt_common;
1269 struct batadv_tt_global_entry *tt_global;
cc47f66e 1270
cc47f66e
AQ
1271 for (i = 0; i < hash->size; i++) {
1272 head = &hash->table[i];
7683fdc1 1273 list_lock = &hash->list_locks[i];
cc47f66e 1274
7683fdc1 1275 spin_lock_bh(list_lock);
b67bfe0d 1276 hlist_for_each_entry_safe(tt_common, node_tmp, head,
30cfd02b
AQ
1277 hash_entry) {
1278 tt_global = container_of(tt_common,
1279 struct batadv_tt_global_entry,
1280 common);
1281
1282 if (!batadv_tt_global_to_purge(tt_global, &msg))
1283 continue;
1284
1285 batadv_dbg(BATADV_DBG_TT, bat_priv,
1286 "Deleting global tt entry (%pM): %s\n",
1287 tt_global->common.addr, msg);
1288
b67bfe0d 1289 hlist_del_rcu(&tt_common->hash_entry);
30cfd02b
AQ
1290
1291 batadv_tt_global_entry_free_ref(tt_global);
1292 }
7683fdc1 1293 spin_unlock_bh(list_lock);
cc47f66e 1294 }
cc47f66e
AQ
1295}
1296
56303d34 1297static void batadv_tt_global_table_free(struct batadv_priv *bat_priv)
c6c8fea2 1298{
5bf74e9c 1299 struct batadv_hashtable *hash;
7683fdc1 1300 spinlock_t *list_lock; /* protects write access to the hash lists */
56303d34
SE
1301 struct batadv_tt_common_entry *tt_common_entry;
1302 struct batadv_tt_global_entry *tt_global;
b67bfe0d 1303 struct hlist_node *node_tmp;
7683fdc1 1304 struct hlist_head *head;
c90681b8 1305 uint32_t i;
7683fdc1 1306
807736f6 1307 if (!bat_priv->tt.global_hash)
c6c8fea2
SE
1308 return;
1309
807736f6 1310 hash = bat_priv->tt.global_hash;
7683fdc1
AQ
1311
1312 for (i = 0; i < hash->size; i++) {
1313 head = &hash->table[i];
1314 list_lock = &hash->list_locks[i];
1315
1316 spin_lock_bh(list_lock);
b67bfe0d 1317 hlist_for_each_entry_safe(tt_common_entry, node_tmp,
7683fdc1 1318 head, hash_entry) {
b67bfe0d 1319 hlist_del_rcu(&tt_common_entry->hash_entry);
56303d34
SE
1320 tt_global = container_of(tt_common_entry,
1321 struct batadv_tt_global_entry,
1322 common);
1323 batadv_tt_global_entry_free_ref(tt_global);
7683fdc1
AQ
1324 }
1325 spin_unlock_bh(list_lock);
1326 }
1327
1a8eaf07 1328 batadv_hash_destroy(hash);
7683fdc1 1329
807736f6 1330 bat_priv->tt.global_hash = NULL;
c6c8fea2
SE
1331}
1332
56303d34
SE
1333static bool
1334_batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,
1335 struct batadv_tt_global_entry *tt_global_entry)
59b699cd
AQ
1336{
1337 bool ret = false;
1338
acd34afa
SE
1339 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI &&
1340 tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI)
59b699cd
AQ
1341 ret = true;
1342
1343 return ret;
1344}
1345
56303d34
SE
1346struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
1347 const uint8_t *src,
1348 const uint8_t *addr)
c6c8fea2 1349{
56303d34
SE
1350 struct batadv_tt_local_entry *tt_local_entry = NULL;
1351 struct batadv_tt_global_entry *tt_global_entry = NULL;
1352 struct batadv_orig_node *orig_node = NULL;
981d8900 1353 struct batadv_tt_orig_list_entry *best_entry;
c6c8fea2 1354
3d393e47 1355 if (src && atomic_read(&bat_priv->ap_isolation)) {
a513088d 1356 tt_local_entry = batadv_tt_local_hash_find(bat_priv, src);
068ee6e2
AQ
1357 if (!tt_local_entry ||
1358 (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
3d393e47
AQ
1359 goto out;
1360 }
7aadf889 1361
a513088d 1362 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
2dafb49d 1363 if (!tt_global_entry)
7b36e8ee 1364 goto out;
7aadf889 1365
3d393e47 1366 /* check whether the clients should not communicate due to AP
9cfc7bd6
SE
1367 * isolation
1368 */
a513088d
SE
1369 if (tt_local_entry &&
1370 _batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
3d393e47
AQ
1371 goto out;
1372
db08e6e5 1373 rcu_read_lock();
981d8900 1374 best_entry = batadv_transtable_best_orig(tt_global_entry);
db08e6e5 1375 /* found anything? */
981d8900
SE
1376 if (best_entry)
1377 orig_node = best_entry->orig_node;
db08e6e5
SW
1378 if (orig_node && !atomic_inc_not_zero(&orig_node->refcount))
1379 orig_node = NULL;
1380 rcu_read_unlock();
981d8900 1381
7b36e8ee 1382out:
3d393e47 1383 if (tt_global_entry)
a513088d 1384 batadv_tt_global_entry_free_ref(tt_global_entry);
3d393e47 1385 if (tt_local_entry)
a513088d 1386 batadv_tt_local_entry_free_ref(tt_local_entry);
3d393e47 1387
7b36e8ee 1388 return orig_node;
c6c8fea2 1389}
a73105b8 1390
ced72933
AQ
1391/**
1392 * batadv_tt_global_crc - calculates the checksum of the local table belonging
1393 * to the given orig_node
1394 * @bat_priv: the bat priv with all the soft interface information
1395 */
1396static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
56303d34 1397 struct batadv_orig_node *orig_node)
a73105b8 1398{
807736f6 1399 struct batadv_hashtable *hash = bat_priv->tt.global_hash;
56303d34
SE
1400 struct batadv_tt_common_entry *tt_common;
1401 struct batadv_tt_global_entry *tt_global;
a73105b8 1402 struct hlist_head *head;
ced72933 1403 uint32_t i, crc = 0;
a73105b8
AQ
1404
1405 for (i = 0; i < hash->size; i++) {
1406 head = &hash->table[i];
1407
1408 rcu_read_lock();
b67bfe0d 1409 hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
56303d34
SE
1410 tt_global = container_of(tt_common,
1411 struct batadv_tt_global_entry,
1412 common);
db08e6e5
SW
1413 /* Roaming clients are in the global table for
1414 * consistency only. They don't have to be
1415 * taken into account while computing the
1416 * global crc
1417 */
acd34afa 1418 if (tt_common->flags & BATADV_TT_CLIENT_ROAM)
db08e6e5 1419 continue;
30cfd02b
AQ
1420 /* Temporary clients have not been announced yet, so
1421 * they have to be skipped while computing the global
1422 * crc
1423 */
1424 if (tt_common->flags & BATADV_TT_CLIENT_TEMP)
1425 continue;
db08e6e5
SW
1426
1427 /* find out if this global entry is announced by this
1428 * originator
1429 */
56303d34 1430 if (!batadv_tt_global_entry_has_orig(tt_global,
a513088d 1431 orig_node))
db08e6e5
SW
1432 continue;
1433
ced72933 1434 crc ^= crc32c(0, tt_common->addr, ETH_ALEN);
a73105b8
AQ
1435 }
1436 rcu_read_unlock();
1437 }
1438
ced72933 1439 return crc;
a73105b8
AQ
1440}
1441
ced72933
AQ
1442/**
1443 * batadv_tt_local_crc - calculates the checksum of the local table
1444 * @bat_priv: the bat priv with all the soft interface information
1445 */
1446static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv)
a73105b8 1447{
807736f6 1448 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
56303d34 1449 struct batadv_tt_common_entry *tt_common;
a73105b8 1450 struct hlist_head *head;
ced72933 1451 uint32_t i, crc = 0;
a73105b8
AQ
1452
1453 for (i = 0; i < hash->size; i++) {
1454 head = &hash->table[i];
1455
1456 rcu_read_lock();
b67bfe0d 1457 hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
058d0e26 1458 /* not yet committed clients have not to be taken into
9cfc7bd6
SE
1459 * account while computing the CRC
1460 */
acd34afa 1461 if (tt_common->flags & BATADV_TT_CLIENT_NEW)
058d0e26 1462 continue;
ced72933
AQ
1463
1464 crc ^= crc32c(0, tt_common->addr, ETH_ALEN);
a73105b8 1465 }
a73105b8
AQ
1466 rcu_read_unlock();
1467 }
1468
ced72933 1469 return crc;
a73105b8
AQ
1470}
1471
56303d34 1472static void batadv_tt_req_list_free(struct batadv_priv *bat_priv)
a73105b8 1473{
56303d34 1474 struct batadv_tt_req_node *node, *safe;
a73105b8 1475
807736f6 1476 spin_lock_bh(&bat_priv->tt.req_list_lock);
a73105b8 1477
807736f6 1478 list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
a73105b8
AQ
1479 list_del(&node->list);
1480 kfree(node);
1481 }
1482
807736f6 1483 spin_unlock_bh(&bat_priv->tt.req_list_lock);
a73105b8
AQ
1484}
1485
56303d34
SE
1486static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv,
1487 struct batadv_orig_node *orig_node,
a513088d 1488 const unsigned char *tt_buff,
e1bf0c14 1489 uint16_t tt_num_changes)
a73105b8 1490{
08c36d3e 1491 uint16_t tt_buff_len = batadv_tt_len(tt_num_changes);
a73105b8
AQ
1492
1493 /* Replace the old buffer only if I received something in the
9cfc7bd6
SE
1494 * last OGM (the OGM could carry no changes)
1495 */
a73105b8
AQ
1496 spin_lock_bh(&orig_node->tt_buff_lock);
1497 if (tt_buff_len > 0) {
1498 kfree(orig_node->tt_buff);
1499 orig_node->tt_buff_len = 0;
1500 orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
1501 if (orig_node->tt_buff) {
1502 memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
1503 orig_node->tt_buff_len = tt_buff_len;
1504 }
1505 }
1506 spin_unlock_bh(&orig_node->tt_buff_lock);
1507}
1508
56303d34 1509static void batadv_tt_req_purge(struct batadv_priv *bat_priv)
a73105b8 1510{
56303d34 1511 struct batadv_tt_req_node *node, *safe;
a73105b8 1512
807736f6
SE
1513 spin_lock_bh(&bat_priv->tt.req_list_lock);
1514 list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
42d0b044
SE
1515 if (batadv_has_timed_out(node->issued_at,
1516 BATADV_TT_REQUEST_TIMEOUT)) {
a73105b8
AQ
1517 list_del(&node->list);
1518 kfree(node);
1519 }
1520 }
807736f6 1521 spin_unlock_bh(&bat_priv->tt.req_list_lock);
a73105b8
AQ
1522}
1523
1524/* returns the pointer to the new tt_req_node struct if no request
9cfc7bd6
SE
1525 * has already been issued for this orig_node, NULL otherwise
1526 */
56303d34
SE
1527static struct batadv_tt_req_node *
1528batadv_new_tt_req_node(struct batadv_priv *bat_priv,
1529 struct batadv_orig_node *orig_node)
a73105b8 1530{
56303d34 1531 struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
a73105b8 1532
807736f6
SE
1533 spin_lock_bh(&bat_priv->tt.req_list_lock);
1534 list_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) {
1eda58bf
SE
1535 if (batadv_compare_eth(tt_req_node_tmp, orig_node) &&
1536 !batadv_has_timed_out(tt_req_node_tmp->issued_at,
42d0b044 1537 BATADV_TT_REQUEST_TIMEOUT))
a73105b8
AQ
1538 goto unlock;
1539 }
1540
1541 tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
1542 if (!tt_req_node)
1543 goto unlock;
1544
1545 memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
1546 tt_req_node->issued_at = jiffies;
1547
807736f6 1548 list_add(&tt_req_node->list, &bat_priv->tt.req_list);
a73105b8 1549unlock:
807736f6 1550 spin_unlock_bh(&bat_priv->tt.req_list_lock);
a73105b8
AQ
1551 return tt_req_node;
1552}
1553
335fbe0f
ML
1554/**
1555 * batadv_tt_local_valid - verify that given tt entry is a valid one
1556 * @entry_ptr: to be checked local tt entry
1557 * @data_ptr: not used but definition required to satisfy the callback prototype
1558 *
1559 * Returns 1 if the entry is a valid, 0 otherwise.
1560 */
1561static int batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr)
058d0e26 1562{
56303d34 1563 const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
058d0e26 1564
acd34afa 1565 if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
058d0e26
AQ
1566 return 0;
1567 return 1;
1568}
1569
a513088d
SE
1570static int batadv_tt_global_valid(const void *entry_ptr,
1571 const void *data_ptr)
a73105b8 1572{
56303d34
SE
1573 const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
1574 const struct batadv_tt_global_entry *tt_global_entry;
1575 const struct batadv_orig_node *orig_node = data_ptr;
a73105b8 1576
30cfd02b
AQ
1577 if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ||
1578 tt_common_entry->flags & BATADV_TT_CLIENT_TEMP)
cc47f66e
AQ
1579 return 0;
1580
56303d34
SE
1581 tt_global_entry = container_of(tt_common_entry,
1582 struct batadv_tt_global_entry,
48100bac
AQ
1583 common);
1584
a513088d 1585 return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node);
a73105b8
AQ
1586}
1587
335fbe0f
ML
1588/**
1589 * batadv_tt_tvlv_generate - creates tvlv tt data buffer to fill it with the
1590 * tt entries from the specified tt hash
1591 * @bat_priv: the bat priv with all the soft interface information
1592 * @hash: hash table containing the tt entries
1593 * @tt_len: expected tvlv tt data buffer length in number of bytes
1594 * @valid_cb: function to filter tt change entries
1595 * @cb_data: data passed to the filter function as argument
1596 *
1597 * Returns pointer to allocated tvlv tt data buffer if operation was
1598 * successful or NULL otherwise.
1599 */
1600static struct batadv_tvlv_tt_data *
1601batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
1602 struct batadv_hashtable *hash, uint16_t tt_len,
1603 int (*valid_cb)(const void *, const void *),
1604 void *cb_data)
a73105b8 1605{
56303d34 1606 struct batadv_tt_common_entry *tt_common_entry;
335fbe0f
ML
1607 struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
1608 struct batadv_tvlv_tt_change *tt_change;
a73105b8 1609 struct hlist_head *head;
335fbe0f
ML
1610 uint16_t tt_tot, tt_num_entries = 0;
1611 ssize_t tvlv_tt_size = sizeof(struct batadv_tvlv_tt_data);
c90681b8 1612 uint32_t i;
a73105b8 1613
335fbe0f
ML
1614 if (tvlv_tt_size + tt_len > bat_priv->soft_iface->mtu) {
1615 tt_len = bat_priv->soft_iface->mtu - tvlv_tt_size;
1616 tt_len -= tt_len % sizeof(struct batadv_tvlv_tt_change);
a73105b8 1617 }
a73105b8 1618
335fbe0f 1619 tt_tot = tt_len / sizeof(struct batadv_tvlv_tt_change);
a73105b8 1620
335fbe0f
ML
1621 tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len,
1622 GFP_ATOMIC);
1623 if (!tvlv_tt_data)
1624 goto out;
a73105b8 1625
335fbe0f 1626 tt_change = (struct batadv_tvlv_tt_change *)(tvlv_tt_data + 1);
a73105b8
AQ
1627
1628 rcu_read_lock();
1629 for (i = 0; i < hash->size; i++) {
1630 head = &hash->table[i];
1631
b67bfe0d 1632 hlist_for_each_entry_rcu(tt_common_entry,
a73105b8 1633 head, hash_entry) {
335fbe0f 1634 if (tt_tot == tt_num_entries)
a73105b8
AQ
1635 break;
1636
48100bac 1637 if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
a73105b8
AQ
1638 continue;
1639
48100bac
AQ
1640 memcpy(tt_change->addr, tt_common_entry->addr,
1641 ETH_ALEN);
27b37ebf 1642 tt_change->flags = tt_common_entry->flags;
335fbe0f 1643 tt_change->reserved = 0;
a73105b8 1644
335fbe0f 1645 tt_num_entries++;
a73105b8
AQ
1646 tt_change++;
1647 }
1648 }
1649 rcu_read_unlock();
1650
1651out:
335fbe0f 1652 return tvlv_tt_data;
a73105b8
AQ
1653}
1654
ced72933
AQ
1655/**
1656 * batadv_send_tt_request - send a TT Request message to a given node
1657 * @bat_priv: the bat priv with all the soft interface information
1658 * @dst_orig_node: the destination of the message
1659 * @ttvn: the version number that the source of the message is looking for
1660 * @tt_crc: the CRC associated with the version number
1661 * @full_table: ask for the entire translation table if true, while only for the
1662 * last TT diff otherwise
1663 */
56303d34
SE
1664static int batadv_send_tt_request(struct batadv_priv *bat_priv,
1665 struct batadv_orig_node *dst_orig_node,
ced72933 1666 uint8_t ttvn, uint32_t tt_crc,
a513088d 1667 bool full_table)
a73105b8 1668{
335fbe0f 1669 struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
56303d34
SE
1670 struct batadv_hard_iface *primary_if;
1671 struct batadv_tt_req_node *tt_req_node = NULL;
335fbe0f 1672 bool ret = false;
a73105b8 1673
e5d89254 1674 primary_if = batadv_primary_if_get_selected(bat_priv);
a73105b8
AQ
1675 if (!primary_if)
1676 goto out;
1677
1678 /* The new tt_req will be issued only if I'm not waiting for a
9cfc7bd6
SE
1679 * reply from the same orig_node yet
1680 */
a513088d 1681 tt_req_node = batadv_new_tt_req_node(bat_priv, dst_orig_node);
a73105b8
AQ
1682 if (!tt_req_node)
1683 goto out;
1684
335fbe0f
ML
1685 tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data), GFP_ATOMIC);
1686 if (!tvlv_tt_data)
a73105b8
AQ
1687 goto out;
1688
335fbe0f
ML
1689 tvlv_tt_data->flags = BATADV_TT_REQUEST;
1690 tvlv_tt_data->ttvn = ttvn;
ced72933 1691 tvlv_tt_data->crc = htonl(tt_crc);
a73105b8
AQ
1692
1693 if (full_table)
335fbe0f 1694 tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
a73105b8 1695
bb351ba0 1696 batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n",
335fbe0f 1697 dst_orig_node->orig, full_table ? 'F' : '.');
a73105b8 1698
d69909d2 1699 batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX);
335fbe0f
ML
1700 batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
1701 dst_orig_node->orig, BATADV_TVLV_TT, 1,
1702 tvlv_tt_data, sizeof(*tvlv_tt_data));
1703 ret = true;
a73105b8
AQ
1704
1705out:
a73105b8 1706 if (primary_if)
e5d89254 1707 batadv_hardif_free_ref(primary_if);
a73105b8 1708 if (ret && tt_req_node) {
807736f6 1709 spin_lock_bh(&bat_priv->tt.req_list_lock);
a73105b8 1710 list_del(&tt_req_node->list);
807736f6 1711 spin_unlock_bh(&bat_priv->tt.req_list_lock);
a73105b8
AQ
1712 kfree(tt_req_node);
1713 }
335fbe0f 1714 kfree(tvlv_tt_data);
a73105b8
AQ
1715 return ret;
1716}
1717
335fbe0f
ML
1718/**
1719 * batadv_send_other_tt_response - send reply to tt request concerning another
1720 * node's translation table
1721 * @bat_priv: the bat priv with all the soft interface information
1722 * @tt_data: tt data containing the tt request information
1723 * @req_src: mac address of tt request sender
1724 * @req_dst: mac address of tt request recipient
1725 *
1726 * Returns true if tt request reply was sent, false otherwise.
1727 */
1728static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
1729 struct batadv_tvlv_tt_data *tt_data,
1730 uint8_t *req_src, uint8_t *req_dst)
a73105b8 1731{
170173bf 1732 struct batadv_orig_node *req_dst_orig_node;
56303d34 1733 struct batadv_orig_node *res_dst_orig_node = NULL;
335fbe0f
ML
1734 struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
1735 uint8_t orig_ttvn, req_ttvn;
1736 uint16_t tt_len;
1737 bool ret = false, full_table;
a73105b8 1738
39c75a51 1739 batadv_dbg(BATADV_DBG_TT, bat_priv,
1eda58bf 1740 "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n",
335fbe0f
ML
1741 req_src, tt_data->ttvn, req_dst,
1742 (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
a73105b8
AQ
1743
1744 /* Let's get the orig node of the REAL destination */
335fbe0f 1745 req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst);
a73105b8
AQ
1746 if (!req_dst_orig_node)
1747 goto out;
1748
335fbe0f 1749 res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src);
a73105b8
AQ
1750 if (!res_dst_orig_node)
1751 goto out;
1752
a73105b8 1753 orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
335fbe0f 1754 req_ttvn = tt_data->ttvn;
a73105b8 1755
335fbe0f 1756 /* this node doesn't have the requested data */
a73105b8 1757 if (orig_ttvn != req_ttvn ||
ced72933 1758 tt_data->crc != htonl(req_dst_orig_node->tt_crc))
a73105b8
AQ
1759 goto out;
1760
015758d0 1761 /* If the full table has been explicitly requested */
335fbe0f 1762 if (tt_data->flags & BATADV_TT_FULL_TABLE ||
a73105b8
AQ
1763 !req_dst_orig_node->tt_buff)
1764 full_table = true;
1765 else
1766 full_table = false;
1767
335fbe0f
ML
1768 /* TT fragmentation hasn't been implemented yet, so send as many
1769 * TT entries fit a single packet as possible only
9cfc7bd6 1770 */
a73105b8
AQ
1771 if (!full_table) {
1772 spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
1773 tt_len = req_dst_orig_node->tt_buff_len;
a73105b8 1774
335fbe0f
ML
1775 tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len,
1776 GFP_ATOMIC);
1777 if (!tvlv_tt_data)
a73105b8
AQ
1778 goto unlock;
1779
a73105b8 1780 /* Copy the last orig_node's OGM buffer */
335fbe0f 1781 memcpy(tvlv_tt_data + 1, req_dst_orig_node->tt_buff,
a73105b8 1782 req_dst_orig_node->tt_buff_len);
a73105b8
AQ
1783 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1784 } else {
96412690 1785 tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size);
335fbe0f
ML
1786 tt_len = batadv_tt_len(tt_len);
1787
1788 tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv,
1789 bat_priv->tt.global_hash,
1790 tt_len,
1791 batadv_tt_global_valid,
1792 req_dst_orig_node);
1793 if (!tvlv_tt_data)
a73105b8 1794 goto out;
a73105b8
AQ
1795 }
1796
335fbe0f
ML
1797 tvlv_tt_data->flags = BATADV_TT_RESPONSE;
1798 tvlv_tt_data->ttvn = req_ttvn;
a73105b8
AQ
1799
1800 if (full_table)
335fbe0f 1801 tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
a73105b8 1802
39c75a51 1803 batadv_dbg(BATADV_DBG_TT, bat_priv,
335fbe0f
ML
1804 "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n",
1805 res_dst_orig_node->orig, req_dst_orig_node->orig,
1806 full_table ? 'F' : '.', req_ttvn);
a73105b8 1807
d69909d2 1808 batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
f8214865 1809
335fbe0f
ML
1810 batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig,
1811 req_src, BATADV_TVLV_TT, 1,
1812 tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len);
e91ecfc6 1813
335fbe0f 1814 ret = true;
a73105b8
AQ
1815 goto out;
1816
1817unlock:
1818 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1819
1820out:
1821 if (res_dst_orig_node)
7d211efc 1822 batadv_orig_node_free_ref(res_dst_orig_node);
a73105b8 1823 if (req_dst_orig_node)
7d211efc 1824 batadv_orig_node_free_ref(req_dst_orig_node);
335fbe0f 1825 kfree(tvlv_tt_data);
a73105b8 1826 return ret;
a73105b8 1827}
96412690 1828
335fbe0f
ML
1829/**
1830 * batadv_send_my_tt_response - send reply to tt request concerning this node's
1831 * translation table
1832 * @bat_priv: the bat priv with all the soft interface information
1833 * @tt_data: tt data containing the tt request information
1834 * @req_src: mac address of tt request sender
1835 *
1836 * Returns true if tt request reply was sent, false otherwise.
1837 */
1838static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
1839 struct batadv_tvlv_tt_data *tt_data,
1840 uint8_t *req_src)
a73105b8 1841{
335fbe0f 1842 struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
170173bf 1843 struct batadv_orig_node *orig_node;
56303d34 1844 struct batadv_hard_iface *primary_if = NULL;
335fbe0f 1845 uint8_t my_ttvn, req_ttvn;
a73105b8 1846 bool full_table;
335fbe0f 1847 uint16_t tt_len;
a73105b8 1848
39c75a51 1849 batadv_dbg(BATADV_DBG_TT, bat_priv,
1eda58bf 1850 "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n",
335fbe0f
ML
1851 req_src, tt_data->ttvn,
1852 (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
a73105b8
AQ
1853
1854
807736f6 1855 my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn);
335fbe0f 1856 req_ttvn = tt_data->ttvn;
a73105b8 1857
335fbe0f 1858 orig_node = batadv_orig_hash_find(bat_priv, req_src);
a73105b8
AQ
1859 if (!orig_node)
1860 goto out;
1861
e5d89254 1862 primary_if = batadv_primary_if_get_selected(bat_priv);
a73105b8
AQ
1863 if (!primary_if)
1864 goto out;
1865
1866 /* If the full table has been explicitly requested or the gap
9cfc7bd6
SE
1867 * is too big send the whole local translation table
1868 */
335fbe0f 1869 if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn ||
807736f6 1870 !bat_priv->tt.last_changeset)
a73105b8
AQ
1871 full_table = true;
1872 else
1873 full_table = false;
1874
335fbe0f
ML
1875 /* TT fragmentation hasn't been implemented yet, so send as many
1876 * TT entries fit a single packet as possible only
9cfc7bd6 1877 */
a73105b8 1878 if (!full_table) {
807736f6
SE
1879 spin_lock_bh(&bat_priv->tt.last_changeset_lock);
1880 tt_len = bat_priv->tt.last_changeset_len;
a73105b8 1881
335fbe0f
ML
1882 tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len,
1883 GFP_ATOMIC);
1884 if (!tvlv_tt_data)
a73105b8
AQ
1885 goto unlock;
1886
335fbe0f
ML
1887 /* Copy the last orig_node's OGM buffer */
1888 memcpy(tvlv_tt_data + 1, bat_priv->tt.last_changeset,
807736f6
SE
1889 bat_priv->tt.last_changeset_len);
1890 spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
a73105b8 1891 } else {
807736f6 1892 tt_len = (uint16_t)atomic_read(&bat_priv->tt.local_entry_num);
335fbe0f
ML
1893 tt_len = batadv_tt_len(tt_len);
1894 req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn);
1895
1896 tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv,
1897 bat_priv->tt.local_hash,
1898 tt_len,
1899 batadv_tt_local_valid,
1900 NULL);
1901 if (!tvlv_tt_data)
a73105b8 1902 goto out;
a73105b8
AQ
1903 }
1904
335fbe0f
ML
1905 tvlv_tt_data->flags = BATADV_TT_RESPONSE;
1906 tvlv_tt_data->ttvn = req_ttvn;
a73105b8
AQ
1907
1908 if (full_table)
335fbe0f 1909 tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
a73105b8 1910
39c75a51 1911 batadv_dbg(BATADV_DBG_TT, bat_priv,
335fbe0f
ML
1912 "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n",
1913 orig_node->orig, full_table ? 'F' : '.', req_ttvn);
a73105b8 1914
d69909d2 1915 batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
f8214865 1916
335fbe0f
ML
1917 batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
1918 req_src, BATADV_TVLV_TT, 1,
1919 tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len);
1920
a73105b8
AQ
1921 goto out;
1922
1923unlock:
807736f6 1924 spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
a73105b8
AQ
1925out:
1926 if (orig_node)
7d211efc 1927 batadv_orig_node_free_ref(orig_node);
a73105b8 1928 if (primary_if)
e5d89254 1929 batadv_hardif_free_ref(primary_if);
335fbe0f
ML
1930 kfree(tvlv_tt_data);
1931 /* The packet was for this host, so it doesn't need to be re-routed */
a73105b8
AQ
1932 return true;
1933}
1934
335fbe0f
ML
1935/**
1936 * batadv_send_tt_response - send reply to tt request
1937 * @bat_priv: the bat priv with all the soft interface information
1938 * @tt_data: tt data containing the tt request information
1939 * @req_src: mac address of tt request sender
1940 * @req_dst: mac address of tt request recipient
1941 *
1942 * Returns true if tt request reply was sent, false otherwise.
1943 */
1944static bool batadv_send_tt_response(struct batadv_priv *bat_priv,
1945 struct batadv_tvlv_tt_data *tt_data,
1946 uint8_t *req_src, uint8_t *req_dst)
a73105b8 1947{
335fbe0f 1948 if (batadv_is_my_mac(bat_priv, req_dst)) {
20ff9d59 1949 /* don't answer backbone gws! */
335fbe0f 1950 if (batadv_bla_is_backbone_gw_orig(bat_priv, req_src))
20ff9d59
SW
1951 return true;
1952
335fbe0f 1953 return batadv_send_my_tt_response(bat_priv, tt_data, req_src);
20ff9d59 1954 } else {
335fbe0f
ML
1955 return batadv_send_other_tt_response(bat_priv, tt_data,
1956 req_src, req_dst);
20ff9d59 1957 }
a73105b8
AQ
1958}
1959
56303d34
SE
1960static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
1961 struct batadv_orig_node *orig_node,
335fbe0f 1962 struct batadv_tvlv_tt_change *tt_change,
a513088d 1963 uint16_t tt_num_changes, uint8_t ttvn)
a73105b8
AQ
1964{
1965 int i;
a513088d 1966 int roams;
a73105b8
AQ
1967
1968 for (i = 0; i < tt_num_changes; i++) {
acd34afa
SE
1969 if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) {
1970 roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM;
a513088d
SE
1971 batadv_tt_global_del(bat_priv, orig_node,
1972 (tt_change + i)->addr,
d4f44692
AQ
1973 "tt removed by changes",
1974 roams);
08c36d3e 1975 } else {
08c36d3e 1976 if (!batadv_tt_global_add(bat_priv, orig_node,
d4f44692
AQ
1977 (tt_change + i)->addr,
1978 (tt_change + i)->flags, ttvn))
a73105b8
AQ
1979 /* In case of problem while storing a
1980 * global_entry, we stop the updating
1981 * procedure without committing the
1982 * ttvn change. This will avoid to send
1983 * corrupted data on tt_request
1984 */
1985 return;
08c36d3e 1986 }
a73105b8 1987 }
17071578 1988 orig_node->tt_initialised = true;
a73105b8
AQ
1989}
1990
56303d34 1991static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
335fbe0f
ML
1992 struct batadv_tvlv_tt_data *tt_data,
1993 uint8_t *resp_src, uint16_t num_entries)
a73105b8 1994{
170173bf 1995 struct batadv_orig_node *orig_node;
a73105b8 1996
335fbe0f 1997 orig_node = batadv_orig_hash_find(bat_priv, resp_src);
a73105b8
AQ
1998 if (!orig_node)
1999 goto out;
2000
2001 /* Purge the old table first.. */
08c36d3e 2002 batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table");
a73105b8 2003
a513088d 2004 _batadv_tt_update_changes(bat_priv, orig_node,
335fbe0f
ML
2005 (struct batadv_tvlv_tt_change *)(tt_data + 1),
2006 num_entries, tt_data->ttvn);
a73105b8
AQ
2007
2008 spin_lock_bh(&orig_node->tt_buff_lock);
2009 kfree(orig_node->tt_buff);
2010 orig_node->tt_buff_len = 0;
2011 orig_node->tt_buff = NULL;
2012 spin_unlock_bh(&orig_node->tt_buff_lock);
2013
335fbe0f 2014 atomic_set(&orig_node->last_ttvn, tt_data->ttvn);
a73105b8
AQ
2015
2016out:
2017 if (orig_node)
7d211efc 2018 batadv_orig_node_free_ref(orig_node);
a73105b8
AQ
2019}
2020
56303d34
SE
2021static void batadv_tt_update_changes(struct batadv_priv *bat_priv,
2022 struct batadv_orig_node *orig_node,
a513088d 2023 uint16_t tt_num_changes, uint8_t ttvn,
335fbe0f 2024 struct batadv_tvlv_tt_change *tt_change)
a73105b8 2025{
a513088d
SE
2026 _batadv_tt_update_changes(bat_priv, orig_node, tt_change,
2027 tt_num_changes, ttvn);
a73105b8 2028
a513088d
SE
2029 batadv_tt_save_orig_buffer(bat_priv, orig_node,
2030 (unsigned char *)tt_change, tt_num_changes);
a73105b8
AQ
2031 atomic_set(&orig_node->last_ttvn, ttvn);
2032}
2033
56303d34 2034bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr)
a73105b8 2035{
170173bf 2036 struct batadv_tt_local_entry *tt_local_entry;
7683fdc1 2037 bool ret = false;
a73105b8 2038
a513088d 2039 tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
7683fdc1
AQ
2040 if (!tt_local_entry)
2041 goto out;
058d0e26 2042 /* Check if the client has been logically deleted (but is kept for
9cfc7bd6
SE
2043 * consistency purpose)
2044 */
7c1fd91d
AQ
2045 if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) ||
2046 (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM))
058d0e26 2047 goto out;
7683fdc1
AQ
2048 ret = true;
2049out:
a73105b8 2050 if (tt_local_entry)
a513088d 2051 batadv_tt_local_entry_free_ref(tt_local_entry);
7683fdc1 2052 return ret;
a73105b8
AQ
2053}
2054
335fbe0f
ML
2055/**
2056 * batadv_handle_tt_response - process incoming tt reply
2057 * @bat_priv: the bat priv with all the soft interface information
2058 * @tt_data: tt data containing the tt request information
2059 * @resp_src: mac address of tt reply sender
2060 * @num_entries: number of tt change entries appended to the tt data
2061 */
2062static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
2063 struct batadv_tvlv_tt_data *tt_data,
2064 uint8_t *resp_src, uint16_t num_entries)
a73105b8 2065{
56303d34
SE
2066 struct batadv_tt_req_node *node, *safe;
2067 struct batadv_orig_node *orig_node = NULL;
335fbe0f 2068 struct batadv_tvlv_tt_change *tt_change;
a73105b8 2069
39c75a51 2070 batadv_dbg(BATADV_DBG_TT, bat_priv,
1eda58bf 2071 "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n",
335fbe0f
ML
2072 resp_src, tt_data->ttvn, num_entries,
2073 (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
a73105b8 2074
20ff9d59 2075 /* we should have never asked a backbone gw */
335fbe0f 2076 if (batadv_bla_is_backbone_gw_orig(bat_priv, resp_src))
20ff9d59
SW
2077 goto out;
2078
335fbe0f 2079 orig_node = batadv_orig_hash_find(bat_priv, resp_src);
a73105b8
AQ
2080 if (!orig_node)
2081 goto out;
2082
335fbe0f
ML
2083 if (tt_data->flags & BATADV_TT_FULL_TABLE) {
2084 batadv_tt_fill_gtable(bat_priv, tt_data, resp_src, num_entries);
96412690 2085 } else {
335fbe0f
ML
2086 tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1);
2087 batadv_tt_update_changes(bat_priv, orig_node, num_entries,
2088 tt_data->ttvn, tt_change);
96412690 2089 }
a73105b8
AQ
2090
2091 /* Delete the tt_req_node from pending tt_requests list */
807736f6
SE
2092 spin_lock_bh(&bat_priv->tt.req_list_lock);
2093 list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
335fbe0f 2094 if (!batadv_compare_eth(node->addr, resp_src))
a73105b8
AQ
2095 continue;
2096 list_del(&node->list);
2097 kfree(node);
2098 }
807736f6 2099 spin_unlock_bh(&bat_priv->tt.req_list_lock);
a73105b8
AQ
2100
2101 /* Recalculate the CRC for this orig_node and store it */
a513088d 2102 orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
a73105b8
AQ
2103out:
2104 if (orig_node)
7d211efc 2105 batadv_orig_node_free_ref(orig_node);
a73105b8
AQ
2106}
2107
56303d34 2108static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv)
a73105b8 2109{
56303d34 2110 struct batadv_tt_roam_node *node, *safe;
a73105b8 2111
807736f6 2112 spin_lock_bh(&bat_priv->tt.roam_list_lock);
a73105b8 2113
807736f6 2114 list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
cc47f66e
AQ
2115 list_del(&node->list);
2116 kfree(node);
2117 }
2118
807736f6 2119 spin_unlock_bh(&bat_priv->tt.roam_list_lock);
cc47f66e
AQ
2120}
2121
56303d34 2122static void batadv_tt_roam_purge(struct batadv_priv *bat_priv)
cc47f66e 2123{
56303d34 2124 struct batadv_tt_roam_node *node, *safe;
cc47f66e 2125
807736f6
SE
2126 spin_lock_bh(&bat_priv->tt.roam_list_lock);
2127 list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
42d0b044
SE
2128 if (!batadv_has_timed_out(node->first_time,
2129 BATADV_ROAMING_MAX_TIME))
cc47f66e
AQ
2130 continue;
2131
2132 list_del(&node->list);
2133 kfree(node);
2134 }
807736f6 2135 spin_unlock_bh(&bat_priv->tt.roam_list_lock);
cc47f66e
AQ
2136}
2137
2138/* This function checks whether the client already reached the
2139 * maximum number of possible roaming phases. In this case the ROAMING_ADV
2140 * will not be sent.
2141 *
9cfc7bd6
SE
2142 * returns true if the ROAMING_ADV can be sent, false otherwise
2143 */
56303d34 2144static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv,
a513088d 2145 uint8_t *client)
cc47f66e 2146{
56303d34 2147 struct batadv_tt_roam_node *tt_roam_node;
cc47f66e
AQ
2148 bool ret = false;
2149
807736f6 2150 spin_lock_bh(&bat_priv->tt.roam_list_lock);
cc47f66e 2151 /* The new tt_req will be issued only if I'm not waiting for a
9cfc7bd6
SE
2152 * reply from the same orig_node yet
2153 */
807736f6 2154 list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) {
1eda58bf 2155 if (!batadv_compare_eth(tt_roam_node->addr, client))
cc47f66e
AQ
2156 continue;
2157
1eda58bf 2158 if (batadv_has_timed_out(tt_roam_node->first_time,
42d0b044 2159 BATADV_ROAMING_MAX_TIME))
cc47f66e
AQ
2160 continue;
2161
3e34819e 2162 if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter))
cc47f66e
AQ
2163 /* Sorry, you roamed too many times! */
2164 goto unlock;
2165 ret = true;
2166 break;
2167 }
2168
2169 if (!ret) {
2170 tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
2171 if (!tt_roam_node)
2172 goto unlock;
2173
2174 tt_roam_node->first_time = jiffies;
42d0b044
SE
2175 atomic_set(&tt_roam_node->counter,
2176 BATADV_ROAMING_MAX_COUNT - 1);
cc47f66e
AQ
2177 memcpy(tt_roam_node->addr, client, ETH_ALEN);
2178
807736f6 2179 list_add(&tt_roam_node->list, &bat_priv->tt.roam_list);
cc47f66e
AQ
2180 ret = true;
2181 }
2182
2183unlock:
807736f6 2184 spin_unlock_bh(&bat_priv->tt.roam_list_lock);
cc47f66e
AQ
2185 return ret;
2186}
2187
56303d34
SE
2188static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client,
2189 struct batadv_orig_node *orig_node)
cc47f66e 2190{
56303d34 2191 struct batadv_hard_iface *primary_if;
122edaa0
ML
2192 struct batadv_tvlv_roam_adv tvlv_roam;
2193
2194 primary_if = batadv_primary_if_get_selected(bat_priv);
2195 if (!primary_if)
2196 goto out;
cc47f66e
AQ
2197
2198 /* before going on we have to check whether the client has
9cfc7bd6
SE
2199 * already roamed to us too many times
2200 */
a513088d 2201 if (!batadv_tt_check_roam_count(bat_priv, client))
cc47f66e
AQ
2202 goto out;
2203
39c75a51 2204 batadv_dbg(BATADV_DBG_TT, bat_priv,
bb351ba0
MH
2205 "Sending ROAMING_ADV to %pM (client %pM)\n",
2206 orig_node->orig, client);
cc47f66e 2207
d69909d2 2208 batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX);
f8214865 2209
122edaa0
ML
2210 memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client));
2211 tvlv_roam.reserved = 0;
2212
2213 batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
2214 orig_node->orig, BATADV_TVLV_ROAM, 1,
2215 &tvlv_roam, sizeof(tvlv_roam));
cc47f66e
AQ
2216
2217out:
122edaa0
ML
2218 if (primary_if)
2219 batadv_hardif_free_ref(primary_if);
a73105b8
AQ
2220}
2221
a513088d 2222static void batadv_tt_purge(struct work_struct *work)
a73105b8 2223{
56303d34 2224 struct delayed_work *delayed_work;
807736f6 2225 struct batadv_priv_tt *priv_tt;
56303d34
SE
2226 struct batadv_priv *bat_priv;
2227
2228 delayed_work = container_of(work, struct delayed_work, work);
807736f6
SE
2229 priv_tt = container_of(delayed_work, struct batadv_priv_tt, work);
2230 bat_priv = container_of(priv_tt, struct batadv_priv, tt);
a73105b8 2231
a513088d 2232 batadv_tt_local_purge(bat_priv);
30cfd02b 2233 batadv_tt_global_purge(bat_priv);
a513088d
SE
2234 batadv_tt_req_purge(bat_priv);
2235 batadv_tt_roam_purge(bat_priv);
a73105b8 2236
72414442
AQ
2237 queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
2238 msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
a73105b8 2239}
cc47f66e 2240
56303d34 2241void batadv_tt_free(struct batadv_priv *bat_priv)
cc47f66e 2242{
e1bf0c14
ML
2243 batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1);
2244 batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1);
2245
807736f6 2246 cancel_delayed_work_sync(&bat_priv->tt.work);
cc47f66e 2247
a513088d
SE
2248 batadv_tt_local_table_free(bat_priv);
2249 batadv_tt_global_table_free(bat_priv);
2250 batadv_tt_req_list_free(bat_priv);
2251 batadv_tt_changes_list_free(bat_priv);
2252 batadv_tt_roam_list_free(bat_priv);
cc47f66e 2253
807736f6 2254 kfree(bat_priv->tt.last_changeset);
cc47f66e 2255}
058d0e26 2256
697f2531 2257/* This function will enable or disable the specified flags for all the entries
9cfc7bd6
SE
2258 * in the given hash table and returns the number of modified entries
2259 */
5bf74e9c
SE
2260static uint16_t batadv_tt_set_flags(struct batadv_hashtable *hash,
2261 uint16_t flags, bool enable)
058d0e26 2262{
c90681b8 2263 uint32_t i;
697f2531 2264 uint16_t changed_num = 0;
058d0e26 2265 struct hlist_head *head;
56303d34 2266 struct batadv_tt_common_entry *tt_common_entry;
058d0e26
AQ
2267
2268 if (!hash)
697f2531 2269 goto out;
058d0e26
AQ
2270
2271 for (i = 0; i < hash->size; i++) {
2272 head = &hash->table[i];
2273
2274 rcu_read_lock();
b67bfe0d 2275 hlist_for_each_entry_rcu(tt_common_entry,
058d0e26 2276 head, hash_entry) {
697f2531
AQ
2277 if (enable) {
2278 if ((tt_common_entry->flags & flags) == flags)
2279 continue;
2280 tt_common_entry->flags |= flags;
2281 } else {
2282 if (!(tt_common_entry->flags & flags))
2283 continue;
2284 tt_common_entry->flags &= ~flags;
2285 }
2286 changed_num++;
058d0e26
AQ
2287 }
2288 rcu_read_unlock();
2289 }
697f2531
AQ
2290out:
2291 return changed_num;
058d0e26
AQ
2292}
2293
acd34afa 2294/* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */
56303d34 2295static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
058d0e26 2296{
807736f6 2297 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
56303d34
SE
2298 struct batadv_tt_common_entry *tt_common;
2299 struct batadv_tt_local_entry *tt_local;
b67bfe0d 2300 struct hlist_node *node_tmp;
058d0e26
AQ
2301 struct hlist_head *head;
2302 spinlock_t *list_lock; /* protects write access to the hash lists */
c90681b8 2303 uint32_t i;
058d0e26
AQ
2304
2305 if (!hash)
2306 return;
2307
2308 for (i = 0; i < hash->size; i++) {
2309 head = &hash->table[i];
2310 list_lock = &hash->list_locks[i];
2311
2312 spin_lock_bh(list_lock);
b67bfe0d 2313 hlist_for_each_entry_safe(tt_common, node_tmp, head,
acd34afa
SE
2314 hash_entry) {
2315 if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING))
058d0e26
AQ
2316 continue;
2317
39c75a51 2318 batadv_dbg(BATADV_DBG_TT, bat_priv,
1eda58bf 2319 "Deleting local tt entry (%pM): pending\n",
acd34afa 2320 tt_common->addr);
058d0e26 2321
807736f6 2322 atomic_dec(&bat_priv->tt.local_entry_num);
b67bfe0d 2323 hlist_del_rcu(&tt_common->hash_entry);
56303d34
SE
2324 tt_local = container_of(tt_common,
2325 struct batadv_tt_local_entry,
2326 common);
2327 batadv_tt_local_entry_free_ref(tt_local);
058d0e26
AQ
2328 }
2329 spin_unlock_bh(list_lock);
2330 }
058d0e26
AQ
2331}
2332
e1bf0c14
ML
2333/**
2334 * batadv_tt_local_commit_changes - commit all pending local tt changes which
2335 * have been queued in the time since the last commit
2336 * @bat_priv: the bat priv with all the soft interface information
2337 */
2338void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
058d0e26 2339{
be9aa4c1
ML
2340 uint16_t changed_num = 0;
2341
e1bf0c14
ML
2342 if (atomic_read(&bat_priv->tt.local_changes) < 1) {
2343 if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
2344 batadv_tt_tvlv_container_update(bat_priv);
2345 return;
2346 }
be9aa4c1 2347
807736f6 2348 changed_num = batadv_tt_set_flags(bat_priv->tt.local_hash,
acd34afa 2349 BATADV_TT_CLIENT_NEW, false);
be9aa4c1
ML
2350
2351 /* all reset entries have to be counted as local entries */
807736f6 2352 atomic_add(changed_num, &bat_priv->tt.local_entry_num);
a513088d 2353 batadv_tt_local_purge_pending_clients(bat_priv);
807736f6 2354 bat_priv->tt.local_crc = batadv_tt_local_crc(bat_priv);
058d0e26
AQ
2355
2356 /* Increment the TTVN only once per OGM interval */
807736f6 2357 atomic_inc(&bat_priv->tt.vn);
39c75a51 2358 batadv_dbg(BATADV_DBG_TT, bat_priv,
1eda58bf 2359 "Local changes committed, updating to ttvn %u\n",
807736f6 2360 (uint8_t)atomic_read(&bat_priv->tt.vn));
be9aa4c1
ML
2361
2362 /* reset the sending counter */
807736f6 2363 atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
e1bf0c14 2364 batadv_tt_tvlv_container_update(bat_priv);
058d0e26 2365}
59b699cd 2366
56303d34 2367bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src,
08c36d3e 2368 uint8_t *dst)
59b699cd 2369{
56303d34
SE
2370 struct batadv_tt_local_entry *tt_local_entry = NULL;
2371 struct batadv_tt_global_entry *tt_global_entry = NULL;
5870adc6 2372 bool ret = false;
59b699cd
AQ
2373
2374 if (!atomic_read(&bat_priv->ap_isolation))
5870adc6 2375 goto out;
59b699cd 2376
a513088d 2377 tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst);
59b699cd
AQ
2378 if (!tt_local_entry)
2379 goto out;
2380
a513088d 2381 tt_global_entry = batadv_tt_global_hash_find(bat_priv, src);
59b699cd
AQ
2382 if (!tt_global_entry)
2383 goto out;
2384
1f129fef 2385 if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
59b699cd
AQ
2386 goto out;
2387
5870adc6 2388 ret = true;
59b699cd
AQ
2389
2390out:
2391 if (tt_global_entry)
a513088d 2392 batadv_tt_global_entry_free_ref(tt_global_entry);
59b699cd 2393 if (tt_local_entry)
a513088d 2394 batadv_tt_local_entry_free_ref(tt_local_entry);
59b699cd
AQ
2395 return ret;
2396}
a943cac1 2397
e1bf0c14
ML
2398/**
2399 * batadv_tt_update_orig - update global translation table with new tt
2400 * information received via ogms
2401 * @bat_priv: the bat priv with all the soft interface information
2402 * @orig: the orig_node of the ogm
2403 * @tt_buff: buffer holding the tt information
2404 * @tt_num_changes: number of tt changes inside the tt buffer
2405 * @ttvn: translation table version number of this changeset
ced72933 2406 * @tt_crc: crc32 checksum of orig node's translation table
e1bf0c14
ML
2407 */
2408static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
2409 struct batadv_orig_node *orig_node,
2410 const unsigned char *tt_buff,
2411 uint16_t tt_num_changes, uint8_t ttvn,
ced72933 2412 uint32_t tt_crc)
a943cac1
ML
2413{
2414 uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
2415 bool full_table = true;
335fbe0f 2416 struct batadv_tvlv_tt_change *tt_change;
a943cac1 2417
20ff9d59 2418 /* don't care about a backbone gateways updates. */
08adf151 2419 if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
20ff9d59
SW
2420 return;
2421
17071578 2422 /* orig table not initialised AND first diff is in the OGM OR the ttvn
9cfc7bd6
SE
2423 * increased by one -> we can apply the attached changes
2424 */
17071578
AQ
2425 if ((!orig_node->tt_initialised && ttvn == 1) ||
2426 ttvn - orig_ttvn == 1) {
a943cac1 2427 /* the OGM could not contain the changes due to their size or
42d0b044
SE
2428 * because they have already been sent BATADV_TT_OGM_APPEND_MAX
2429 * times.
9cfc7bd6
SE
2430 * In this case send a tt request
2431 */
a943cac1
ML
2432 if (!tt_num_changes) {
2433 full_table = false;
2434 goto request_table;
2435 }
2436
335fbe0f 2437 tt_change = (struct batadv_tvlv_tt_change *)tt_buff;
a513088d 2438 batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
96412690 2439 ttvn, tt_change);
a943cac1
ML
2440
2441 /* Even if we received the precomputed crc with the OGM, we
2442 * prefer to recompute it to spot any possible inconsistency
9cfc7bd6
SE
2443 * in the global table
2444 */
a513088d 2445 orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
a943cac1
ML
2446
2447 /* The ttvn alone is not enough to guarantee consistency
2448 * because a single value could represent different states
2449 * (due to the wrap around). Thus a node has to check whether
2450 * the resulting table (after applying the changes) is still
2451 * consistent or not. E.g. a node could disconnect while its
2452 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
2453 * checking the CRC value is mandatory to detect the
9cfc7bd6
SE
2454 * inconsistency
2455 */
a943cac1
ML
2456 if (orig_node->tt_crc != tt_crc)
2457 goto request_table;
a943cac1
ML
2458 } else {
2459 /* if we missed more than one change or our tables are not
9cfc7bd6
SE
2460 * in sync anymore -> request fresh tt data
2461 */
17071578
AQ
2462 if (!orig_node->tt_initialised || ttvn != orig_ttvn ||
2463 orig_node->tt_crc != tt_crc) {
a943cac1 2464request_table:
39c75a51 2465 batadv_dbg(BATADV_DBG_TT, bat_priv,
ced72933 2466 "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %#.8x last_crc: %#.8x num_changes: %u)\n",
1eda58bf
SE
2467 orig_node->orig, ttvn, orig_ttvn, tt_crc,
2468 orig_node->tt_crc, tt_num_changes);
a513088d
SE
2469 batadv_send_tt_request(bat_priv, orig_node, ttvn,
2470 tt_crc, full_table);
a943cac1
ML
2471 return;
2472 }
2473 }
2474}
3275e7cc
AQ
2475
2476/* returns true whether we know that the client has moved from its old
2477 * originator to another one. This entry is kept is still kept for consistency
2478 * purposes
2479 */
56303d34 2480bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
08c36d3e 2481 uint8_t *addr)
3275e7cc 2482{
56303d34 2483 struct batadv_tt_global_entry *tt_global_entry;
3275e7cc
AQ
2484 bool ret = false;
2485
a513088d 2486 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
3275e7cc
AQ
2487 if (!tt_global_entry)
2488 goto out;
2489
c1d07431 2490 ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
a513088d 2491 batadv_tt_global_entry_free_ref(tt_global_entry);
3275e7cc
AQ
2492out:
2493 return ret;
2494}
30cfd02b 2495
7c1fd91d
AQ
2496/**
2497 * batadv_tt_local_client_is_roaming - tells whether the client is roaming
2498 * @bat_priv: the bat priv with all the soft interface information
2499 * @addr: the MAC address of the local client to query
2500 *
2501 * Returns true if the local client is known to be roaming (it is not served by
2502 * this node anymore) or not. If yes, the client is still present in the table
2503 * to keep the latter consistent with the node TTVN
2504 */
2505bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
2506 uint8_t *addr)
2507{
2508 struct batadv_tt_local_entry *tt_local_entry;
2509 bool ret = false;
2510
2511 tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
2512 if (!tt_local_entry)
2513 goto out;
2514
2515 ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM;
2516 batadv_tt_local_entry_free_ref(tt_local_entry);
2517out:
2518 return ret;
7c1fd91d
AQ
2519}
2520
30cfd02b
AQ
2521bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
2522 struct batadv_orig_node *orig_node,
2523 const unsigned char *addr)
2524{
2525 bool ret = false;
2526
1f36aebc
AQ
2527 /* if the originator is a backbone node (meaning it belongs to the same
2528 * LAN of this node) the temporary client must not be added because to
2529 * reach such destination the node must use the LAN instead of the mesh
2530 */
2531 if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
2532 goto out;
2533
30cfd02b
AQ
2534 if (!batadv_tt_global_add(bat_priv, orig_node, addr,
2535 BATADV_TT_CLIENT_TEMP,
2536 atomic_read(&orig_node->last_ttvn)))
2537 goto out;
2538
2539 batadv_dbg(BATADV_DBG_TT, bat_priv,
2540 "Added temporary global client (addr: %pM orig: %pM)\n",
2541 addr, orig_node->orig);
2542 ret = true;
2543out:
2544 return ret;
2545}
e1bf0c14
ML
2546
2547/**
2548 * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container
2549 * @bat_priv: the bat priv with all the soft interface information
2550 * @orig: the orig_node of the ogm
2551 * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
2552 * @tvlv_value: tvlv buffer containing the gateway data
2553 * @tvlv_value_len: tvlv buffer length
2554 */
2555static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
2556 struct batadv_orig_node *orig,
2557 uint8_t flags,
2558 void *tvlv_value,
2559 uint16_t tvlv_value_len)
2560{
2561 struct batadv_tvlv_tt_data *tt_data;
2562 uint16_t num_entries;
2563
2564 if (tvlv_value_len < sizeof(*tt_data))
2565 return;
2566
2567 tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
2568 tvlv_value_len -= sizeof(*tt_data);
2569
2570 num_entries = tvlv_value_len / batadv_tt_len(1);
2571
2572 batadv_tt_update_orig(bat_priv, orig,
2573 (unsigned char *)(tt_data + 1),
ced72933 2574 num_entries, tt_data->ttvn, ntohl(tt_data->crc));
e1bf0c14
ML
2575}
2576
335fbe0f
ML
2577/**
2578 * batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv
2579 * container
2580 * @bat_priv: the bat priv with all the soft interface information
2581 * @src: mac address of tt tvlv sender
2582 * @dst: mac address of tt tvlv recipient
2583 * @tvlv_value: tvlv buffer containing the tt data
2584 * @tvlv_value_len: tvlv buffer length
2585 *
2586 * Returns NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS
2587 * otherwise.
2588 */
2589static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
2590 uint8_t *src, uint8_t *dst,
2591 void *tvlv_value,
2592 uint16_t tvlv_value_len)
2593{
2594 struct batadv_tvlv_tt_data *tt_data;
2595 uint16_t num_entries;
2596 char tt_flag;
2597 bool ret;
2598
2599 if (tvlv_value_len < sizeof(*tt_data))
2600 return NET_RX_SUCCESS;
2601
2602 tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
2603 tvlv_value_len -= sizeof(*tt_data);
2604
2605 num_entries = tvlv_value_len / batadv_tt_len(1);
2606
2607 switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) {
2608 case BATADV_TT_REQUEST:
2609 batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX);
2610
2611 /* If this node cannot provide a TT response the tt_request is
2612 * forwarded
2613 */
2614 ret = batadv_send_tt_response(bat_priv, tt_data, src, dst);
2615 if (!ret) {
2616 if (tt_data->flags & BATADV_TT_FULL_TABLE)
2617 tt_flag = 'F';
2618 else
2619 tt_flag = '.';
2620
2621 batadv_dbg(BATADV_DBG_TT, bat_priv,
2622 "Routing TT_REQUEST to %pM [%c]\n",
2623 dst, tt_flag);
2624 /* tvlv API will re-route the packet */
2625 return NET_RX_DROP;
2626 }
2627 break;
2628 case BATADV_TT_RESPONSE:
2629 batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX);
2630
2631 if (batadv_is_my_mac(bat_priv, dst)) {
2632 batadv_handle_tt_response(bat_priv, tt_data,
2633 src, num_entries);
2634 return NET_RX_SUCCESS;
2635 }
2636
2637 if (tt_data->flags & BATADV_TT_FULL_TABLE)
2638 tt_flag = 'F';
2639 else
2640 tt_flag = '.';
2641
2642 batadv_dbg(BATADV_DBG_TT, bat_priv,
2643 "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag);
2644
2645 /* tvlv API will re-route the packet */
2646 return NET_RX_DROP;
2647 }
2648
2649 return NET_RX_SUCCESS;
2650}
2651
122edaa0
ML
2652/**
2653 * batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container
2654 * @bat_priv: the bat priv with all the soft interface information
2655 * @src: mac address of tt tvlv sender
2656 * @dst: mac address of tt tvlv recipient
2657 * @tvlv_value: tvlv buffer containing the tt data
2658 * @tvlv_value_len: tvlv buffer length
2659 *
2660 * Returns NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS
2661 * otherwise.
2662 */
2663static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
2664 uint8_t *src, uint8_t *dst,
2665 void *tvlv_value,
2666 uint16_t tvlv_value_len)
2667{
2668 struct batadv_tvlv_roam_adv *roaming_adv;
2669 struct batadv_orig_node *orig_node = NULL;
2670
2671 /* If this node is not the intended recipient of the
2672 * roaming advertisement the packet is forwarded
2673 * (the tvlv API will re-route the packet).
2674 */
2675 if (!batadv_is_my_mac(bat_priv, dst))
2676 return NET_RX_DROP;
2677
2678 /* check if it is a backbone gateway. we don't accept
2679 * roaming advertisement from it, as it has the same
2680 * entries as we have.
2681 */
2682 if (batadv_bla_is_backbone_gw_orig(bat_priv, src))
2683 goto out;
2684
2685 if (tvlv_value_len < sizeof(*roaming_adv))
2686 goto out;
2687
2688 orig_node = batadv_orig_hash_find(bat_priv, src);
2689 if (!orig_node)
2690 goto out;
2691
2692 batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX);
2693 roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value;
2694
2695 batadv_dbg(BATADV_DBG_TT, bat_priv,
2696 "Received ROAMING_ADV from %pM (client %pM)\n",
2697 src, roaming_adv->client);
2698
2699 batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client,
2700 BATADV_TT_CLIENT_ROAM,
2701 atomic_read(&orig_node->last_ttvn) + 1);
2702
2703out:
2704 if (orig_node)
2705 batadv_orig_node_free_ref(orig_node);
2706 return NET_RX_SUCCESS;
2707}
2708
e1bf0c14
ML
2709/**
2710 * batadv_tt_init - initialise the translation table internals
2711 * @bat_priv: the bat priv with all the soft interface information
2712 *
2713 * Return 0 on success or negative error number in case of failure.
2714 */
2715int batadv_tt_init(struct batadv_priv *bat_priv)
2716{
2717 int ret;
2718
2719 ret = batadv_tt_local_init(bat_priv);
2720 if (ret < 0)
2721 return ret;
2722
2723 ret = batadv_tt_global_init(bat_priv);
2724 if (ret < 0)
2725 return ret;
2726
2727 batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1,
335fbe0f
ML
2728 batadv_tt_tvlv_unicast_handler_v1,
2729 BATADV_TVLV_TT, 1, BATADV_NO_FLAGS);
e1bf0c14 2730
122edaa0
ML
2731 batadv_tvlv_handler_register(bat_priv, NULL,
2732 batadv_roam_tvlv_unicast_handler_v1,
2733 BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS);
2734
e1bf0c14
ML
2735 INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge);
2736 queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
2737 msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
2738
2739 return 1;
2740}
This page took 0.37219 seconds and 5 git commands to generate.