Blame view
net/batman-adv/translation-table.c
110 KB
e19f9759e
|
1 |
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: |
c6c8fea29
|
2 |
* |
35c133a00
|
3 |
* Marek Lindner, Simon Wunderlich, Antonio Quartulli |
c6c8fea29
|
4 5 6 7 8 9 10 11 12 13 14 |
* * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License |
ebf38fb7a
|
15 |
* along with this program; if not, see <http://www.gnu.org/licenses/>. |
c6c8fea29
|
16 17 18 19 20 |
*/ #include "main.h" #include "translation-table.h" #include "soft-interface.h" |
32ae9b221
|
21 |
#include "hard-interface.h" |
a73105b8d
|
22 |
#include "send.h" |
c6c8fea29
|
23 24 |
#include "hash.h" #include "originator.h" |
a73105b8d
|
25 |
#include "routing.h" |
20ff9d593
|
26 |
#include "bridge_loop_avoidance.h" |
c5caf4ef3
|
27 |
#include "multicast.h" |
c6c8fea29
|
28 |
|
ced72933a
|
29 |
#include <linux/crc32c.h> |
a73105b8d
|
30 |
|
dec05074b
|
31 32 33 |
/* hash class keys */ static struct lock_class_key batadv_tt_local_hash_lock_class_key; static struct lock_class_key batadv_tt_global_hash_lock_class_key; |
56303d34a
|
34 |
static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, |
c018ad3de
|
35 |
unsigned short vid, |
56303d34a
|
36 |
struct batadv_orig_node *orig_node); |
a513088d0
|
37 38 |
static void batadv_tt_purge(struct work_struct *work); static void |
56303d34a
|
39 |
batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry); |
30cfd02b6
|
40 41 42 |
static void batadv_tt_global_del(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const unsigned char *addr, |
c018ad3de
|
43 44 |
unsigned short vid, const char *message, bool roaming); |
c6c8fea29
|
45 |
|
7aadf889e
|
46 |
/* returns 1 if they are the same mac addr */ |
a513088d0
|
47 |
static int batadv_compare_tt(const struct hlist_node *node, const void *data2) |
7aadf889e
|
48 |
{ |
56303d34a
|
49 |
const void *data1 = container_of(node, struct batadv_tt_common_entry, |
747e4221a
|
50 |
hash_entry); |
7aadf889e
|
51 |
|
323813ed2
|
52 |
return batadv_compare_eth(data1, data2); |
7aadf889e
|
53 |
} |
c018ad3de
|
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
/** * batadv_choose_tt - return the index of the tt entry in the hash table * @data: pointer to the tt_common_entry object to map * @size: the size of the hash table * * Returns the hash index where the object represented by 'data' should be * stored at. */ static inline uint32_t batadv_choose_tt(const void *data, uint32_t size) { struct batadv_tt_common_entry *tt; uint32_t hash = 0; tt = (struct batadv_tt_common_entry *)data; hash = batadv_hash_bytes(hash, &tt->addr, ETH_ALEN); hash = batadv_hash_bytes(hash, &tt->vid, sizeof(tt->vid)); hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return hash % size; } /** * batadv_tt_hash_find - look for a client in the given hash table * @hash: the hash table to search * @addr: the mac address of the client to look for * @vid: VLAN identifier * * Returns a pointer to the tt_common struct belonging to the searched client if * found, NULL otherwise. */ |
56303d34a
|
87 |
static struct batadv_tt_common_entry * |
c018ad3de
|
88 89 |
batadv_tt_hash_find(struct batadv_hashtable *hash, const uint8_t *addr, unsigned short vid) |
7aadf889e
|
90 |
{ |
7aadf889e
|
91 |
struct hlist_head *head; |
c018ad3de
|
92 |
struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL; |
c90681b85
|
93 |
uint32_t index; |
7aadf889e
|
94 95 96 |
if (!hash) return NULL; |
8fdd01530
|
97 |
ether_addr_copy(to_search.addr, addr); |
c018ad3de
|
98 99 100 |
to_search.vid = vid; index = batadv_choose_tt(&to_search, hash->size); |
7aadf889e
|
101 102 103 |
head = &hash->table[index]; rcu_read_lock(); |
c018ad3de
|
104 105 106 107 108 |
hlist_for_each_entry_rcu(tt, head, hash_entry) { if (!batadv_compare_eth(tt, addr)) continue; if (tt->vid != vid) |
7aadf889e
|
109 |
continue; |
c018ad3de
|
110 |
if (!atomic_inc_not_zero(&tt->refcount)) |
7683fdc1e
|
111 |
continue; |
c018ad3de
|
112 |
tt_tmp = tt; |
7aadf889e
|
113 114 115 |
break; } rcu_read_unlock(); |
c018ad3de
|
116 |
return tt_tmp; |
7aadf889e
|
117 |
} |
c018ad3de
|
118 119 120 121 122 123 124 125 126 |
/** * batadv_tt_local_hash_find - search the local table for a given client * @bat_priv: the bat priv with all the soft interface information * @addr: the mac address of the client to look for * @vid: VLAN identifier * * Returns a pointer to the corresponding tt_local_entry struct if the client is * found, NULL otherwise. */ |
56303d34a
|
127 |
static struct batadv_tt_local_entry * |
c018ad3de
|
128 129 |
batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr, unsigned short vid) |
7aadf889e
|
130 |
{ |
56303d34a
|
131 132 |
struct batadv_tt_common_entry *tt_common_entry; struct batadv_tt_local_entry *tt_local_entry = NULL; |
7aadf889e
|
133 |
|
c018ad3de
|
134 135 |
tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr, vid); |
48100bac8
|
136 137 |
if (tt_common_entry) tt_local_entry = container_of(tt_common_entry, |
56303d34a
|
138 139 |
struct batadv_tt_local_entry, common); |
48100bac8
|
140 141 |
return tt_local_entry; } |
7aadf889e
|
142 |
|
c018ad3de
|
143 144 145 146 147 148 149 150 151 |
/** * batadv_tt_global_hash_find - search the global table for a given client * @bat_priv: the bat priv with all the soft interface information * @addr: the mac address of the client to look for * @vid: VLAN identifier * * Returns a pointer to the corresponding tt_global_entry struct if the client * is found, NULL otherwise. */ |
56303d34a
|
152 |
static struct batadv_tt_global_entry * |
c018ad3de
|
153 154 |
batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr, unsigned short vid) |
48100bac8
|
155 |
{ |
56303d34a
|
156 157 |
struct batadv_tt_common_entry *tt_common_entry; struct batadv_tt_global_entry *tt_global_entry = NULL; |
7683fdc1e
|
158 |
|
c018ad3de
|
159 160 |
tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr, vid); |
48100bac8
|
161 162 |
if (tt_common_entry) tt_global_entry = container_of(tt_common_entry, |
56303d34a
|
163 164 |
struct batadv_tt_global_entry, common); |
48100bac8
|
165 |
return tt_global_entry; |
7aadf889e
|
166 |
} |
a513088d0
|
167 |
static void |
56303d34a
|
168 |
batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry) |
7683fdc1e
|
169 |
{ |
48100bac8
|
170 171 |
if (atomic_dec_and_test(&tt_local_entry->common.refcount)) kfree_rcu(tt_local_entry, common.rcu); |
7683fdc1e
|
172 |
} |
210260594
|
173 174 175 176 177 |
/** * batadv_tt_global_entry_free_ref - decrement the refcounter for a * tt_global_entry and possibly free it * @tt_global_entry: the object to free */ |
a513088d0
|
178 |
static void |
56303d34a
|
179 |
batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry) |
7683fdc1e
|
180 |
{ |
db08e6e55
|
181 |
if (atomic_dec_and_test(&tt_global_entry->common.refcount)) { |
a513088d0
|
182 |
batadv_tt_global_del_orig_list(tt_global_entry); |
210260594
|
183 |
kfree_rcu(tt_global_entry, common.rcu); |
db08e6e55
|
184 185 |
} } |
1d8ab8d3c
|
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
/** * batadv_tt_global_hash_count - count the number of orig entries * @hash: hash table containing the tt entries * @addr: the mac address of the client to count entries for * @vid: VLAN identifier * * Return the number of originators advertising the given address/data * (excluding ourself). */ int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, const uint8_t *addr, unsigned short vid) { struct batadv_tt_global_entry *tt_global_entry; int count; tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); if (!tt_global_entry) return 0; count = atomic_read(&tt_global_entry->orig_list_count); batadv_tt_global_entry_free_ref(tt_global_entry); return count; } |
a513088d0
|
210 |
static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu) |
db08e6e55
|
211 |
{ |
56303d34a
|
212 |
struct batadv_tt_orig_list_entry *orig_entry; |
db08e6e55
|
213 |
|
56303d34a
|
214 |
orig_entry = container_of(rcu, struct batadv_tt_orig_list_entry, rcu); |
72822225b
|
215 216 217 218 219 220 |
/* We are in an rcu callback here, therefore we cannot use * batadv_orig_node_free_ref() and its call_rcu(): * An rcu_barrier() wouldn't wait for that to finish */ batadv_orig_node_free_ref_now(orig_entry->orig_node); |
db08e6e55
|
221 222 |
kfree(orig_entry); } |
7ea7b4a14
|
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
/** * batadv_tt_local_size_mod - change the size by v of the local table identified * by vid * @bat_priv: the bat priv with all the soft interface information * @vid: the VLAN identifier of the sub-table to change * @v: the amount to sum to the local table size */ static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv, unsigned short vid, int v) { struct batadv_softif_vlan *vlan; vlan = batadv_softif_vlan_get(bat_priv, vid); if (!vlan) return; atomic_add(v, &vlan->tt.num_entries); batadv_softif_vlan_free_ref(vlan); } /** * batadv_tt_local_size_inc - increase by one the local table size for the given * vid * @bat_priv: the bat priv with all the soft interface information * @vid: the VLAN identifier */ static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv, unsigned short vid) { batadv_tt_local_size_mod(bat_priv, vid, 1); } /** * batadv_tt_local_size_dec - decrease by one the local table size for the given * vid * @bat_priv: the bat priv with all the soft interface information * @vid: the VLAN identifier */ static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv, unsigned short vid) { batadv_tt_local_size_mod(bat_priv, vid, -1); } /** * batadv_tt_global_size_mod - change the size by v of the local table * identified by vid * @bat_priv: the bat priv with all the soft interface information * @vid: the VLAN identifier * @v: the amount to sum to the global table size */ static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node, unsigned short vid, int v) { struct batadv_orig_node_vlan *vlan; vlan = batadv_orig_node_vlan_new(orig_node, vid); if (!vlan) return; if (atomic_add_return(v, &vlan->tt.num_entries) == 0) { spin_lock_bh(&orig_node->vlan_list_lock); list_del_rcu(&vlan->list); spin_unlock_bh(&orig_node->vlan_list_lock); batadv_orig_node_vlan_free_ref(vlan); } batadv_orig_node_vlan_free_ref(vlan); } /** * batadv_tt_global_size_inc - increase by one the global table size for the * given vid * @orig_node: the originator which global table size has to be decreased * @vid: the vlan identifier */ static void batadv_tt_global_size_inc(struct batadv_orig_node *orig_node, unsigned short vid) { batadv_tt_global_size_mod(orig_node, vid, 1); } /** * batadv_tt_global_size_dec - decrease by one the global table size for the * given vid * @orig_node: the originator which global table size has to be decreased * @vid: the vlan identifier */ static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node, unsigned short vid) { batadv_tt_global_size_mod(orig_node, vid, -1); } |
a513088d0
|
317 |
static void |
56303d34a
|
318 |
batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry) |
db08e6e55
|
319 |
{ |
d657e621a
|
320 321 |
if (!atomic_dec_and_test(&orig_entry->refcount)) return; |
7ea7b4a14
|
322 |
|
a513088d0
|
323 |
call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu); |
7683fdc1e
|
324 |
} |
3abe4adbf
|
325 326 327 328 329 330 |
/** * batadv_tt_local_event - store a local TT event (ADD/DEL) * @bat_priv: the bat priv with all the soft interface information * @tt_local_entry: the TT entry involved in the event * @event_flags: flags to store in the event structure */ |
56303d34a
|
331 |
static void batadv_tt_local_event(struct batadv_priv *bat_priv, |
3abe4adbf
|
332 333 |
struct batadv_tt_local_entry *tt_local_entry, uint8_t event_flags) |
a73105b8d
|
334 |
{ |
56303d34a
|
335 |
struct batadv_tt_change_node *tt_change_node, *entry, *safe; |
3abe4adbf
|
336 337 |
struct batadv_tt_common_entry *common = &tt_local_entry->common; uint8_t flags = common->flags | event_flags; |
3b643de54
|
338 339 |
bool event_removed = false; bool del_op_requested, del_op_entry; |
a73105b8d
|
340 341 |
tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC); |
a73105b8d
|
342 343 |
if (!tt_change_node) return; |
ff66c975d
|
344 |
tt_change_node->change.flags = flags; |
ca6630464
|
345 346 |
memset(tt_change_node->change.reserved, 0, sizeof(tt_change_node->change.reserved)); |
8fdd01530
|
347 |
ether_addr_copy(tt_change_node->change.addr, common->addr); |
c018ad3de
|
348 |
tt_change_node->change.vid = htons(common->vid); |
a73105b8d
|
349 |
|
acd34afa8
|
350 |
del_op_requested = flags & BATADV_TT_CLIENT_DEL; |
3b643de54
|
351 352 |
/* check for ADD+DEL or DEL+ADD events */ |
807736f6e
|
353 354 |
spin_lock_bh(&bat_priv->tt.changes_list_lock); list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, |
3b643de54
|
355 |
list) { |
3abe4adbf
|
356 |
if (!batadv_compare_eth(entry->change.addr, common->addr)) |
3b643de54
|
357 358 359 360 361 362 363 364 365 |
continue; /* DEL+ADD in the same orig interval have no effect and can be * removed to avoid silly behaviour on the receiver side. The * other way around (ADD+DEL) can happen in case of roaming of * a client still in the NEW state. Roaming of NEW clients is * now possible due to automatically recognition of "temporary" * clients */ |
acd34afa8
|
366 |
del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL; |
3b643de54
|
367 368 369 370 |
if (!del_op_requested && del_op_entry) goto del; if (del_op_requested && !del_op_entry) goto del; |
3c4f7ab60
|
371 372 373 374 375 376 |
/* this is a second add in the same originator interval. It * means that flags have been changed: update them! */ if (!del_op_requested && !del_op_entry) entry->change.flags = flags; |
3b643de54
|
377 378 379 380 |
continue; del: list_del(&entry->list); kfree(entry); |
155e4e12b
|
381 |
kfree(tt_change_node); |
3b643de54
|
382 383 384 |
event_removed = true; goto unlock; } |
a73105b8d
|
385 |
/* track the change in the OGMinterval list */ |
807736f6e
|
386 |
list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list); |
3b643de54
|
387 388 |
unlock: |
807736f6e
|
389 |
spin_unlock_bh(&bat_priv->tt.changes_list_lock); |
a73105b8d
|
390 |
|
3b643de54
|
391 |
if (event_removed) |
807736f6e
|
392 |
atomic_dec(&bat_priv->tt.local_changes); |
3b643de54
|
393 |
else |
807736f6e
|
394 |
atomic_inc(&bat_priv->tt.local_changes); |
a73105b8d
|
395 |
} |
335fbe0f5
|
396 397 398 399 400 401 402 |
/** * batadv_tt_len - compute length in bytes of given number of tt changes * @changes_num: number of tt changes * * Returns computed length in bytes. */ static int batadv_tt_len(int changes_num) |
a73105b8d
|
403 |
{ |
335fbe0f5
|
404 |
return changes_num * sizeof(struct batadv_tvlv_tt_change); |
a73105b8d
|
405 |
} |
298e6e685
|
406 407 408 409 410 411 412 413 414 415 |
/** * batadv_tt_entries - compute the number of entries fitting in tt_len bytes * @tt_len: available space * * Returns the number of entries. */ static uint16_t batadv_tt_entries(uint16_t tt_len) { return tt_len / batadv_tt_len(1); } |
a19d3d85e
|
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 |
/** * batadv_tt_local_table_transmit_size - calculates the local translation table * size when transmitted over the air * @bat_priv: the bat priv with all the soft interface information * * Returns local translation table size in bytes. */ static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv) { uint16_t num_vlan = 0, tt_local_entries = 0; struct batadv_softif_vlan *vlan; int hdr_size; rcu_read_lock(); hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { num_vlan++; tt_local_entries += atomic_read(&vlan->tt.num_entries); } rcu_read_unlock(); /* header size of tvlv encapsulated tt response payload */ hdr_size = sizeof(struct batadv_unicast_tvlv_packet); hdr_size += sizeof(struct batadv_tvlv_hdr); hdr_size += sizeof(struct batadv_tvlv_tt_data); hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data); return hdr_size + batadv_tt_len(tt_local_entries); } |
56303d34a
|
444 |
static int batadv_tt_local_init(struct batadv_priv *bat_priv) |
c6c8fea29
|
445 |
{ |
807736f6e
|
446 |
if (bat_priv->tt.local_hash) |
5346c35eb
|
447 |
return 0; |
c6c8fea29
|
448 |
|
807736f6e
|
449 |
bat_priv->tt.local_hash = batadv_hash_new(1024); |
c6c8fea29
|
450 |
|
807736f6e
|
451 |
if (!bat_priv->tt.local_hash) |
5346c35eb
|
452 |
return -ENOMEM; |
c6c8fea29
|
453 |
|
dec05074b
|
454 455 |
batadv_hash_set_lock_class(bat_priv->tt.local_hash, &batadv_tt_local_hash_lock_class_key); |
5346c35eb
|
456 |
return 0; |
c6c8fea29
|
457 |
} |
068ee6e20
|
458 459 460 461 462 |
static void batadv_tt_global_free(struct batadv_priv *bat_priv, struct batadv_tt_global_entry *tt_global, const char *message) { batadv_dbg(BATADV_DBG_TT, bat_priv, |
160527890
|
463 464 465 466 |
"Deleting global tt entry %pM (vid: %d): %s ", tt_global->common.addr, BATADV_PRINT_VID(tt_global->common.vid), message); |
068ee6e20
|
467 468 |
batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, |
c018ad3de
|
469 |
batadv_choose_tt, &tt_global->common); |
068ee6e20
|
470 |
batadv_tt_global_entry_free_ref(tt_global); |
068ee6e20
|
471 |
} |
c018ad3de
|
472 473 474 475 476 477 478 479 |
/** * batadv_tt_local_add - add a new client to the local table or update an * existing client * @soft_iface: netdev struct of the mesh interface * @addr: the mac address of the client to add * @vid: VLAN identifier * @ifindex: index of the interface where the client is connected to (useful to * identify wireless clients) |
9464d0718
|
480 481 |
* @mark: the value contained in the skb->mark field of the received packet (if * any) |
a19d3d85e
|
482 483 |
* * Returns true if the client was successfully added, false otherwise. |
c018ad3de
|
484 |
*/ |
a19d3d85e
|
485 |
bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, |
9464d0718
|
486 |
unsigned short vid, int ifindex, uint32_t mark) |
c6c8fea29
|
487 |
{ |
56303d34a
|
488 |
struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
170173bf3
|
489 |
struct batadv_tt_local_entry *tt_local; |
c5caf4ef3
|
490 |
struct batadv_tt_global_entry *tt_global = NULL; |
0c69aecc5
|
491 |
struct net_device *in_dev = NULL; |
db08e6e55
|
492 |
struct hlist_head *head; |
56303d34a
|
493 |
struct batadv_tt_orig_list_entry *orig_entry; |
a19d3d85e
|
494 495 |
int hash_added, table_size, packet_size_max; bool ret = false, roamed_back = false; |
3c4f7ab60
|
496 |
uint8_t remote_flags; |
9464d0718
|
497 |
uint32_t match_mark; |
c6c8fea29
|
498 |
|
0c69aecc5
|
499 500 |
if (ifindex != BATADV_NULL_IFINDEX) in_dev = dev_get_by_index(&init_net, ifindex); |
c018ad3de
|
501 |
tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); |
c5caf4ef3
|
502 503 504 |
if (!is_multicast_ether_addr(addr)) tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); |
c6c8fea29
|
505 |
|
47c94655c
|
506 507 |
if (tt_local) { tt_local->last_seen = jiffies; |
068ee6e20
|
508 509 |
if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { batadv_dbg(BATADV_DBG_TT, bat_priv, |
160527890
|
510 511 512 |
"Re-adding pending client %pM (vid: %d) ", addr, BATADV_PRINT_VID(vid)); |
068ee6e20
|
513 514 515 516 517 518 519 520 521 522 523 |
/* whatever the reason why the PENDING flag was set, * this is a client which was enqueued to be removed in * this orig_interval. Since it popped up again, the * flag can be reset like it was never enqueued */ tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING; goto add_event; } if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { batadv_dbg(BATADV_DBG_TT, bat_priv, |
160527890
|
524 525 526 |
"Roaming client %pM (vid: %d) came back to its original location ", addr, BATADV_PRINT_VID(vid)); |
068ee6e20
|
527 528 529 530 531 532 533 534 535 |
/* the ROAM flag is set because this client roamed away * and the node got a roaming_advertisement message. Now * that the client popped up again at its original * location such flag can be unset */ tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM; roamed_back = true; } goto check_roaming; |
c6c8fea29
|
536 |
} |
a19d3d85e
|
537 538 539 540 541 542 543 544 545 546 547 |
/* Ignore the client if we cannot send it in a full table response. */ table_size = batadv_tt_local_table_transmit_size(bat_priv); table_size += batadv_tt_len(1); packet_size_max = atomic_read(&bat_priv->packet_size_max); if (table_size > packet_size_max) { net_ratelimited_function(batadv_info, soft_iface, "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM ", table_size, packet_size_max, addr); goto out; } |
47c94655c
|
548 549 |
tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC); if (!tt_local) |
7683fdc1e
|
550 |
goto out; |
a73105b8d
|
551 |
|
39c75a51e
|
552 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
160527890
|
553 554 555 |
"Creating new local tt entry: %pM (vid: %d, ttvn: %d) ", addr, BATADV_PRINT_VID(vid), |
807736f6e
|
556 |
(uint8_t)atomic_read(&bat_priv->tt.vn)); |
c6c8fea29
|
557 |
|
8fdd01530
|
558 |
ether_addr_copy(tt_local->common.addr, addr); |
8425ec6ae
|
559 560 561 562 563 |
/* The local entry has to be marked as NEW to avoid to send it in * a full table response going out before the next ttvn increment * (consistency check) */ tt_local->common.flags = BATADV_TT_CLIENT_NEW; |
c018ad3de
|
564 |
tt_local->common.vid = vid; |
0c69aecc5
|
565 |
if (batadv_is_wifi_netdev(in_dev)) |
47c94655c
|
566 567 568 569 |
tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; atomic_set(&tt_local->common.refcount, 2); tt_local->last_seen = jiffies; tt_local->common.added_at = tt_local->last_seen; |
c6c8fea29
|
570 |
|
c5caf4ef3
|
571 572 573 574 575 |
/* the batman interface mac and multicast addresses should never be * purged */ if (batadv_compare_eth(addr, soft_iface->dev_addr) || is_multicast_ether_addr(addr)) |
47c94655c
|
576 |
tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE; |
c6c8fea29
|
577 |
|
807736f6e
|
578 |
hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, |
c018ad3de
|
579 |
batadv_choose_tt, &tt_local->common, |
47c94655c
|
580 |
&tt_local->common.hash_entry); |
80b3f58cf
|
581 582 583 |
if (unlikely(hash_added != 0)) { /* remove the reference for the hash */ |
47c94655c
|
584 |
batadv_tt_local_entry_free_ref(tt_local); |
80b3f58cf
|
585 586 |
goto out; } |
068ee6e20
|
587 |
add_event: |
3abe4adbf
|
588 |
batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); |
ff66c975d
|
589 |
|
068ee6e20
|
590 591 592 593 594 |
check_roaming: /* Check whether it is a roaming, but don't do anything if the roaming * process has already been handled */ if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) { |
db08e6e55
|
595 |
/* These node are probably going to update their tt table */ |
47c94655c
|
596 |
head = &tt_global->orig_list; |
db08e6e55
|
597 |
rcu_read_lock(); |
b67bfe0d4
|
598 |
hlist_for_each_entry_rcu(orig_entry, head, list) { |
47c94655c
|
599 |
batadv_send_roam_adv(bat_priv, tt_global->common.addr, |
c018ad3de
|
600 |
tt_global->common.vid, |
a513088d0
|
601 |
orig_entry->orig_node); |
db08e6e55
|
602 603 |
} rcu_read_unlock(); |
068ee6e20
|
604 605 606 607 608 609 610 611 612 613 614 |
if (roamed_back) { batadv_tt_global_free(bat_priv, tt_global, "Roaming canceled"); tt_global = NULL; } else { /* The global entry has to be marked as ROAMING and * has to be kept for consistency purpose */ tt_global->common.flags |= BATADV_TT_CLIENT_ROAM; tt_global->roam_at = jiffies; } |
7683fdc1e
|
615 |
} |
068ee6e20
|
616 |
|
3c4f7ab60
|
617 618 619 620 621 622 623 624 625 |
/* store the current remote flags before altering them. This helps * understanding is flags are changing or not */ remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK; if (batadv_is_wifi_netdev(in_dev)) tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; else tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI; |
a19d3d85e
|
626 |
|
9464d0718
|
627 628 629 630 631 632 633 634 635 636 |
/* check the mark in the skb: if it's equal to the configured * isolation_mark, it means the packet is coming from an isolated * non-mesh client */ match_mark = (mark & bat_priv->isolation_mark_mask); if (bat_priv->isolation_mark_mask && match_mark == bat_priv->isolation_mark) tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA; else tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA; |
3c4f7ab60
|
637 638 639 640 641 642 643 |
/* if any "dynamic" flag has been modified, resend an ADD event for this * entry so that all the nodes can get the new flags */ if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK)) batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS); ret = true; |
7683fdc1e
|
644 |
out: |
0c69aecc5
|
645 646 |
if (in_dev) dev_put(in_dev); |
47c94655c
|
647 648 649 650 |
if (tt_local) batadv_tt_local_entry_free_ref(tt_local); if (tt_global) batadv_tt_global_entry_free_ref(tt_global); |
a19d3d85e
|
651 |
return ret; |
c6c8fea29
|
652 |
} |
e1bf0c140
|
653 |
/** |
7ea7b4a14
|
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 |
* batadv_tt_prepare_tvlv_global_data - prepare the TVLV TT header to send * within a TT Response directed to another node * @orig_node: originator for which the TT data has to be prepared * @tt_data: uninitialised pointer to the address of the TVLV buffer * @tt_change: uninitialised pointer to the address of the area where the TT * changed can be stored * @tt_len: pointer to the length to reserve to the tt_change. if -1 this * function reserves the amount of space needed to send the entire global TT * table. In case of success the value is updated with the real amount of * reserved bytes * Allocate the needed amount of memory for the entire TT TVLV and write its * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data * objects, one per active VLAN served by the originator node. * * Return the size of the allocated buffer or 0 in case of failure. */ static uint16_t batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, struct batadv_tvlv_tt_data **tt_data, struct batadv_tvlv_tt_change **tt_change, int32_t *tt_len) { uint16_t num_vlan = 0, num_entries = 0, change_offset, tvlv_len; struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_orig_node_vlan *vlan; uint8_t *tt_change_ptr; rcu_read_lock(); list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { num_vlan++; num_entries += atomic_read(&vlan->tt.num_entries); } change_offset = sizeof(**tt_data); change_offset += num_vlan * sizeof(*tt_vlan); /* if tt_len is negative, allocate the space needed by the full table */ if (*tt_len < 0) *tt_len = batadv_tt_len(num_entries); tvlv_len = *tt_len; tvlv_len += change_offset; *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); if (!*tt_data) { *tt_len = 0; goto out; } (*tt_data)->flags = BATADV_NO_FLAGS; (*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn); (*tt_data)->num_vlan = htons(num_vlan); tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { tt_vlan->vid = htons(vlan->vid); tt_vlan->crc = htonl(vlan->tt.crc); tt_vlan++; } tt_change_ptr = (uint8_t *)*tt_data + change_offset; *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; out: rcu_read_unlock(); return tvlv_len; } /** * batadv_tt_prepare_tvlv_local_data - allocate and prepare the TT TVLV for this * node * @bat_priv: the bat priv with all the soft interface information * @tt_data: uninitialised pointer to the address of the TVLV buffer * @tt_change: uninitialised pointer to the address of the area where the TT * changes can be stored * @tt_len: pointer to the length to reserve to the tt_change. if -1 this * function reserves the amount of space needed to send the entire local TT * table. In case of success the value is updated with the real amount of * reserved bytes * * Allocate the needed amount of memory for the entire TT TVLV and write its * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data * objects, one per active VLAN. * * Return the size of the allocated buffer or 0 in case of failure. */ static uint16_t batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data **tt_data, struct batadv_tvlv_tt_change **tt_change, int32_t *tt_len) { struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_softif_vlan *vlan; uint16_t num_vlan = 0, num_entries = 0, tvlv_len; uint8_t *tt_change_ptr; int change_offset; rcu_read_lock(); hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { num_vlan++; num_entries += atomic_read(&vlan->tt.num_entries); } change_offset = sizeof(**tt_data); change_offset += num_vlan * sizeof(*tt_vlan); /* if tt_len is negative, allocate the space needed by the full table */ if (*tt_len < 0) *tt_len = batadv_tt_len(num_entries); tvlv_len = *tt_len; tvlv_len += change_offset; *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); if (!*tt_data) { tvlv_len = 0; goto out; } (*tt_data)->flags = BATADV_NO_FLAGS; (*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn); (*tt_data)->num_vlan = htons(num_vlan); tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { tt_vlan->vid = htons(vlan->vid); tt_vlan->crc = htonl(vlan->tt.crc); tt_vlan++; } tt_change_ptr = (uint8_t *)*tt_data + change_offset; *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; out: rcu_read_unlock(); return tvlv_len; } /** |
e1bf0c140
|
797 798 799 800 801 |
* batadv_tt_tvlv_container_update - update the translation table tvlv container * after local tt changes have been committed * @bat_priv: the bat priv with all the soft interface information */ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) |
be9aa4c1e
|
802 |
{ |
e1bf0c140
|
803 804 805 |
struct batadv_tt_change_node *entry, *safe; struct batadv_tvlv_tt_data *tt_data; struct batadv_tvlv_tt_change *tt_change; |
7ea7b4a14
|
806 |
int tt_diff_len, tt_change_len = 0; |
e1bf0c140
|
807 |
int tt_diff_entries_num = 0, tt_diff_entries_count = 0; |
7ea7b4a14
|
808 |
uint16_t tvlv_len; |
be9aa4c1e
|
809 |
|
7ea7b4a14
|
810 811 |
tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes); tt_diff_len = batadv_tt_len(tt_diff_entries_num); |
be9aa4c1e
|
812 813 814 815 |
/* if we have too many changes for one packet don't send any * and wait for the tt table request which will be fragmented */ |
e1bf0c140
|
816 817 |
if (tt_diff_len > bat_priv->soft_iface->mtu) tt_diff_len = 0; |
be9aa4c1e
|
818 |
|
7ea7b4a14
|
819 820 821 |
tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data, &tt_change, &tt_diff_len); if (!tvlv_len) |
e1bf0c140
|
822 |
return; |
be9aa4c1e
|
823 |
|
e1bf0c140
|
824 |
tt_data->flags = BATADV_TT_OGM_DIFF; |
c6c8fea29
|
825 |
|
e1bf0c140
|
826 827 |
if (tt_diff_len == 0) goto container_register; |
be9aa4c1e
|
828 |
|
807736f6e
|
829 830 |
spin_lock_bh(&bat_priv->tt.changes_list_lock); atomic_set(&bat_priv->tt.local_changes, 0); |
c6c8fea29
|
831 |
|
807736f6e
|
832 |
list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, |
7c64fd98c
|
833 |
list) { |
e1bf0c140
|
834 835 836 837 838 |
if (tt_diff_entries_count < tt_diff_entries_num) { memcpy(tt_change + tt_diff_entries_count, &entry->change, sizeof(struct batadv_tvlv_tt_change)); tt_diff_entries_count++; |
c6c8fea29
|
839 |
} |
a73105b8d
|
840 841 |
list_del(&entry->list); kfree(entry); |
c6c8fea29
|
842 |
} |
807736f6e
|
843 |
spin_unlock_bh(&bat_priv->tt.changes_list_lock); |
a73105b8d
|
844 845 |
/* Keep the buffer for possible tt_request */ |
807736f6e
|
846 847 848 849 |
spin_lock_bh(&bat_priv->tt.last_changeset_lock); kfree(bat_priv->tt.last_changeset); bat_priv->tt.last_changeset_len = 0; bat_priv->tt.last_changeset = NULL; |
e1bf0c140
|
850 |
tt_change_len = batadv_tt_len(tt_diff_entries_count); |
be9aa4c1e
|
851 |
/* check whether this new OGM has no changes due to size problems */ |
e1bf0c140
|
852 |
if (tt_diff_entries_count > 0) { |
be9aa4c1e
|
853 |
/* if kmalloc() fails we will reply with the full table |
a73105b8d
|
854 855 |
* instead of providing the diff */ |
e1bf0c140
|
856 |
bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC); |
807736f6e
|
857 |
if (bat_priv->tt.last_changeset) { |
e1bf0c140
|
858 859 860 |
memcpy(bat_priv->tt.last_changeset, tt_change, tt_change_len); bat_priv->tt.last_changeset_len = tt_diff_len; |
a73105b8d
|
861 862 |
} } |
807736f6e
|
863 |
spin_unlock_bh(&bat_priv->tt.last_changeset_lock); |
c6c8fea29
|
864 |
|
e1bf0c140
|
865 866 |
container_register: batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data, |
7ea7b4a14
|
867 |
tvlv_len); |
e1bf0c140
|
868 |
kfree(tt_data); |
c6c8fea29
|
869 |
} |
08c36d3e8
|
870 |
int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) |
c6c8fea29
|
871 872 |
{ struct net_device *net_dev = (struct net_device *)seq->private; |
56303d34a
|
873 |
struct batadv_priv *bat_priv = netdev_priv(net_dev); |
807736f6e
|
874 |
struct batadv_hashtable *hash = bat_priv->tt.local_hash; |
56303d34a
|
875 |
struct batadv_tt_common_entry *tt_common_entry; |
85766a820
|
876 |
struct batadv_tt_local_entry *tt_local; |
56303d34a
|
877 |
struct batadv_hard_iface *primary_if; |
7ea7b4a14
|
878 |
struct batadv_softif_vlan *vlan; |
c6c8fea29
|
879 |
struct hlist_head *head; |
7ea7b4a14
|
880 |
unsigned short vid; |
c90681b85
|
881 |
uint32_t i; |
85766a820
|
882 883 884 885 886 |
int last_seen_secs; int last_seen_msecs; unsigned long last_seen_jiffies; bool no_purge; uint16_t np_flag = BATADV_TT_CLIENT_NOPURGE; |
c6c8fea29
|
887 |
|
30da63a6a
|
888 889 |
primary_if = batadv_seq_print_text_primary_if_get(seq); if (!primary_if) |
32ae9b221
|
890 |
goto out; |
c6c8fea29
|
891 |
|
86ceb3605
|
892 |
seq_printf(seq, |
7ea7b4a14
|
893 894 895 |
"Locally retrieved addresses (from %s) announced via TT (TTVN: %u): ", net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn)); |
dd24ddb26
|
896 897 |
seq_printf(seq, " %-13s %s %-8s %-9s (%-10s) ", "Client", "VID", |
7ea7b4a14
|
898 |
"Flags", "Last seen", "CRC"); |
c6c8fea29
|
899 |
|
c6c8fea29
|
900 901 |
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; |
7aadf889e
|
902 |
rcu_read_lock(); |
b67bfe0d4
|
903 |
hlist_for_each_entry_rcu(tt_common_entry, |
7aadf889e
|
904 |
head, hash_entry) { |
85766a820
|
905 906 907 |
tt_local = container_of(tt_common_entry, struct batadv_tt_local_entry, common); |
7ea7b4a14
|
908 |
vid = tt_common_entry->vid; |
85766a820
|
909 910 911 912 913 914 |
last_seen_jiffies = jiffies - tt_local->last_seen; last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); last_seen_secs = last_seen_msecs / 1000; last_seen_msecs = last_seen_msecs % 1000; no_purge = tt_common_entry->flags & np_flag; |
7ea7b4a14
|
915 916 917 918 919 920 921 922 923 |
vlan = batadv_softif_vlan_get(bat_priv, vid); if (!vlan) { seq_printf(seq, "Cannot retrieve VLAN %d ", BATADV_PRINT_VID(vid)); continue; } seq_printf(seq, |
dd24ddb26
|
924 925 |
" * %pM %4i [%c%c%c%c%c%c] %3u.%03u (%#.8x) ", |
7c64fd98c
|
926 |
tt_common_entry->addr, |
160527890
|
927 |
BATADV_PRINT_VID(tt_common_entry->vid), |
7c64fd98c
|
928 |
(tt_common_entry->flags & |
acd34afa8
|
929 |
BATADV_TT_CLIENT_ROAM ? 'R' : '.'), |
85766a820
|
930 |
no_purge ? 'P' : '.', |
7c64fd98c
|
931 |
(tt_common_entry->flags & |
acd34afa8
|
932 |
BATADV_TT_CLIENT_NEW ? 'N' : '.'), |
7c64fd98c
|
933 |
(tt_common_entry->flags & |
acd34afa8
|
934 |
BATADV_TT_CLIENT_PENDING ? 'X' : '.'), |
7c64fd98c
|
935 |
(tt_common_entry->flags & |
85766a820
|
936 |
BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
dd24ddb26
|
937 938 |
(tt_common_entry->flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'), |
a7966d908
|
939 |
no_purge ? 0 : last_seen_secs, |
7ea7b4a14
|
940 941 942 943 |
no_purge ? 0 : last_seen_msecs, vlan->tt.crc); batadv_softif_vlan_free_ref(vlan); |
c6c8fea29
|
944 |
} |
7aadf889e
|
945 |
rcu_read_unlock(); |
c6c8fea29
|
946 |
} |
32ae9b221
|
947 948 |
out: if (primary_if) |
e5d89254b
|
949 |
batadv_hardif_free_ref(primary_if); |
30da63a6a
|
950 |
return 0; |
c6c8fea29
|
951 |
} |
56303d34a
|
952 953 954 955 |
static void batadv_tt_local_set_pending(struct batadv_priv *bat_priv, struct batadv_tt_local_entry *tt_local_entry, uint16_t flags, const char *message) |
c6c8fea29
|
956 |
{ |
3abe4adbf
|
957 |
batadv_tt_local_event(bat_priv, tt_local_entry, flags); |
a73105b8d
|
958 |
|
015758d00
|
959 960 |
/* The local client has to be marked as "pending to be removed" but has * to be kept in the table in order to send it in a full table |
9cfc7bd60
|
961 962 |
* response issued before the net ttvn increment (consistency check) */ |
acd34afa8
|
963 |
tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING; |
c566dbbef
|
964 |
|
39c75a51e
|
965 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
160527890
|
966 967 968 969 |
"Local tt entry (%pM, vid: %d) pending to be removed: %s ", tt_local_entry->common.addr, BATADV_PRINT_VID(tt_local_entry->common.vid), message); |
c6c8fea29
|
970 |
} |
7f91d06c9
|
971 972 973 974 |
/** * batadv_tt_local_remove - logically remove an entry from the local table * @bat_priv: the bat priv with all the soft interface information * @addr: the MAC address of the client to remove |
c018ad3de
|
975 |
* @vid: VLAN identifier |
7f91d06c9
|
976 977 978 979 980 981 |
* @message: message to append to the log on deletion * @roaming: true if the deletion is due to a roaming event * * Returns the flags assigned to the local entry before being deleted */ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, |
c018ad3de
|
982 983 |
const uint8_t *addr, unsigned short vid, const char *message, bool roaming) |
c6c8fea29
|
984 |
{ |
170173bf3
|
985 |
struct batadv_tt_local_entry *tt_local_entry; |
7f91d06c9
|
986 |
uint16_t flags, curr_flags = BATADV_NO_FLAGS; |
c6c8fea29
|
987 |
|
c018ad3de
|
988 |
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); |
7683fdc1e
|
989 990 |
if (!tt_local_entry) goto out; |
7f91d06c9
|
991 |
curr_flags = tt_local_entry->common.flags; |
acd34afa8
|
992 |
flags = BATADV_TT_CLIENT_DEL; |
068ee6e20
|
993 994 995 996 |
/* if this global entry addition is due to a roaming, the node has to * mark the local entry as "roamed" in order to correctly reroute * packets later */ |
7c1fd91da
|
997 |
if (roaming) { |
acd34afa8
|
998 |
flags |= BATADV_TT_CLIENT_ROAM; |
7c1fd91da
|
999 1000 1001 |
/* mark the local client as ROAMed */ tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM; } |
42d0b044b
|
1002 |
|
068ee6e20
|
1003 1004 1005 1006 1007 1008 1009 1010 |
if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) { batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags, message); goto out; } /* if this client has been added right now, it is possible to * immediately purge it */ |
3abe4adbf
|
1011 |
batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); |
068ee6e20
|
1012 1013 |
hlist_del_rcu(&tt_local_entry->common.hash_entry); batadv_tt_local_entry_free_ref(tt_local_entry); |
7f91d06c9
|
1014 |
|
7683fdc1e
|
1015 1016 |
out: if (tt_local_entry) |
a513088d0
|
1017 |
batadv_tt_local_entry_free_ref(tt_local_entry); |
7f91d06c9
|
1018 1019 |
return curr_flags; |
c6c8fea29
|
1020 |
} |
a19d3d85e
|
1021 1022 1023 1024 1025 1026 1027 |
/** * batadv_tt_local_purge_list - purge inactive tt local entries * @bat_priv: the bat priv with all the soft interface information * @head: pointer to the list containing the local tt entries * @timeout: parameter deciding whether a given tt local entry is considered * inactive or not */ |
56303d34a
|
1028 |
static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv, |
a19d3d85e
|
1029 1030 |
struct hlist_head *head, int timeout) |
c6c8fea29
|
1031 |
{ |
56303d34a
|
1032 1033 |
struct batadv_tt_local_entry *tt_local_entry; struct batadv_tt_common_entry *tt_common_entry; |
b67bfe0d4
|
1034 |
struct hlist_node *node_tmp; |
acd34afa8
|
1035 |
|
b67bfe0d4
|
1036 |
hlist_for_each_entry_safe(tt_common_entry, node_tmp, head, |
acd34afa8
|
1037 1038 |
hash_entry) { tt_local_entry = container_of(tt_common_entry, |
56303d34a
|
1039 1040 |
struct batadv_tt_local_entry, common); |
acd34afa8
|
1041 1042 1043 1044 1045 1046 |
if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE) continue; /* entry already marked for deletion */ if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) continue; |
a19d3d85e
|
1047 |
if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout)) |
acd34afa8
|
1048 1049 1050 1051 1052 1053 |
continue; batadv_tt_local_set_pending(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL, "timed out"); } } |
a19d3d85e
|
1054 1055 1056 1057 1058 1059 1060 1061 |
/** * batadv_tt_local_purge - purge inactive tt local entries * @bat_priv: the bat priv with all the soft interface information * @timeout: parameter deciding whether a given tt local entry is considered * inactive or not */ static void batadv_tt_local_purge(struct batadv_priv *bat_priv, int timeout) |
acd34afa8
|
1062 |
{ |
807736f6e
|
1063 |
struct batadv_hashtable *hash = bat_priv->tt.local_hash; |
c6c8fea29
|
1064 |
struct hlist_head *head; |
7683fdc1e
|
1065 |
spinlock_t *list_lock; /* protects write access to the hash lists */ |
c90681b85
|
1066 |
uint32_t i; |
c6c8fea29
|
1067 |
|
c6c8fea29
|
1068 1069 |
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; |
7683fdc1e
|
1070 |
list_lock = &hash->list_locks[i]; |
c6c8fea29
|
1071 |
|
7683fdc1e
|
1072 |
spin_lock_bh(list_lock); |
a19d3d85e
|
1073 |
batadv_tt_local_purge_list(bat_priv, head, timeout); |
7683fdc1e
|
1074 |
spin_unlock_bh(list_lock); |
c6c8fea29
|
1075 |
} |
c6c8fea29
|
1076 |
} |
56303d34a
|
1077 |
static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) |
c6c8fea29
|
1078 |
{ |
5bf74e9ca
|
1079 |
struct batadv_hashtable *hash; |
a73105b8d
|
1080 |
spinlock_t *list_lock; /* protects write access to the hash lists */ |
56303d34a
|
1081 1082 |
struct batadv_tt_common_entry *tt_common_entry; struct batadv_tt_local_entry *tt_local; |
b67bfe0d4
|
1083 |
struct hlist_node *node_tmp; |
7683fdc1e
|
1084 |
struct hlist_head *head; |
c90681b85
|
1085 |
uint32_t i; |
a73105b8d
|
1086 |
|
807736f6e
|
1087 |
if (!bat_priv->tt.local_hash) |
c6c8fea29
|
1088 |
return; |
807736f6e
|
1089 |
hash = bat_priv->tt.local_hash; |
a73105b8d
|
1090 1091 1092 1093 1094 1095 |
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; list_lock = &hash->list_locks[i]; spin_lock_bh(list_lock); |
b67bfe0d4
|
1096 |
hlist_for_each_entry_safe(tt_common_entry, node_tmp, |
a73105b8d
|
1097 |
head, hash_entry) { |
b67bfe0d4
|
1098 |
hlist_del_rcu(&tt_common_entry->hash_entry); |
56303d34a
|
1099 1100 1101 1102 |
tt_local = container_of(tt_common_entry, struct batadv_tt_local_entry, common); batadv_tt_local_entry_free_ref(tt_local); |
a73105b8d
|
1103 1104 1105 |
} spin_unlock_bh(list_lock); } |
1a8eaf073
|
1106 |
batadv_hash_destroy(hash); |
a73105b8d
|
1107 |
|
807736f6e
|
1108 |
bat_priv->tt.local_hash = NULL; |
c6c8fea29
|
1109 |
} |
56303d34a
|
1110 |
static int batadv_tt_global_init(struct batadv_priv *bat_priv) |
c6c8fea29
|
1111 |
{ |
807736f6e
|
1112 |
if (bat_priv->tt.global_hash) |
5346c35eb
|
1113 |
return 0; |
c6c8fea29
|
1114 |
|
807736f6e
|
1115 |
bat_priv->tt.global_hash = batadv_hash_new(1024); |
c6c8fea29
|
1116 |
|
807736f6e
|
1117 |
if (!bat_priv->tt.global_hash) |
5346c35eb
|
1118 |
return -ENOMEM; |
c6c8fea29
|
1119 |
|
dec05074b
|
1120 1121 |
batadv_hash_set_lock_class(bat_priv->tt.global_hash, &batadv_tt_global_hash_lock_class_key); |
5346c35eb
|
1122 |
return 0; |
c6c8fea29
|
1123 |
} |
56303d34a
|
1124 |
static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv) |
c6c8fea29
|
1125 |
{ |
56303d34a
|
1126 |
struct batadv_tt_change_node *entry, *safe; |
c6c8fea29
|
1127 |
|
807736f6e
|
1128 |
spin_lock_bh(&bat_priv->tt.changes_list_lock); |
c6c8fea29
|
1129 |
|
807736f6e
|
1130 |
list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, |
a73105b8d
|
1131 1132 1133 1134 |
list) { list_del(&entry->list); kfree(entry); } |
c6c8fea29
|
1135 |
|
807736f6e
|
1136 1137 |
atomic_set(&bat_priv->tt.local_changes, 0); spin_unlock_bh(&bat_priv->tt.changes_list_lock); |
a73105b8d
|
1138 |
} |
c6c8fea29
|
1139 |
|
d657e621a
|
1140 1141 1142 1143 |
/* retrieves the orig_tt_list_entry belonging to orig_node from the * batadv_tt_global_entry list * * returns it with an increased refcounter, NULL if not found |
db08e6e55
|
1144 |
*/ |
d657e621a
|
1145 1146 1147 |
static struct batadv_tt_orig_list_entry * batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, const struct batadv_orig_node *orig_node) |
db08e6e55
|
1148 |
{ |
d657e621a
|
1149 |
struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL; |
db08e6e55
|
1150 |
const struct hlist_head *head; |
db08e6e55
|
1151 1152 1153 |
rcu_read_lock(); head = &entry->orig_list; |
b67bfe0d4
|
1154 |
hlist_for_each_entry_rcu(tmp_orig_entry, head, list) { |
d657e621a
|
1155 1156 1157 1158 1159 1160 1161 |
if (tmp_orig_entry->orig_node != orig_node) continue; if (!atomic_inc_not_zero(&tmp_orig_entry->refcount)) continue; orig_entry = tmp_orig_entry; break; |
db08e6e55
|
1162 1163 |
} rcu_read_unlock(); |
d657e621a
|
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 |
return orig_entry; } /* find out if an orig_node is already in the list of a tt_global_entry. * returns true if found, false otherwise */ static bool batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, const struct batadv_orig_node *orig_node) { struct batadv_tt_orig_list_entry *orig_entry; bool found = false; orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node); if (orig_entry) { found = true; batadv_tt_orig_list_entry_free_ref(orig_entry); } |
db08e6e55
|
1183 1184 |
return found; } |
a513088d0
|
1185 |
static void |
d657e621a
|
1186 |
batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global, |
56303d34a
|
1187 |
struct batadv_orig_node *orig_node, int ttvn) |
db08e6e55
|
1188 |
{ |
56303d34a
|
1189 |
struct batadv_tt_orig_list_entry *orig_entry; |
db08e6e55
|
1190 |
|
d657e621a
|
1191 |
orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node); |
30cfd02b6
|
1192 1193 1194 1195 1196 |
if (orig_entry) { /* refresh the ttvn: the current value could be a bogus one that * was added during a "temporary client detection" */ orig_entry->ttvn = ttvn; |
d657e621a
|
1197 |
goto out; |
30cfd02b6
|
1198 |
} |
d657e621a
|
1199 |
|
db08e6e55
|
1200 1201 |
orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC); if (!orig_entry) |
d657e621a
|
1202 |
goto out; |
db08e6e55
|
1203 1204 1205 |
INIT_HLIST_NODE(&orig_entry->list); atomic_inc(&orig_node->refcount); |
7ea7b4a14
|
1206 |
batadv_tt_global_size_inc(orig_node, tt_global->common.vid); |
db08e6e55
|
1207 1208 |
orig_entry->orig_node = orig_node; orig_entry->ttvn = ttvn; |
d657e621a
|
1209 |
atomic_set(&orig_entry->refcount, 2); |
db08e6e55
|
1210 |
|
d657e621a
|
1211 |
spin_lock_bh(&tt_global->list_lock); |
db08e6e55
|
1212 |
hlist_add_head_rcu(&orig_entry->list, |
d657e621a
|
1213 1214 |
&tt_global->orig_list); spin_unlock_bh(&tt_global->list_lock); |
1d8ab8d3c
|
1215 |
atomic_inc(&tt_global->orig_list_count); |
d657e621a
|
1216 1217 1218 |
out: if (orig_entry) batadv_tt_orig_list_entry_free_ref(orig_entry); |
db08e6e55
|
1219 |
} |
d4ff40f68
|
1220 1221 1222 1223 1224 |
/** * batadv_tt_global_add - add a new TT global entry or update an existing one * @bat_priv: the bat priv with all the soft interface information * @orig_node: the originator announcing the client * @tt_addr: the mac address of the non-mesh client |
c018ad3de
|
1225 |
* @vid: VLAN identifier |
d4ff40f68
|
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 |
* @flags: TT flags that have to be set for this non-mesh client * @ttvn: the tt version number ever announcing this non-mesh client * * Add a new TT global entry for the given originator. If the entry already * exists add a new reference to the given originator (a global entry can have * references to multiple originators) and adjust the flags attribute to reflect * the function argument. * If a TT local entry exists for this non-mesh client remove it. * * The caller must hold orig_node refcount. |
1e5d49fce
|
1236 1237 |
* * Return true if the new entry has been added, false otherwise |
d4ff40f68
|
1238 |
*/ |
1e5d49fce
|
1239 1240 |
static bool batadv_tt_global_add(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, |
c018ad3de
|
1241 1242 |
const unsigned char *tt_addr, unsigned short vid, uint16_t flags, |
1e5d49fce
|
1243 |
uint8_t ttvn) |
a73105b8d
|
1244 |
{ |
170173bf3
|
1245 1246 |
struct batadv_tt_global_entry *tt_global_entry; struct batadv_tt_local_entry *tt_local_entry; |
1e5d49fce
|
1247 |
bool ret = false; |
80b3f58cf
|
1248 |
int hash_added; |
56303d34a
|
1249 |
struct batadv_tt_common_entry *common; |
7f91d06c9
|
1250 |
uint16_t local_flags; |
c6c8fea29
|
1251 |
|
cfd4f7570
|
1252 1253 1254 |
/* ignore global entries from backbone nodes */ if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) return true; |
c018ad3de
|
1255 1256 |
tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid); tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid); |
068ee6e20
|
1257 1258 1259 1260 1261 1262 1263 1264 |
/* if the node already has a local client for this entry, it has to wait * for a roaming advertisement instead of manually messing up the global * table */ if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry && !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) goto out; |
a73105b8d
|
1265 1266 |
if (!tt_global_entry) { |
d4f446925
|
1267 |
tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC); |
a73105b8d
|
1268 |
if (!tt_global_entry) |
7683fdc1e
|
1269 |
goto out; |
c0a559295
|
1270 |
common = &tt_global_entry->common; |
8fdd01530
|
1271 |
ether_addr_copy(common->addr, tt_addr); |
c018ad3de
|
1272 |
common->vid = vid; |
db08e6e55
|
1273 |
|
d4f446925
|
1274 |
common->flags = flags; |
cc47f66e6
|
1275 |
tt_global_entry->roam_at = 0; |
fdf793205
|
1276 1277 1278 1279 1280 1281 |
/* node must store current time in case of roaming. This is * needed to purge this entry out on timeout (if nobody claims * it) */ if (flags & BATADV_TT_CLIENT_ROAM) tt_global_entry->roam_at = jiffies; |
c0a559295
|
1282 |
atomic_set(&common->refcount, 2); |
30cfd02b6
|
1283 |
common->added_at = jiffies; |
db08e6e55
|
1284 1285 |
INIT_HLIST_HEAD(&tt_global_entry->orig_list); |
1d8ab8d3c
|
1286 |
atomic_set(&tt_global_entry->orig_list_count, 0); |
db08e6e55
|
1287 |
spin_lock_init(&tt_global_entry->list_lock); |
7683fdc1e
|
1288 |
|
807736f6e
|
1289 |
hash_added = batadv_hash_add(bat_priv->tt.global_hash, |
a513088d0
|
1290 |
batadv_compare_tt, |
c018ad3de
|
1291 |
batadv_choose_tt, common, |
a513088d0
|
1292 |
&common->hash_entry); |
80b3f58cf
|
1293 1294 1295 |
if (unlikely(hash_added != 0)) { /* remove the reference for the hash */ |
a513088d0
|
1296 |
batadv_tt_global_entry_free_ref(tt_global_entry); |
80b3f58cf
|
1297 1298 |
goto out_remove; } |
a73105b8d
|
1299 |
} else { |
068ee6e20
|
1300 |
common = &tt_global_entry->common; |
30cfd02b6
|
1301 1302 |
/* If there is already a global entry, we can use this one for * our processing. |
068ee6e20
|
1303 1304 1305 1306 1307 1308 1309 |
* But if we are trying to add a temporary client then here are * two options at this point: * 1) the global client is not a temporary client: the global * client has to be left as it is, temporary information * should never override any already known client state * 2) the global client is a temporary client: purge the * originator list and add the new one orig_entry |
30cfd02b6
|
1310 |
*/ |
068ee6e20
|
1311 1312 1313 1314 1315 1316 1317 1318 1319 |
if (flags & BATADV_TT_CLIENT_TEMP) { if (!(common->flags & BATADV_TT_CLIENT_TEMP)) goto out; if (batadv_tt_global_entry_has_orig(tt_global_entry, orig_node)) goto out_remove; batadv_tt_global_del_orig_list(tt_global_entry); goto add_orig_entry; } |
30cfd02b6
|
1320 1321 1322 1323 |
/* if the client was temporary added before receiving the first * OGM announcing it, we have to clear the TEMP flag */ |
068ee6e20
|
1324 |
common->flags &= ~BATADV_TT_CLIENT_TEMP; |
db08e6e55
|
1325 |
|
e9c00136a
|
1326 1327 1328 1329 1330 |
/* the change can carry possible "attribute" flags like the * TT_CLIENT_WIFI, therefore they have to be copied in the * client entry */ tt_global_entry->common.flags |= flags; |
acd34afa8
|
1331 1332 |
/* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only * one originator left in the list and we previously received a |
db08e6e55
|
1333 1334 1335 1336 1337 |
* delete + roaming change for this originator. * * We should first delete the old originator before adding the * new one. */ |
068ee6e20
|
1338 |
if (common->flags & BATADV_TT_CLIENT_ROAM) { |
a513088d0
|
1339 |
batadv_tt_global_del_orig_list(tt_global_entry); |
068ee6e20
|
1340 |
common->flags &= ~BATADV_TT_CLIENT_ROAM; |
db08e6e55
|
1341 |
tt_global_entry->roam_at = 0; |
a73105b8d
|
1342 1343 |
} } |
068ee6e20
|
1344 |
add_orig_entry: |
30cfd02b6
|
1345 |
/* add the new orig_entry (if needed) or update it */ |
d657e621a
|
1346 |
batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); |
c6c8fea29
|
1347 |
|
39c75a51e
|
1348 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
160527890
|
1349 1350 1351 1352 |
"Creating new global tt entry: %pM (vid: %d, via %pM) ", common->addr, BATADV_PRINT_VID(common->vid), orig_node->orig); |
1e5d49fce
|
1353 |
ret = true; |
c6c8fea29
|
1354 |
|
80b3f58cf
|
1355 |
out_remove: |
c5caf4ef3
|
1356 1357 1358 1359 1360 |
/* Do not remove multicast addresses from the local hash on * global additions */ if (is_multicast_ether_addr(tt_addr)) goto out; |
7f91d06c9
|
1361 |
|
a73105b8d
|
1362 |
/* remove address from local hash if present */ |
c018ad3de
|
1363 |
local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid, |
7f91d06c9
|
1364 |
"global tt received", |
c1d07431b
|
1365 |
flags & BATADV_TT_CLIENT_ROAM); |
7f91d06c9
|
1366 |
tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; |
068ee6e20
|
1367 1368 1369 1370 1371 |
if (!(flags & BATADV_TT_CLIENT_ROAM)) /* this is a normal global add. Therefore the client is not in a * roaming state anymore. */ tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM; |
7683fdc1e
|
1372 1373 |
out: if (tt_global_entry) |
a513088d0
|
1374 |
batadv_tt_global_entry_free_ref(tt_global_entry); |
068ee6e20
|
1375 1376 |
if (tt_local_entry) batadv_tt_local_entry_free_ref(tt_local_entry); |
7683fdc1e
|
1377 |
return ret; |
c6c8fea29
|
1378 |
} |
1b371d130
|
1379 1380 |
/** * batadv_transtable_best_orig - Get best originator list entry from tt entry |
4627456a7
|
1381 |
* @bat_priv: the bat priv with all the soft interface information |
981d89002
|
1382 1383 1384 1385 1386 1387 |
* @tt_global_entry: global translation table entry to be analyzed * * This functon assumes the caller holds rcu_read_lock(). * Returns best originator list entry or NULL on errors. */ static struct batadv_tt_orig_list_entry * |
4627456a7
|
1388 1389 |
batadv_transtable_best_orig(struct batadv_priv *bat_priv, struct batadv_tt_global_entry *tt_global_entry) |
981d89002
|
1390 |
{ |
4627456a7
|
1391 1392 |
struct batadv_neigh_node *router, *best_router = NULL; struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; |
981d89002
|
1393 |
struct hlist_head *head; |
981d89002
|
1394 |
struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL; |
981d89002
|
1395 1396 |
head = &tt_global_entry->orig_list; |
b67bfe0d4
|
1397 |
hlist_for_each_entry_rcu(orig_entry, head, list) { |
7351a4822
|
1398 1399 |
router = batadv_orig_router_get(orig_entry->orig_node, BATADV_IF_DEFAULT); |
981d89002
|
1400 1401 |
if (!router) continue; |
4627456a7
|
1402 |
if (best_router && |
89652331c
|
1403 1404 |
bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT, best_router, BATADV_IF_DEFAULT) <= 0) { |
4627456a7
|
1405 1406 |
batadv_neigh_node_free_ref(router); continue; |
981d89002
|
1407 |
} |
4627456a7
|
1408 1409 1410 1411 1412 1413 |
/* release the refcount for the "old" best */ if (best_router) batadv_neigh_node_free_ref(best_router); best_entry = orig_entry; best_router = router; |
981d89002
|
1414 |
} |
4627456a7
|
1415 1416 |
if (best_router) batadv_neigh_node_free_ref(best_router); |
981d89002
|
1417 1418 |
return best_entry; } |
1b371d130
|
1419 1420 1421 |
/** * batadv_tt_global_print_entry - print all orig nodes who announce the address * for this global entry |
4627456a7
|
1422 |
* @bat_priv: the bat priv with all the soft interface information |
981d89002
|
1423 1424 1425 1426 |
* @tt_global_entry: global translation table entry to be printed * @seq: debugfs table seq_file struct * * This functon assumes the caller holds rcu_read_lock(). |
db08e6e55
|
1427 |
*/ |
a513088d0
|
1428 |
static void |
4627456a7
|
1429 1430 |
batadv_tt_global_print_entry(struct batadv_priv *bat_priv, struct batadv_tt_global_entry *tt_global_entry, |
a513088d0
|
1431 |
struct seq_file *seq) |
db08e6e55
|
1432 |
{ |
981d89002
|
1433 |
struct batadv_tt_orig_list_entry *orig_entry, *best_entry; |
56303d34a
|
1434 |
struct batadv_tt_common_entry *tt_common_entry; |
7ea7b4a14
|
1435 1436 |
struct batadv_orig_node_vlan *vlan; struct hlist_head *head; |
db08e6e55
|
1437 |
uint8_t last_ttvn; |
7ea7b4a14
|
1438 |
uint16_t flags; |
db08e6e55
|
1439 1440 |
tt_common_entry = &tt_global_entry->common; |
981d89002
|
1441 |
flags = tt_common_entry->flags; |
4627456a7
|
1442 |
best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry); |
981d89002
|
1443 |
if (best_entry) { |
7ea7b4a14
|
1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 |
vlan = batadv_orig_node_vlan_get(best_entry->orig_node, tt_common_entry->vid); if (!vlan) { seq_printf(seq, " * Cannot retrieve VLAN %d for originator %pM ", BATADV_PRINT_VID(tt_common_entry->vid), best_entry->orig_node->orig); goto print_list; } |
981d89002
|
1454 |
last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); |
f9d8a5378
|
1455 |
seq_printf(seq, |
dd24ddb26
|
1456 1457 |
" %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c] ", |
981d89002
|
1458 |
'*', tt_global_entry->common.addr, |
160527890
|
1459 |
BATADV_PRINT_VID(tt_global_entry->common.vid), |
981d89002
|
1460 |
best_entry->ttvn, best_entry->orig_node->orig, |
7ea7b4a14
|
1461 |
last_ttvn, vlan->tt.crc, |
981d89002
|
1462 1463 |
(flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
dd24ddb26
|
1464 |
(flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'), |
981d89002
|
1465 |
(flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); |
7ea7b4a14
|
1466 1467 |
batadv_orig_node_vlan_free_ref(vlan); |
981d89002
|
1468 |
} |
db08e6e55
|
1469 |
|
7ea7b4a14
|
1470 |
print_list: |
db08e6e55
|
1471 |
head = &tt_global_entry->orig_list; |
b67bfe0d4
|
1472 |
hlist_for_each_entry_rcu(orig_entry, head, list) { |
981d89002
|
1473 1474 |
if (best_entry == orig_entry) continue; |
7ea7b4a14
|
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 |
vlan = batadv_orig_node_vlan_get(orig_entry->orig_node, tt_common_entry->vid); if (!vlan) { seq_printf(seq, " + Cannot retrieve VLAN %d for originator %pM ", BATADV_PRINT_VID(tt_common_entry->vid), orig_entry->orig_node->orig); continue; } |
db08e6e55
|
1485 |
last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); |
160527890
|
1486 |
seq_printf(seq, |
dd24ddb26
|
1487 1488 |
" %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c] ", |
981d89002
|
1489 |
'+', tt_global_entry->common.addr, |
160527890
|
1490 |
BATADV_PRINT_VID(tt_global_entry->common.vid), |
981d89002
|
1491 |
orig_entry->ttvn, orig_entry->orig_node->orig, |
7ea7b4a14
|
1492 |
last_ttvn, vlan->tt.crc, |
acd34afa8
|
1493 |
(flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), |
30cfd02b6
|
1494 |
(flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
dd24ddb26
|
1495 |
(flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'), |
30cfd02b6
|
1496 |
(flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); |
7ea7b4a14
|
1497 1498 |
batadv_orig_node_vlan_free_ref(vlan); |
db08e6e55
|
1499 1500 |
} } |
08c36d3e8
|
1501 |
int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) |
c6c8fea29
|
1502 1503 |
{ struct net_device *net_dev = (struct net_device *)seq->private; |
56303d34a
|
1504 |
struct batadv_priv *bat_priv = netdev_priv(net_dev); |
807736f6e
|
1505 |
struct batadv_hashtable *hash = bat_priv->tt.global_hash; |
56303d34a
|
1506 1507 1508 |
struct batadv_tt_common_entry *tt_common_entry; struct batadv_tt_global_entry *tt_global; struct batadv_hard_iface *primary_if; |
c6c8fea29
|
1509 |
struct hlist_head *head; |
c90681b85
|
1510 |
uint32_t i; |
c6c8fea29
|
1511 |
|
30da63a6a
|
1512 1513 |
primary_if = batadv_seq_print_text_primary_if_get(seq); if (!primary_if) |
32ae9b221
|
1514 |
goto out; |
c6c8fea29
|
1515 |
|
2dafb49d8
|
1516 1517 1518 |
seq_printf(seq, "Globally announced TT entries received via the mesh %s ", |
c6c8fea29
|
1519 |
net_dev->name); |
160527890
|
1520 1521 1522 1523 |
seq_printf(seq, " %-13s %s %s %-15s %s (%-10s) %s ", "Client", "VID", "(TTVN)", "Originator", "(Curr TTVN)", "CRC", "Flags"); |
c6c8fea29
|
1524 |
|
c6c8fea29
|
1525 1526 |
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; |
7aadf889e
|
1527 |
rcu_read_lock(); |
b67bfe0d4
|
1528 |
hlist_for_each_entry_rcu(tt_common_entry, |
7aadf889e
|
1529 |
head, hash_entry) { |
56303d34a
|
1530 1531 1532 |
tt_global = container_of(tt_common_entry, struct batadv_tt_global_entry, common); |
4627456a7
|
1533 |
batadv_tt_global_print_entry(bat_priv, tt_global, seq); |
c6c8fea29
|
1534 |
} |
7aadf889e
|
1535 |
rcu_read_unlock(); |
c6c8fea29
|
1536 |
} |
32ae9b221
|
1537 1538 |
out: if (primary_if) |
e5d89254b
|
1539 |
batadv_hardif_free_ref(primary_if); |
30da63a6a
|
1540 |
return 0; |
c6c8fea29
|
1541 |
} |
1d8ab8d3c
|
1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 |
/** * batadv_tt_global_del_orig_entry - remove and free an orig_entry * @tt_global_entry: the global entry to remove the orig_entry from * @orig_entry: the orig entry to remove and free * * Remove an orig_entry from its list in the given tt_global_entry and * free this orig_entry afterwards. */ static void batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry, struct batadv_tt_orig_list_entry *orig_entry) { batadv_tt_global_size_dec(orig_entry->orig_node, tt_global_entry->common.vid); atomic_dec(&tt_global_entry->orig_list_count); hlist_del_rcu(&orig_entry->list); batadv_tt_orig_list_entry_free_ref(orig_entry); } |
db08e6e55
|
1560 |
/* deletes the orig list of a tt_global_entry */ |
a513088d0
|
1561 |
static void |
56303d34a
|
1562 |
batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) |
c6c8fea29
|
1563 |
{ |
db08e6e55
|
1564 |
struct hlist_head *head; |
b67bfe0d4
|
1565 |
struct hlist_node *safe; |
56303d34a
|
1566 |
struct batadv_tt_orig_list_entry *orig_entry; |
a73105b8d
|
1567 |
|
db08e6e55
|
1568 1569 |
spin_lock_bh(&tt_global_entry->list_lock); head = &tt_global_entry->orig_list; |
1d8ab8d3c
|
1570 1571 |
hlist_for_each_entry_safe(orig_entry, safe, head, list) batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry); |
db08e6e55
|
1572 |
spin_unlock_bh(&tt_global_entry->list_lock); |
db08e6e55
|
1573 |
} |
1d8ab8d3c
|
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 |
/** * batadv_tt_global_del_orig_node - remove orig_node from a global tt entry * @bat_priv: the bat priv with all the soft interface information * @tt_global_entry: the global entry to remove the orig_node from * @orig_node: the originator announcing the client * @message: message to append to the log on deletion * * Remove the given orig_node and its according orig_entry from the given * global tt entry. */ |
a513088d0
|
1584 |
static void |
1d8ab8d3c
|
1585 1586 1587 1588 |
batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv, struct batadv_tt_global_entry *tt_global_entry, struct batadv_orig_node *orig_node, const char *message) |
db08e6e55
|
1589 1590 |
{ struct hlist_head *head; |
b67bfe0d4
|
1591 |
struct hlist_node *safe; |
56303d34a
|
1592 |
struct batadv_tt_orig_list_entry *orig_entry; |
160527890
|
1593 |
unsigned short vid; |
db08e6e55
|
1594 1595 1596 |
spin_lock_bh(&tt_global_entry->list_lock); head = &tt_global_entry->orig_list; |
b67bfe0d4
|
1597 |
hlist_for_each_entry_safe(orig_entry, safe, head, list) { |
db08e6e55
|
1598 |
if (orig_entry->orig_node == orig_node) { |
160527890
|
1599 |
vid = tt_global_entry->common.vid; |
39c75a51e
|
1600 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
160527890
|
1601 1602 |
"Deleting %pM from global tt entry %pM (vid: %d): %s ", |
1eda58bfc
|
1603 |
orig_node->orig, |
160527890
|
1604 1605 |
tt_global_entry->common.addr, BATADV_PRINT_VID(vid), message); |
1d8ab8d3c
|
1606 1607 |
batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry); |
db08e6e55
|
1608 1609 1610 1611 |
} } spin_unlock_bh(&tt_global_entry->list_lock); } |
db08e6e55
|
1612 |
/* If the client is to be deleted, we check if it is the last origantor entry |
acd34afa8
|
1613 1614 |
* within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the * timer, otherwise we simply remove the originator scheduled for deletion. |
db08e6e55
|
1615 |
*/ |
a513088d0
|
1616 |
static void |
56303d34a
|
1617 1618 1619 1620 |
batadv_tt_global_del_roaming(struct batadv_priv *bat_priv, struct batadv_tt_global_entry *tt_global_entry, struct batadv_orig_node *orig_node, const char *message) |
db08e6e55
|
1621 1622 1623 |
{ bool last_entry = true; struct hlist_head *head; |
56303d34a
|
1624 |
struct batadv_tt_orig_list_entry *orig_entry; |
db08e6e55
|
1625 1626 1627 1628 1629 1630 1631 |
/* no local entry exists, case 1: * Check if this is the last one or if other entries exist. */ rcu_read_lock(); head = &tt_global_entry->orig_list; |
b67bfe0d4
|
1632 |
hlist_for_each_entry_rcu(orig_entry, head, list) { |
db08e6e55
|
1633 1634 1635 1636 1637 1638 1639 1640 1641 |
if (orig_entry->orig_node != orig_node) { last_entry = false; break; } } rcu_read_unlock(); if (last_entry) { /* its the last one, mark for roaming. */ |
acd34afa8
|
1642 |
tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM; |
db08e6e55
|
1643 1644 1645 1646 1647 |
tt_global_entry->roam_at = jiffies; } else /* there is another entry, we can simply delete this * one and can still use the other one. */ |
1d8ab8d3c
|
1648 1649 |
batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, orig_node, message); |
db08e6e55
|
1650 |
} |
c018ad3de
|
1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 |
/** * batadv_tt_global_del - remove a client from the global table * @bat_priv: the bat priv with all the soft interface information * @orig_node: an originator serving this client * @addr: the mac address of the client * @vid: VLAN identifier * @message: a message explaining the reason for deleting the client to print * for debugging purpose * @roaming: true if the deletion has been triggered by a roaming event */ |
56303d34a
|
1661 1662 |
static void batadv_tt_global_del(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, |
c018ad3de
|
1663 |
const unsigned char *addr, unsigned short vid, |
a513088d0
|
1664 |
const char *message, bool roaming) |
a73105b8d
|
1665 |
{ |
170173bf3
|
1666 |
struct batadv_tt_global_entry *tt_global_entry; |
56303d34a
|
1667 |
struct batadv_tt_local_entry *local_entry = NULL; |
a73105b8d
|
1668 |
|
c018ad3de
|
1669 |
tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); |
db08e6e55
|
1670 |
if (!tt_global_entry) |
7683fdc1e
|
1671 |
goto out; |
a73105b8d
|
1672 |
|
db08e6e55
|
1673 |
if (!roaming) { |
1d8ab8d3c
|
1674 1675 |
batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, orig_node, message); |
db08e6e55
|
1676 1677 |
if (hlist_empty(&tt_global_entry->orig_list)) |
be73b488d
|
1678 1679 |
batadv_tt_global_free(bat_priv, tt_global_entry, message); |
db08e6e55
|
1680 1681 1682 |
goto out; } |
92f90f56c
|
1683 1684 1685 |
/* if we are deleting a global entry due to a roam * event, there are two possibilities: |
db08e6e55
|
1686 1687 |
* 1) the client roamed from node A to node B => if there * is only one originator left for this client, we mark |
acd34afa8
|
1688 |
* it with BATADV_TT_CLIENT_ROAM, we start a timer and we |
92f90f56c
|
1689 1690 |
* wait for node B to claim it. In case of timeout * the entry is purged. |
db08e6e55
|
1691 1692 1693 |
* * If there are other originators left, we directly delete * the originator. |
92f90f56c
|
1694 |
* 2) the client roamed to us => we can directly delete |
9cfc7bd60
|
1695 1696 |
* the global entry, since it is useless now. */ |
a513088d0
|
1697 |
local_entry = batadv_tt_local_hash_find(bat_priv, |
c018ad3de
|
1698 1699 |
tt_global_entry->common.addr, vid); |
a513088d0
|
1700 |
if (local_entry) { |
db08e6e55
|
1701 |
/* local entry exists, case 2: client roamed to us. */ |
a513088d0
|
1702 |
batadv_tt_global_del_orig_list(tt_global_entry); |
be73b488d
|
1703 |
batadv_tt_global_free(bat_priv, tt_global_entry, message); |
db08e6e55
|
1704 1705 |
} else /* no local entry exists, case 1: check for roaming */ |
a513088d0
|
1706 1707 |
batadv_tt_global_del_roaming(bat_priv, tt_global_entry, orig_node, message); |
92f90f56c
|
1708 |
|
92f90f56c
|
1709 |
|
cc47f66e6
|
1710 |
out: |
7683fdc1e
|
1711 |
if (tt_global_entry) |
a513088d0
|
1712 1713 1714 |
batadv_tt_global_entry_free_ref(tt_global_entry); if (local_entry) batadv_tt_local_entry_free_ref(local_entry); |
a73105b8d
|
1715 |
} |
95fb130d6
|
1716 1717 1718 1719 1720 1721 1722 1723 1724 |
/** * batadv_tt_global_del_orig - remove all the TT global entries belonging to the * given originator matching the provided vid * @bat_priv: the bat priv with all the soft interface information * @orig_node: the originator owning the entries to remove * @match_vid: the VLAN identifier to match. If negative all the entries will be * removed * @message: debug message to print as "reason" */ |
56303d34a
|
1725 1726 |
void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, |
95fb130d6
|
1727 |
int32_t match_vid, |
56303d34a
|
1728 |
const char *message) |
c6c8fea29
|
1729 |
{ |
56303d34a
|
1730 1731 |
struct batadv_tt_global_entry *tt_global; struct batadv_tt_common_entry *tt_common_entry; |
c90681b85
|
1732 |
uint32_t i; |
807736f6e
|
1733 |
struct batadv_hashtable *hash = bat_priv->tt.global_hash; |
b67bfe0d4
|
1734 |
struct hlist_node *safe; |
a73105b8d
|
1735 |
struct hlist_head *head; |
7683fdc1e
|
1736 |
spinlock_t *list_lock; /* protects write access to the hash lists */ |
160527890
|
1737 |
unsigned short vid; |
c6c8fea29
|
1738 |
|
6e8014947
|
1739 1740 |
if (!hash) return; |
a73105b8d
|
1741 1742 |
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; |
7683fdc1e
|
1743 |
list_lock = &hash->list_locks[i]; |
c6c8fea29
|
1744 |
|
7683fdc1e
|
1745 |
spin_lock_bh(list_lock); |
b67bfe0d4
|
1746 |
hlist_for_each_entry_safe(tt_common_entry, safe, |
7c64fd98c
|
1747 |
head, hash_entry) { |
95fb130d6
|
1748 1749 1750 |
/* remove only matching entries */ if (match_vid >= 0 && tt_common_entry->vid != match_vid) continue; |
56303d34a
|
1751 1752 1753 |
tt_global = container_of(tt_common_entry, struct batadv_tt_global_entry, common); |
db08e6e55
|
1754 |
|
1d8ab8d3c
|
1755 1756 |
batadv_tt_global_del_orig_node(bat_priv, tt_global, orig_node, message); |
db08e6e55
|
1757 |
|
56303d34a
|
1758 |
if (hlist_empty(&tt_global->orig_list)) { |
160527890
|
1759 |
vid = tt_global->common.vid; |
39c75a51e
|
1760 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
160527890
|
1761 1762 1763 1764 |
"Deleting global tt entry %pM (vid: %d): %s ", tt_global->common.addr, BATADV_PRINT_VID(vid), message); |
b67bfe0d4
|
1765 |
hlist_del_rcu(&tt_common_entry->hash_entry); |
56303d34a
|
1766 |
batadv_tt_global_entry_free_ref(tt_global); |
7683fdc1e
|
1767 |
} |
a73105b8d
|
1768 |
} |
7683fdc1e
|
1769 |
spin_unlock_bh(list_lock); |
c6c8fea29
|
1770 |
} |
e17931d1a
|
1771 |
orig_node->capa_initialized &= ~BATADV_ORIG_CAPA_HAS_TT; |
c6c8fea29
|
1772 |
} |
30cfd02b6
|
1773 1774 |
static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global, char **msg) |
cc47f66e6
|
1775 |
{ |
30cfd02b6
|
1776 1777 1778 |
bool purge = false; unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT; unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT; |
42d0b044b
|
1779 |
|
30cfd02b6
|
1780 1781 1782 1783 1784 1785 |
if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) && batadv_has_timed_out(tt_global->roam_at, roam_timeout)) { purge = true; *msg = "Roaming timeout "; } |
42d0b044b
|
1786 |
|
30cfd02b6
|
1787 1788 1789 1790 1791 |
if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) && batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) { purge = true; *msg = "Temporary client timeout "; |
42d0b044b
|
1792 |
} |
30cfd02b6
|
1793 1794 |
return purge; |
42d0b044b
|
1795 |
} |
30cfd02b6
|
1796 |
static void batadv_tt_global_purge(struct batadv_priv *bat_priv) |
42d0b044b
|
1797 |
{ |
807736f6e
|
1798 |
struct batadv_hashtable *hash = bat_priv->tt.global_hash; |
cc47f66e6
|
1799 |
struct hlist_head *head; |
b67bfe0d4
|
1800 |
struct hlist_node *node_tmp; |
7683fdc1e
|
1801 |
spinlock_t *list_lock; /* protects write access to the hash lists */ |
c90681b85
|
1802 |
uint32_t i; |
30cfd02b6
|
1803 1804 1805 |
char *msg = NULL; struct batadv_tt_common_entry *tt_common; struct batadv_tt_global_entry *tt_global; |
cc47f66e6
|
1806 |
|
cc47f66e6
|
1807 1808 |
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; |
7683fdc1e
|
1809 |
list_lock = &hash->list_locks[i]; |
cc47f66e6
|
1810 |
|
7683fdc1e
|
1811 |
spin_lock_bh(list_lock); |
b67bfe0d4
|
1812 |
hlist_for_each_entry_safe(tt_common, node_tmp, head, |
30cfd02b6
|
1813 1814 1815 1816 1817 1818 1819 1820 1821 |
hash_entry) { tt_global = container_of(tt_common, struct batadv_tt_global_entry, common); if (!batadv_tt_global_to_purge(tt_global, &msg)) continue; batadv_dbg(BATADV_DBG_TT, bat_priv, |
160527890
|
1822 1823 1824 1825 1826 |
"Deleting global tt entry %pM (vid: %d): %s ", tt_global->common.addr, BATADV_PRINT_VID(tt_global->common.vid), msg); |
30cfd02b6
|
1827 |
|
b67bfe0d4
|
1828 |
hlist_del_rcu(&tt_common->hash_entry); |
30cfd02b6
|
1829 1830 1831 |
batadv_tt_global_entry_free_ref(tt_global); } |
7683fdc1e
|
1832 |
spin_unlock_bh(list_lock); |
cc47f66e6
|
1833 |
} |
cc47f66e6
|
1834 |
} |
56303d34a
|
1835 |
static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) |
c6c8fea29
|
1836 |
{ |
5bf74e9ca
|
1837 |
struct batadv_hashtable *hash; |
7683fdc1e
|
1838 |
spinlock_t *list_lock; /* protects write access to the hash lists */ |
56303d34a
|
1839 1840 |
struct batadv_tt_common_entry *tt_common_entry; struct batadv_tt_global_entry *tt_global; |
b67bfe0d4
|
1841 |
struct hlist_node *node_tmp; |
7683fdc1e
|
1842 |
struct hlist_head *head; |
c90681b85
|
1843 |
uint32_t i; |
7683fdc1e
|
1844 |
|
807736f6e
|
1845 |
if (!bat_priv->tt.global_hash) |
c6c8fea29
|
1846 |
return; |
807736f6e
|
1847 |
hash = bat_priv->tt.global_hash; |
7683fdc1e
|
1848 1849 1850 1851 1852 1853 |
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; list_lock = &hash->list_locks[i]; spin_lock_bh(list_lock); |
b67bfe0d4
|
1854 |
hlist_for_each_entry_safe(tt_common_entry, node_tmp, |
7683fdc1e
|
1855 |
head, hash_entry) { |
b67bfe0d4
|
1856 |
hlist_del_rcu(&tt_common_entry->hash_entry); |
56303d34a
|
1857 1858 1859 1860 |
tt_global = container_of(tt_common_entry, struct batadv_tt_global_entry, common); batadv_tt_global_entry_free_ref(tt_global); |
7683fdc1e
|
1861 1862 1863 |
} spin_unlock_bh(list_lock); } |
1a8eaf073
|
1864 |
batadv_hash_destroy(hash); |
7683fdc1e
|
1865 |
|
807736f6e
|
1866 |
bat_priv->tt.global_hash = NULL; |
c6c8fea29
|
1867 |
} |
56303d34a
|
1868 1869 1870 |
static bool _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, struct batadv_tt_global_entry *tt_global_entry) |
59b699cde
|
1871 1872 |
{ bool ret = false; |
acd34afa8
|
1873 1874 |
if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI && tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI) |
59b699cde
|
1875 |
ret = true; |
2d2fcc2a3
|
1876 1877 1878 1879 |
/* check if the two clients are marked as isolated */ if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA && tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA) ret = true; |
59b699cde
|
1880 1881 |
return ret; } |
c018ad3de
|
1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 |
/** * batadv_transtable_search - get the mesh destination for a given client * @bat_priv: the bat priv with all the soft interface information * @src: mac address of the source client * @addr: mac address of the destination client * @vid: VLAN identifier * * Returns a pointer to the originator that was selected as destination in the * mesh for contacting the client 'addr', NULL otherwise. * In case of multiple originators serving the same client, the function returns * the best one (best in terms of metric towards the destination node). * * If the two clients are AP isolated the function returns NULL. */ |
56303d34a
|
1896 1897 |
struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, const uint8_t *src, |
c018ad3de
|
1898 1899 |
const uint8_t *addr, unsigned short vid) |
c6c8fea29
|
1900 |
{ |
56303d34a
|
1901 1902 1903 |
struct batadv_tt_local_entry *tt_local_entry = NULL; struct batadv_tt_global_entry *tt_global_entry = NULL; struct batadv_orig_node *orig_node = NULL; |
981d89002
|
1904 |
struct batadv_tt_orig_list_entry *best_entry; |
b8cbd81d0
|
1905 |
|
eceb22ae0
|
1906 |
if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) { |
c018ad3de
|
1907 |
tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid); |
068ee6e20
|
1908 1909 |
if (!tt_local_entry || (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) |
3d393e473
|
1910 1911 |
goto out; } |
7aadf889e
|
1912 |
|
c018ad3de
|
1913 |
tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); |
2dafb49d8
|
1914 |
if (!tt_global_entry) |
7b36e8eef
|
1915 |
goto out; |
7aadf889e
|
1916 |
|
3d393e473
|
1917 |
/* check whether the clients should not communicate due to AP |
9cfc7bd60
|
1918 1919 |
* isolation */ |
a513088d0
|
1920 1921 |
if (tt_local_entry && _batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) |
3d393e473
|
1922 |
goto out; |
db08e6e55
|
1923 |
rcu_read_lock(); |
4627456a7
|
1924 |
best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry); |
db08e6e55
|
1925 |
/* found anything? */ |
981d89002
|
1926 1927 |
if (best_entry) orig_node = best_entry->orig_node; |
db08e6e55
|
1928 1929 1930 |
if (orig_node && !atomic_inc_not_zero(&orig_node->refcount)) orig_node = NULL; rcu_read_unlock(); |
981d89002
|
1931 |
|
7b36e8eef
|
1932 |
out: |
3d393e473
|
1933 |
if (tt_global_entry) |
a513088d0
|
1934 |
batadv_tt_global_entry_free_ref(tt_global_entry); |
3d393e473
|
1935 |
if (tt_local_entry) |
a513088d0
|
1936 |
batadv_tt_local_entry_free_ref(tt_local_entry); |
3d393e473
|
1937 |
|
7b36e8eef
|
1938 |
return orig_node; |
c6c8fea29
|
1939 |
} |
a73105b8d
|
1940 |
|
ced72933a
|
1941 1942 1943 1944 |
/** * batadv_tt_global_crc - calculates the checksum of the local table belonging * to the given orig_node * @bat_priv: the bat priv with all the soft interface information |
0ffa9e8d8
|
1945 |
* @orig_node: originator for which the CRC should be computed |
7ea7b4a14
|
1946 |
* @vid: VLAN identifier for which the CRC32 has to be computed |
0ffa9e8d8
|
1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 |
* * This function computes the checksum for the global table corresponding to a * specific originator. In particular, the checksum is computed as follows: For * each client connected to the originator the CRC32C of the MAC address and the * VID is computed and then all the CRC32Cs of the various clients are xor'ed * together. * * The idea behind is that CRC32C should be used as much as possible in order to * produce a unique hash of the table, but since the order which is used to feed * the CRC32C function affects the result and since every node in the network * probably sorts the clients differently, the hash function cannot be directly * computed over the entire table. Hence the CRC32C is used only on * the single client entry, while all the results are then xor'ed together * because the XOR operation can combine them all while trying to reduce the * noise as much as possible. * * Returns the checksum of the global table of a given originator. |
ced72933a
|
1964 1965 |
*/ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, |
7ea7b4a14
|
1966 1967 |
struct batadv_orig_node *orig_node, unsigned short vid) |
a73105b8d
|
1968 |
{ |
807736f6e
|
1969 |
struct batadv_hashtable *hash = bat_priv->tt.global_hash; |
56303d34a
|
1970 1971 |
struct batadv_tt_common_entry *tt_common; struct batadv_tt_global_entry *tt_global; |
a73105b8d
|
1972 |
struct hlist_head *head; |
0ffa9e8d8
|
1973 |
uint32_t i, crc_tmp, crc = 0; |
0eb01568f
|
1974 |
uint8_t flags; |
a30e22ca8
|
1975 |
__be16 tmp_vid; |
a73105b8d
|
1976 1977 1978 1979 1980 |
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; rcu_read_lock(); |
b67bfe0d4
|
1981 |
hlist_for_each_entry_rcu(tt_common, head, hash_entry) { |
56303d34a
|
1982 1983 1984 |
tt_global = container_of(tt_common, struct batadv_tt_global_entry, common); |
7ea7b4a14
|
1985 1986 1987 1988 1989 |
/* compute the CRC only for entries belonging to the * VLAN identified by the vid passed as parameter */ if (tt_common->vid != vid) continue; |
db08e6e55
|
1990 1991 1992 1993 1994 |
/* Roaming clients are in the global table for * consistency only. They don't have to be * taken into account while computing the * global crc */ |
acd34afa8
|
1995 |
if (tt_common->flags & BATADV_TT_CLIENT_ROAM) |
db08e6e55
|
1996 |
continue; |
30cfd02b6
|
1997 1998 1999 2000 2001 2002 |
/* Temporary clients have not been announced yet, so * they have to be skipped while computing the global * crc */ if (tt_common->flags & BATADV_TT_CLIENT_TEMP) continue; |
db08e6e55
|
2003 2004 2005 2006 |
/* find out if this global entry is announced by this * originator */ |
56303d34a
|
2007 |
if (!batadv_tt_global_entry_has_orig(tt_global, |
a513088d0
|
2008 |
orig_node)) |
db08e6e55
|
2009 |
continue; |
a30e22ca8
|
2010 2011 2012 2013 2014 |
/* use network order to read the VID: this ensures that * every node reads the bytes in the same order. */ tmp_vid = htons(tt_common->vid); crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid)); |
0eb01568f
|
2015 2016 2017 2018 2019 2020 |
/* compute the CRC on flags that have to be kept in sync * among nodes */ flags = tt_common->flags & BATADV_TT_SYNC_MASK; crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags)); |
0ffa9e8d8
|
2021 |
crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); |
a73105b8d
|
2022 2023 2024 |
} rcu_read_unlock(); } |
ced72933a
|
2025 |
return crc; |
a73105b8d
|
2026 |
} |
ced72933a
|
2027 2028 2029 |
/** * batadv_tt_local_crc - calculates the checksum of the local table * @bat_priv: the bat priv with all the soft interface information |
7ea7b4a14
|
2030 |
* @vid: VLAN identifier for which the CRC32 has to be computed |
0ffa9e8d8
|
2031 2032 2033 2034 2035 |
* * For details about the computation, please refer to the documentation for * batadv_tt_global_crc(). * * Returns the checksum of the local table |
ced72933a
|
2036 |
*/ |
7ea7b4a14
|
2037 2038 |
static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv, unsigned short vid) |
a73105b8d
|
2039 |
{ |
807736f6e
|
2040 |
struct batadv_hashtable *hash = bat_priv->tt.local_hash; |
56303d34a
|
2041 |
struct batadv_tt_common_entry *tt_common; |
a73105b8d
|
2042 |
struct hlist_head *head; |
0ffa9e8d8
|
2043 |
uint32_t i, crc_tmp, crc = 0; |
0eb01568f
|
2044 |
uint8_t flags; |
a30e22ca8
|
2045 |
__be16 tmp_vid; |
a73105b8d
|
2046 2047 2048 2049 2050 |
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; rcu_read_lock(); |
b67bfe0d4
|
2051 |
hlist_for_each_entry_rcu(tt_common, head, hash_entry) { |
7ea7b4a14
|
2052 2053 2054 2055 2056 |
/* compute the CRC only for entries belonging to the * VLAN identified by vid */ if (tt_common->vid != vid) continue; |
058d0e269
|
2057 |
/* not yet committed clients have not to be taken into |
9cfc7bd60
|
2058 2059 |
* account while computing the CRC */ |
acd34afa8
|
2060 |
if (tt_common->flags & BATADV_TT_CLIENT_NEW) |
058d0e269
|
2061 |
continue; |
ced72933a
|
2062 |
|
a30e22ca8
|
2063 2064 2065 2066 2067 |
/* use network order to read the VID: this ensures that * every node reads the bytes in the same order. */ tmp_vid = htons(tt_common->vid); crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid)); |
0eb01568f
|
2068 2069 2070 2071 2072 2073 |
/* compute the CRC on flags that have to be kept in sync * among nodes */ flags = tt_common->flags & BATADV_TT_SYNC_MASK; crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags)); |
0ffa9e8d8
|
2074 |
crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); |
a73105b8d
|
2075 |
} |
a73105b8d
|
2076 2077 |
rcu_read_unlock(); } |
ced72933a
|
2078 |
return crc; |
a73105b8d
|
2079 |
} |
56303d34a
|
2080 |
static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) |
a73105b8d
|
2081 |
{ |
56303d34a
|
2082 |
struct batadv_tt_req_node *node, *safe; |
a73105b8d
|
2083 |
|
807736f6e
|
2084 |
spin_lock_bh(&bat_priv->tt.req_list_lock); |
a73105b8d
|
2085 |
|
807736f6e
|
2086 |
list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { |
a73105b8d
|
2087 2088 2089 |
list_del(&node->list); kfree(node); } |
807736f6e
|
2090 |
spin_unlock_bh(&bat_priv->tt.req_list_lock); |
a73105b8d
|
2091 |
} |
56303d34a
|
2092 2093 |
static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, |
e8cf234a4
|
2094 2095 |
const void *tt_buff, uint16_t tt_buff_len) |
a73105b8d
|
2096 |
{ |
a73105b8d
|
2097 |
/* Replace the old buffer only if I received something in the |
9cfc7bd60
|
2098 2099 |
* last OGM (the OGM could carry no changes) */ |
a73105b8d
|
2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 |
spin_lock_bh(&orig_node->tt_buff_lock); if (tt_buff_len > 0) { kfree(orig_node->tt_buff); orig_node->tt_buff_len = 0; orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); if (orig_node->tt_buff) { memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); orig_node->tt_buff_len = tt_buff_len; } } spin_unlock_bh(&orig_node->tt_buff_lock); } |
56303d34a
|
2112 |
static void batadv_tt_req_purge(struct batadv_priv *bat_priv) |
a73105b8d
|
2113 |
{ |
56303d34a
|
2114 |
struct batadv_tt_req_node *node, *safe; |
a73105b8d
|
2115 |
|
807736f6e
|
2116 2117 |
spin_lock_bh(&bat_priv->tt.req_list_lock); list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { |
42d0b044b
|
2118 2119 |
if (batadv_has_timed_out(node->issued_at, BATADV_TT_REQUEST_TIMEOUT)) { |
a73105b8d
|
2120 2121 2122 2123 |
list_del(&node->list); kfree(node); } } |
807736f6e
|
2124 |
spin_unlock_bh(&bat_priv->tt.req_list_lock); |
a73105b8d
|
2125 2126 2127 |
} /* returns the pointer to the new tt_req_node struct if no request |
9cfc7bd60
|
2128 2129 |
* has already been issued for this orig_node, NULL otherwise */ |
56303d34a
|
2130 2131 2132 |
static struct batadv_tt_req_node * batadv_new_tt_req_node(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) |
a73105b8d
|
2133 |
{ |
56303d34a
|
2134 |
struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; |
a73105b8d
|
2135 |
|
807736f6e
|
2136 2137 |
spin_lock_bh(&bat_priv->tt.req_list_lock); list_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) { |
1eda58bfc
|
2138 2139 |
if (batadv_compare_eth(tt_req_node_tmp, orig_node) && !batadv_has_timed_out(tt_req_node_tmp->issued_at, |
42d0b044b
|
2140 |
BATADV_TT_REQUEST_TIMEOUT)) |
a73105b8d
|
2141 2142 2143 2144 2145 2146 |
goto unlock; } tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC); if (!tt_req_node) goto unlock; |
8fdd01530
|
2147 |
ether_addr_copy(tt_req_node->addr, orig_node->orig); |
a73105b8d
|
2148 |
tt_req_node->issued_at = jiffies; |
807736f6e
|
2149 |
list_add(&tt_req_node->list, &bat_priv->tt.req_list); |
a73105b8d
|
2150 |
unlock: |
807736f6e
|
2151 |
spin_unlock_bh(&bat_priv->tt.req_list_lock); |
a73105b8d
|
2152 2153 |
return tt_req_node; } |
335fbe0f5
|
2154 2155 2156 2157 2158 2159 2160 2161 |
/** * batadv_tt_local_valid - verify that given tt entry is a valid one * @entry_ptr: to be checked local tt entry * @data_ptr: not used but definition required to satisfy the callback prototype * * Returns 1 if the entry is a valid, 0 otherwise. */ static int batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr) |
058d0e269
|
2162 |
{ |
56303d34a
|
2163 |
const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; |
058d0e269
|
2164 |
|
acd34afa8
|
2165 |
if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) |
058d0e269
|
2166 2167 2168 |
return 0; return 1; } |
a513088d0
|
2169 2170 |
static int batadv_tt_global_valid(const void *entry_ptr, const void *data_ptr) |
a73105b8d
|
2171 |
{ |
56303d34a
|
2172 2173 2174 |
const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; const struct batadv_tt_global_entry *tt_global_entry; const struct batadv_orig_node *orig_node = data_ptr; |
a73105b8d
|
2175 |
|
30cfd02b6
|
2176 2177 |
if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM || tt_common_entry->flags & BATADV_TT_CLIENT_TEMP) |
cc47f66e6
|
2178 |
return 0; |
56303d34a
|
2179 2180 |
tt_global_entry = container_of(tt_common_entry, struct batadv_tt_global_entry, |
48100bac8
|
2181 |
common); |
a513088d0
|
2182 |
return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); |
a73105b8d
|
2183 |
} |
335fbe0f5
|
2184 |
/** |
7ea7b4a14
|
2185 2186 |
* batadv_tt_tvlv_generate - fill the tvlv buff with the tt entries from the * specified tt hash |
335fbe0f5
|
2187 2188 2189 |
* @bat_priv: the bat priv with all the soft interface information * @hash: hash table containing the tt entries * @tt_len: expected tvlv tt data buffer length in number of bytes |
7ea7b4a14
|
2190 |
* @tvlv_buff: pointer to the buffer to fill with the TT data |
335fbe0f5
|
2191 2192 |
* @valid_cb: function to filter tt change entries * @cb_data: data passed to the filter function as argument |
335fbe0f5
|
2193 |
*/ |
7ea7b4a14
|
2194 2195 2196 2197 2198 |
static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, struct batadv_hashtable *hash, void *tvlv_buff, uint16_t tt_len, int (*valid_cb)(const void *, const void *), void *cb_data) |
a73105b8d
|
2199 |
{ |
56303d34a
|
2200 |
struct batadv_tt_common_entry *tt_common_entry; |
335fbe0f5
|
2201 |
struct batadv_tvlv_tt_change *tt_change; |
a73105b8d
|
2202 |
struct hlist_head *head; |
335fbe0f5
|
2203 |
uint16_t tt_tot, tt_num_entries = 0; |
c90681b85
|
2204 |
uint32_t i; |
a73105b8d
|
2205 |
|
298e6e685
|
2206 |
tt_tot = batadv_tt_entries(tt_len); |
7ea7b4a14
|
2207 |
tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; |
a73105b8d
|
2208 2209 2210 2211 |
rcu_read_lock(); for (i = 0; i < hash->size; i++) { head = &hash->table[i]; |
b67bfe0d4
|
2212 |
hlist_for_each_entry_rcu(tt_common_entry, |
a73105b8d
|
2213 |
head, hash_entry) { |
335fbe0f5
|
2214 |
if (tt_tot == tt_num_entries) |
a73105b8d
|
2215 |
break; |
48100bac8
|
2216 |
if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) |
a73105b8d
|
2217 |
continue; |
8fdd01530
|
2218 |
ether_addr_copy(tt_change->addr, tt_common_entry->addr); |
27b37ebfa
|
2219 |
tt_change->flags = tt_common_entry->flags; |
c018ad3de
|
2220 |
tt_change->vid = htons(tt_common_entry->vid); |
ca6630464
|
2221 2222 |
memset(tt_change->reserved, 0, sizeof(tt_change->reserved)); |
a73105b8d
|
2223 |
|
335fbe0f5
|
2224 |
tt_num_entries++; |
a73105b8d
|
2225 2226 2227 2228 |
tt_change++; } } rcu_read_unlock(); |
7ea7b4a14
|
2229 |
} |
a73105b8d
|
2230 |
|
7ea7b4a14
|
2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 |
/** * batadv_tt_global_check_crc - check if all the CRCs are correct * @orig_node: originator for which the CRCs have to be checked * @tt_vlan: pointer to the first tvlv VLAN entry * @num_vlan: number of tvlv VLAN entries * @create: if true, create VLAN objects if not found * * Return true if all the received CRCs match the locally stored ones, false * otherwise */ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, struct batadv_tvlv_tt_vlan_data *tt_vlan, uint16_t num_vlan) { struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp; struct batadv_orig_node_vlan *vlan; |
91c2b1a9f
|
2247 |
uint32_t crc; |
7ea7b4a14
|
2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 |
int i; /* check if each received CRC matches the locally stored one */ for (i = 0; i < num_vlan; i++) { tt_vlan_tmp = tt_vlan + i; /* if orig_node is a backbone node for this VLAN, don't check * the CRC as we ignore all the global entries over it */ if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv, |
cfd4f7570
|
2258 2259 |
orig_node->orig, ntohs(tt_vlan_tmp->vid))) |
7ea7b4a14
|
2260 2261 2262 2263 2264 2265 |
continue; vlan = batadv_orig_node_vlan_get(orig_node, ntohs(tt_vlan_tmp->vid)); if (!vlan) return false; |
91c2b1a9f
|
2266 2267 2268 2269 |
crc = vlan->tt.crc; batadv_orig_node_vlan_free_ref(vlan); if (crc != ntohl(tt_vlan_tmp->crc)) |
7ea7b4a14
|
2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 |
return false; } return true; } /** * batadv_tt_local_update_crc - update all the local CRCs * @bat_priv: the bat priv with all the soft interface information */ static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv) { struct batadv_softif_vlan *vlan; /* recompute the global CRC for each VLAN */ rcu_read_lock(); hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid); } rcu_read_unlock(); } /** * batadv_tt_global_update_crc - update all the global CRCs for this orig_node * @bat_priv: the bat priv with all the soft interface information * @orig_node: the orig_node for which the CRCs have to be updated */ static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { struct batadv_orig_node_vlan *vlan; uint32_t crc; /* recompute the global CRC for each VLAN */ rcu_read_lock(); list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { /* if orig_node is a backbone node for this VLAN, don't compute * the CRC as we ignore all the global entries over it */ |
cfd4f7570
|
2309 2310 |
if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vlan->vid)) |
7ea7b4a14
|
2311 2312 2313 2314 2315 2316 |
continue; crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid); vlan->tt.crc = crc; } rcu_read_unlock(); |
a73105b8d
|
2317 |
} |
ced72933a
|
2318 2319 2320 2321 2322 |
/** * batadv_send_tt_request - send a TT Request message to a given node * @bat_priv: the bat priv with all the soft interface information * @dst_orig_node: the destination of the message * @ttvn: the version number that the source of the message is looking for |
7ea7b4a14
|
2323 2324 |
* @tt_vlan: pointer to the first tvlv VLAN object to request * @num_vlan: number of tvlv VLAN entries |
ced72933a
|
2325 2326 2327 |
* @full_table: ask for the entire translation table if true, while only for the * last TT diff otherwise */ |
56303d34a
|
2328 2329 |
static int batadv_send_tt_request(struct batadv_priv *bat_priv, struct batadv_orig_node *dst_orig_node, |
7ea7b4a14
|
2330 2331 2332 |
uint8_t ttvn, struct batadv_tvlv_tt_vlan_data *tt_vlan, uint16_t num_vlan, bool full_table) |
a73105b8d
|
2333 |
{ |
335fbe0f5
|
2334 |
struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; |
56303d34a
|
2335 |
struct batadv_tt_req_node *tt_req_node = NULL; |
7ea7b4a14
|
2336 2337 |
struct batadv_tvlv_tt_vlan_data *tt_vlan_req; struct batadv_hard_iface *primary_if; |
335fbe0f5
|
2338 |
bool ret = false; |
7ea7b4a14
|
2339 |
int i, size; |
a73105b8d
|
2340 |
|
e5d89254b
|
2341 |
primary_if = batadv_primary_if_get_selected(bat_priv); |
a73105b8d
|
2342 2343 2344 2345 |
if (!primary_if) goto out; /* The new tt_req will be issued only if I'm not waiting for a |
9cfc7bd60
|
2346 2347 |
* reply from the same orig_node yet */ |
a513088d0
|
2348 |
tt_req_node = batadv_new_tt_req_node(bat_priv, dst_orig_node); |
a73105b8d
|
2349 2350 |
if (!tt_req_node) goto out; |
7ea7b4a14
|
2351 2352 |
size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan; tvlv_tt_data = kzalloc(size, GFP_ATOMIC); |
335fbe0f5
|
2353 |
if (!tvlv_tt_data) |
a73105b8d
|
2354 |
goto out; |
335fbe0f5
|
2355 2356 |
tvlv_tt_data->flags = BATADV_TT_REQUEST; tvlv_tt_data->ttvn = ttvn; |
7ea7b4a14
|
2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 |
tvlv_tt_data->num_vlan = htons(num_vlan); /* send all the CRCs within the request. This is needed by intermediate * nodes to ensure they have the correct table before replying */ tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1); for (i = 0; i < num_vlan; i++) { tt_vlan_req->vid = tt_vlan->vid; tt_vlan_req->crc = tt_vlan->crc; tt_vlan_req++; tt_vlan++; } |
a73105b8d
|
2370 2371 |
if (full_table) |
335fbe0f5
|
2372 |
tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; |
a73105b8d
|
2373 |
|
bb351ba0b
|
2374 2375 |
batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c] ", |
335fbe0f5
|
2376 |
dst_orig_node->orig, full_table ? 'F' : '.'); |
a73105b8d
|
2377 |
|
d69909d2f
|
2378 |
batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); |
335fbe0f5
|
2379 2380 |
batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, dst_orig_node->orig, BATADV_TVLV_TT, 1, |
7ea7b4a14
|
2381 |
tvlv_tt_data, size); |
335fbe0f5
|
2382 |
ret = true; |
a73105b8d
|
2383 2384 |
out: |
a73105b8d
|
2385 |
if (primary_if) |
e5d89254b
|
2386 |
batadv_hardif_free_ref(primary_if); |
a73105b8d
|
2387 |
if (ret && tt_req_node) { |
807736f6e
|
2388 |
spin_lock_bh(&bat_priv->tt.req_list_lock); |
a73105b8d
|
2389 |
list_del(&tt_req_node->list); |
807736f6e
|
2390 |
spin_unlock_bh(&bat_priv->tt.req_list_lock); |
a73105b8d
|
2391 2392 |
kfree(tt_req_node); } |
335fbe0f5
|
2393 |
kfree(tvlv_tt_data); |
a73105b8d
|
2394 2395 |
return ret; } |
335fbe0f5
|
2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 |
/** * batadv_send_other_tt_response - send reply to tt request concerning another * node's translation table * @bat_priv: the bat priv with all the soft interface information * @tt_data: tt data containing the tt request information * @req_src: mac address of tt request sender * @req_dst: mac address of tt request recipient * * Returns true if tt request reply was sent, false otherwise. */ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data *tt_data, uint8_t *req_src, uint8_t *req_dst) |
a73105b8d
|
2409 |
{ |
170173bf3
|
2410 |
struct batadv_orig_node *req_dst_orig_node; |
56303d34a
|
2411 |
struct batadv_orig_node *res_dst_orig_node = NULL; |
7ea7b4a14
|
2412 |
struct batadv_tvlv_tt_change *tt_change; |
335fbe0f5
|
2413 |
struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; |
7ea7b4a14
|
2414 |
struct batadv_tvlv_tt_vlan_data *tt_vlan; |
335fbe0f5
|
2415 |
bool ret = false, full_table; |
7ea7b4a14
|
2416 2417 2418 |
uint8_t orig_ttvn, req_ttvn; uint16_t tvlv_len; int32_t tt_len; |
a73105b8d
|
2419 |
|
39c75a51e
|
2420 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
1eda58bfc
|
2421 2422 |
"Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c] ", |
335fbe0f5
|
2423 2424 |
req_src, tt_data->ttvn, req_dst, (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); |
a73105b8d
|
2425 2426 |
/* Let's get the orig node of the REAL destination */ |
335fbe0f5
|
2427 |
req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst); |
a73105b8d
|
2428 2429 |
if (!req_dst_orig_node) goto out; |
335fbe0f5
|
2430 |
res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src); |
a73105b8d
|
2431 2432 |
if (!res_dst_orig_node) goto out; |
a73105b8d
|
2433 |
orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); |
335fbe0f5
|
2434 |
req_ttvn = tt_data->ttvn; |
a73105b8d
|
2435 |
|
7ea7b4a14
|
2436 |
tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); |
335fbe0f5
|
2437 |
/* this node doesn't have the requested data */ |
a73105b8d
|
2438 |
if (orig_ttvn != req_ttvn || |
7ea7b4a14
|
2439 2440 |
!batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan, ntohs(tt_data->num_vlan))) |
a73105b8d
|
2441 |
goto out; |
015758d00
|
2442 |
/* If the full table has been explicitly requested */ |
335fbe0f5
|
2443 |
if (tt_data->flags & BATADV_TT_FULL_TABLE || |
a73105b8d
|
2444 2445 2446 2447 |
!req_dst_orig_node->tt_buff) full_table = true; else full_table = false; |
335fbe0f5
|
2448 2449 |
/* TT fragmentation hasn't been implemented yet, so send as many * TT entries fit a single packet as possible only |
9cfc7bd60
|
2450 |
*/ |
a73105b8d
|
2451 2452 2453 |
if (!full_table) { spin_lock_bh(&req_dst_orig_node->tt_buff_lock); tt_len = req_dst_orig_node->tt_buff_len; |
a73105b8d
|
2454 |
|
7ea7b4a14
|
2455 2456 2457 2458 2459 |
tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, &tvlv_tt_data, &tt_change, &tt_len); if (!tt_len) |
a73105b8d
|
2460 |
goto unlock; |
a73105b8d
|
2461 |
/* Copy the last orig_node's OGM buffer */ |
7ea7b4a14
|
2462 |
memcpy(tt_change, req_dst_orig_node->tt_buff, |
a73105b8d
|
2463 |
req_dst_orig_node->tt_buff_len); |
a73105b8d
|
2464 2465 |
spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); } else { |
7ea7b4a14
|
2466 2467 2468 2469 2470 2471 2472 2473 2474 |
/* allocate the tvlv, put the tt_data and all the tt_vlan_data * in the initial part */ tt_len = -1; tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, &tvlv_tt_data, &tt_change, &tt_len); if (!tt_len) |
a73105b8d
|
2475 |
goto out; |
7ea7b4a14
|
2476 2477 2478 2479 2480 2481 |
/* fill the rest of the tvlv with the real TT entries */ batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash, tt_change, tt_len, batadv_tt_global_valid, req_dst_orig_node); |
a73105b8d
|
2482 |
} |
a19d3d85e
|
2483 2484 2485 2486 2487 2488 2489 2490 2491 |
/* Don't send the response, if larger than fragmented packet. */ tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len; if (tt_len > atomic_read(&bat_priv->packet_size_max)) { net_ratelimited_function(batadv_info, bat_priv->soft_iface, "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size. ", res_dst_orig_node->orig); goto out; } |
335fbe0f5
|
2492 2493 |
tvlv_tt_data->flags = BATADV_TT_RESPONSE; tvlv_tt_data->ttvn = req_ttvn; |
a73105b8d
|
2494 2495 |
if (full_table) |
335fbe0f5
|
2496 |
tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; |
a73105b8d
|
2497 |
|
39c75a51e
|
2498 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
335fbe0f5
|
2499 2500 2501 2502 |
"Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u) ", res_dst_orig_node->orig, req_dst_orig_node->orig, full_table ? 'F' : '.', req_ttvn); |
a73105b8d
|
2503 |
|
d69909d2f
|
2504 |
batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); |
f8214865a
|
2505 |
|
335fbe0f5
|
2506 |
batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig, |
7ea7b4a14
|
2507 2508 |
req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, tvlv_len); |
e91ecfc64
|
2509 |
|
335fbe0f5
|
2510 |
ret = true; |
a73105b8d
|
2511 2512 2513 2514 2515 2516 2517 |
goto out; unlock: spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); out: if (res_dst_orig_node) |
7d211efc5
|
2518 |
batadv_orig_node_free_ref(res_dst_orig_node); |
a73105b8d
|
2519 |
if (req_dst_orig_node) |
7d211efc5
|
2520 |
batadv_orig_node_free_ref(req_dst_orig_node); |
335fbe0f5
|
2521 |
kfree(tvlv_tt_data); |
a73105b8d
|
2522 |
return ret; |
a73105b8d
|
2523 |
} |
964126901
|
2524 |
|
335fbe0f5
|
2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 |
/** * batadv_send_my_tt_response - send reply to tt request concerning this node's * translation table * @bat_priv: the bat priv with all the soft interface information * @tt_data: tt data containing the tt request information * @req_src: mac address of tt request sender * * Returns true if tt request reply was sent, false otherwise. */ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data *tt_data, uint8_t *req_src) |
a73105b8d
|
2537 |
{ |
335fbe0f5
|
2538 |
struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; |
56303d34a
|
2539 |
struct batadv_hard_iface *primary_if = NULL; |
7ea7b4a14
|
2540 2541 |
struct batadv_tvlv_tt_change *tt_change; struct batadv_orig_node *orig_node; |
335fbe0f5
|
2542 |
uint8_t my_ttvn, req_ttvn; |
7ea7b4a14
|
2543 |
uint16_t tvlv_len; |
a73105b8d
|
2544 |
bool full_table; |
7ea7b4a14
|
2545 |
int32_t tt_len; |
a73105b8d
|
2546 |
|
39c75a51e
|
2547 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
1eda58bfc
|
2548 2549 |
"Received TT_REQUEST from %pM for ttvn: %u (me) [%c] ", |
335fbe0f5
|
2550 2551 |
req_src, tt_data->ttvn, (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); |
a73105b8d
|
2552 |
|
a70a9aa99
|
2553 |
spin_lock_bh(&bat_priv->tt.commit_lock); |
a73105b8d
|
2554 |
|
807736f6e
|
2555 |
my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); |
335fbe0f5
|
2556 |
req_ttvn = tt_data->ttvn; |
a73105b8d
|
2557 |
|
335fbe0f5
|
2558 |
orig_node = batadv_orig_hash_find(bat_priv, req_src); |
a73105b8d
|
2559 2560 |
if (!orig_node) goto out; |
e5d89254b
|
2561 |
primary_if = batadv_primary_if_get_selected(bat_priv); |
a73105b8d
|
2562 2563 2564 2565 |
if (!primary_if) goto out; /* If the full table has been explicitly requested or the gap |
9cfc7bd60
|
2566 2567 |
* is too big send the whole local translation table */ |
335fbe0f5
|
2568 |
if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn || |
807736f6e
|
2569 |
!bat_priv->tt.last_changeset) |
a73105b8d
|
2570 2571 2572 |
full_table = true; else full_table = false; |
335fbe0f5
|
2573 2574 |
/* TT fragmentation hasn't been implemented yet, so send as many * TT entries fit a single packet as possible only |
9cfc7bd60
|
2575 |
*/ |
a73105b8d
|
2576 |
if (!full_table) { |
807736f6e
|
2577 |
spin_lock_bh(&bat_priv->tt.last_changeset_lock); |
a73105b8d
|
2578 |
|
7ea7b4a14
|
2579 2580 2581 2582 2583 2584 |
tt_len = bat_priv->tt.last_changeset_len; tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tvlv_tt_data, &tt_change, &tt_len); if (!tt_len) |
a73105b8d
|
2585 |
goto unlock; |
335fbe0f5
|
2586 |
/* Copy the last orig_node's OGM buffer */ |
7ea7b4a14
|
2587 |
memcpy(tt_change, bat_priv->tt.last_changeset, |
807736f6e
|
2588 2589 |
bat_priv->tt.last_changeset_len); spin_unlock_bh(&bat_priv->tt.last_changeset_lock); |
a73105b8d
|
2590 |
} else { |
335fbe0f5
|
2591 |
req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); |
7ea7b4a14
|
2592 2593 2594 2595 2596 2597 2598 2599 2600 |
/* allocate the tvlv, put the tt_data and all the tt_vlan_data * in the initial part */ tt_len = -1; tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tvlv_tt_data, &tt_change, &tt_len); if (!tt_len) |
a73105b8d
|
2601 |
goto out; |
7ea7b4a14
|
2602 2603 2604 2605 2606 |
/* fill the rest of the tvlv with the real TT entries */ batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash, tt_change, tt_len, batadv_tt_local_valid, NULL); |
a73105b8d
|
2607 |
} |
335fbe0f5
|
2608 2609 |
tvlv_tt_data->flags = BATADV_TT_RESPONSE; tvlv_tt_data->ttvn = req_ttvn; |
a73105b8d
|
2610 2611 |
if (full_table) |
335fbe0f5
|
2612 |
tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; |
a73105b8d
|
2613 |
|
39c75a51e
|
2614 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
335fbe0f5
|
2615 2616 2617 |
"Sending TT_RESPONSE to %pM [%c] (ttvn: %u) ", orig_node->orig, full_table ? 'F' : '.', req_ttvn); |
a73105b8d
|
2618 |
|
d69909d2f
|
2619 |
batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); |
f8214865a
|
2620 |
|
335fbe0f5
|
2621 |
batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, |
7ea7b4a14
|
2622 2623 |
req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, tvlv_len); |
335fbe0f5
|
2624 |
|
a73105b8d
|
2625 2626 2627 |
goto out; unlock: |
807736f6e
|
2628 |
spin_unlock_bh(&bat_priv->tt.last_changeset_lock); |
a73105b8d
|
2629 |
out: |
a70a9aa99
|
2630 |
spin_unlock_bh(&bat_priv->tt.commit_lock); |
a73105b8d
|
2631 |
if (orig_node) |
7d211efc5
|
2632 |
batadv_orig_node_free_ref(orig_node); |
a73105b8d
|
2633 |
if (primary_if) |
e5d89254b
|
2634 |
batadv_hardif_free_ref(primary_if); |
335fbe0f5
|
2635 2636 |
kfree(tvlv_tt_data); /* The packet was for this host, so it doesn't need to be re-routed */ |
a73105b8d
|
2637 2638 |
return true; } |
335fbe0f5
|
2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 |
/** * batadv_send_tt_response - send reply to tt request * @bat_priv: the bat priv with all the soft interface information * @tt_data: tt data containing the tt request information * @req_src: mac address of tt request sender * @req_dst: mac address of tt request recipient * * Returns true if tt request reply was sent, false otherwise. */ static bool batadv_send_tt_response(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data *tt_data, uint8_t *req_src, uint8_t *req_dst) |
a73105b8d
|
2651 |
{ |
cfd4f7570
|
2652 |
if (batadv_is_my_mac(bat_priv, req_dst)) |
335fbe0f5
|
2653 |
return batadv_send_my_tt_response(bat_priv, tt_data, req_src); |
cfd4f7570
|
2654 |
else |
335fbe0f5
|
2655 2656 |
return batadv_send_other_tt_response(bat_priv, tt_data, req_src, req_dst); |
a73105b8d
|
2657 |
} |
56303d34a
|
2658 2659 |
static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, |
335fbe0f5
|
2660 |
struct batadv_tvlv_tt_change *tt_change, |
a513088d0
|
2661 |
uint16_t tt_num_changes, uint8_t ttvn) |
a73105b8d
|
2662 2663 |
{ int i; |
a513088d0
|
2664 |
int roams; |
a73105b8d
|
2665 2666 |
for (i = 0; i < tt_num_changes; i++) { |
acd34afa8
|
2667 2668 |
if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) { roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; |
a513088d0
|
2669 2670 |
batadv_tt_global_del(bat_priv, orig_node, (tt_change + i)->addr, |
c018ad3de
|
2671 |
ntohs((tt_change + i)->vid), |
d4f446925
|
2672 2673 |
"tt removed by changes", roams); |
08c36d3e8
|
2674 |
} else { |
08c36d3e8
|
2675 |
if (!batadv_tt_global_add(bat_priv, orig_node, |
d4f446925
|
2676 |
(tt_change + i)->addr, |
c018ad3de
|
2677 |
ntohs((tt_change + i)->vid), |
d4f446925
|
2678 |
(tt_change + i)->flags, ttvn)) |
a73105b8d
|
2679 2680 2681 2682 2683 2684 2685 |
/* In case of problem while storing a * global_entry, we stop the updating * procedure without committing the * ttvn change. This will avoid to send * corrupted data on tt_request */ return; |
08c36d3e8
|
2686 |
} |
a73105b8d
|
2687 |
} |
e17931d1a
|
2688 |
orig_node->capa_initialized |= BATADV_ORIG_CAPA_HAS_TT; |
a73105b8d
|
2689 |
} |
56303d34a
|
2690 |
static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, |
7ea7b4a14
|
2691 2692 2693 |
struct batadv_tvlv_tt_change *tt_change, uint8_t ttvn, uint8_t *resp_src, uint16_t num_entries) |
a73105b8d
|
2694 |
{ |
170173bf3
|
2695 |
struct batadv_orig_node *orig_node; |
a73105b8d
|
2696 |
|
335fbe0f5
|
2697 |
orig_node = batadv_orig_hash_find(bat_priv, resp_src); |
a73105b8d
|
2698 2699 2700 2701 |
if (!orig_node) goto out; /* Purge the old table first.. */ |
95fb130d6
|
2702 2703 |
batadv_tt_global_del_orig(bat_priv, orig_node, -1, "Received full table"); |
a73105b8d
|
2704 |
|
7ea7b4a14
|
2705 2706 |
_batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries, ttvn); |
a73105b8d
|
2707 2708 2709 2710 2711 2712 |
spin_lock_bh(&orig_node->tt_buff_lock); kfree(orig_node->tt_buff); orig_node->tt_buff_len = 0; orig_node->tt_buff = NULL; spin_unlock_bh(&orig_node->tt_buff_lock); |
7ea7b4a14
|
2713 |
atomic_set(&orig_node->last_ttvn, ttvn); |
a73105b8d
|
2714 2715 2716 |
out: if (orig_node) |
7d211efc5
|
2717 |
batadv_orig_node_free_ref(orig_node); |
a73105b8d
|
2718 |
} |
56303d34a
|
2719 2720 |
static void batadv_tt_update_changes(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, |
a513088d0
|
2721 |
uint16_t tt_num_changes, uint8_t ttvn, |
335fbe0f5
|
2722 |
struct batadv_tvlv_tt_change *tt_change) |
a73105b8d
|
2723 |
{ |
a513088d0
|
2724 2725 |
_batadv_tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes, ttvn); |
a73105b8d
|
2726 |
|
e8cf234a4
|
2727 2728 |
batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change, batadv_tt_len(tt_num_changes)); |
a73105b8d
|
2729 2730 |
atomic_set(&orig_node->last_ttvn, ttvn); } |
c018ad3de
|
2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 |
/** * batadv_is_my_client - check if a client is served by the local node * @bat_priv: the bat priv with all the soft interface information * @addr: the mac adress of the client to check * @vid: VLAN identifier * * Returns true if the client is served by this node, false otherwise. */ bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr, unsigned short vid) |
a73105b8d
|
2741 |
{ |
170173bf3
|
2742 |
struct batadv_tt_local_entry *tt_local_entry; |
7683fdc1e
|
2743 |
bool ret = false; |
a73105b8d
|
2744 |
|
c018ad3de
|
2745 |
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); |
7683fdc1e
|
2746 2747 |
if (!tt_local_entry) goto out; |
058d0e269
|
2748 |
/* Check if the client has been logically deleted (but is kept for |
9cfc7bd60
|
2749 2750 |
* consistency purpose) */ |
7c1fd91da
|
2751 2752 |
if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) || (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM)) |
058d0e269
|
2753 |
goto out; |
7683fdc1e
|
2754 2755 |
ret = true; out: |
a73105b8d
|
2756 |
if (tt_local_entry) |
a513088d0
|
2757 |
batadv_tt_local_entry_free_ref(tt_local_entry); |
7683fdc1e
|
2758 |
return ret; |
a73105b8d
|
2759 |
} |
335fbe0f5
|
2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 |
/** * batadv_handle_tt_response - process incoming tt reply * @bat_priv: the bat priv with all the soft interface information * @tt_data: tt data containing the tt request information * @resp_src: mac address of tt reply sender * @num_entries: number of tt change entries appended to the tt data */ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data *tt_data, uint8_t *resp_src, uint16_t num_entries) |
a73105b8d
|
2770 |
{ |
56303d34a
|
2771 2772 |
struct batadv_tt_req_node *node, *safe; struct batadv_orig_node *orig_node = NULL; |
335fbe0f5
|
2773 |
struct batadv_tvlv_tt_change *tt_change; |
7ea7b4a14
|
2774 2775 |
uint8_t *tvlv_ptr = (uint8_t *)tt_data; uint16_t change_offset; |
a73105b8d
|
2776 |
|
39c75a51e
|
2777 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
1eda58bfc
|
2778 2779 |
"Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c] ", |
335fbe0f5
|
2780 2781 |
resp_src, tt_data->ttvn, num_entries, (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); |
a73105b8d
|
2782 |
|
335fbe0f5
|
2783 |
orig_node = batadv_orig_hash_find(bat_priv, resp_src); |
a73105b8d
|
2784 2785 |
if (!orig_node) goto out; |
a70a9aa99
|
2786 |
spin_lock_bh(&orig_node->tt_lock); |
7ea7b4a14
|
2787 2788 2789 2790 2791 2792 |
change_offset = sizeof(struct batadv_tvlv_tt_vlan_data); change_offset *= ntohs(tt_data->num_vlan); change_offset += sizeof(*tt_data); tvlv_ptr += change_offset; tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr; |
335fbe0f5
|
2793 |
if (tt_data->flags & BATADV_TT_FULL_TABLE) { |
7ea7b4a14
|
2794 2795 |
batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn, resp_src, num_entries); |
964126901
|
2796 |
} else { |
335fbe0f5
|
2797 2798 |
batadv_tt_update_changes(bat_priv, orig_node, num_entries, tt_data->ttvn, tt_change); |
964126901
|
2799 |
} |
a73105b8d
|
2800 |
|
a70a9aa99
|
2801 |
/* Recalculate the CRC for this orig_node and store it */ |
7ea7b4a14
|
2802 |
batadv_tt_global_update_crc(bat_priv, orig_node); |
a70a9aa99
|
2803 2804 |
spin_unlock_bh(&orig_node->tt_lock); |
a73105b8d
|
2805 |
/* Delete the tt_req_node from pending tt_requests list */ |
807736f6e
|
2806 2807 |
spin_lock_bh(&bat_priv->tt.req_list_lock); list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { |
335fbe0f5
|
2808 |
if (!batadv_compare_eth(node->addr, resp_src)) |
a73105b8d
|
2809 2810 2811 2812 |
continue; list_del(&node->list); kfree(node); } |
7ea7b4a14
|
2813 |
|
807736f6e
|
2814 |
spin_unlock_bh(&bat_priv->tt.req_list_lock); |
a73105b8d
|
2815 2816 |
out: if (orig_node) |
7d211efc5
|
2817 |
batadv_orig_node_free_ref(orig_node); |
a73105b8d
|
2818 |
} |
56303d34a
|
2819 |
static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) |
a73105b8d
|
2820 |
{ |
56303d34a
|
2821 |
struct batadv_tt_roam_node *node, *safe; |
a73105b8d
|
2822 |
|
807736f6e
|
2823 |
spin_lock_bh(&bat_priv->tt.roam_list_lock); |
a73105b8d
|
2824 |
|
807736f6e
|
2825 |
list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { |
cc47f66e6
|
2826 2827 2828 |
list_del(&node->list); kfree(node); } |
807736f6e
|
2829 |
spin_unlock_bh(&bat_priv->tt.roam_list_lock); |
cc47f66e6
|
2830 |
} |
56303d34a
|
2831 |
static void batadv_tt_roam_purge(struct batadv_priv *bat_priv) |
cc47f66e6
|
2832 |
{ |
56303d34a
|
2833 |
struct batadv_tt_roam_node *node, *safe; |
cc47f66e6
|
2834 |
|
807736f6e
|
2835 2836 |
spin_lock_bh(&bat_priv->tt.roam_list_lock); list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) { |
42d0b044b
|
2837 2838 |
if (!batadv_has_timed_out(node->first_time, BATADV_ROAMING_MAX_TIME)) |
cc47f66e6
|
2839 2840 2841 2842 2843 |
continue; list_del(&node->list); kfree(node); } |
807736f6e
|
2844 |
spin_unlock_bh(&bat_priv->tt.roam_list_lock); |
cc47f66e6
|
2845 2846 2847 2848 2849 2850 |
} /* This function checks whether the client already reached the * maximum number of possible roaming phases. In this case the ROAMING_ADV * will not be sent. * |
9cfc7bd60
|
2851 2852 |
* returns true if the ROAMING_ADV can be sent, false otherwise */ |
56303d34a
|
2853 |
static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, |
a513088d0
|
2854 |
uint8_t *client) |
cc47f66e6
|
2855 |
{ |
56303d34a
|
2856 |
struct batadv_tt_roam_node *tt_roam_node; |
cc47f66e6
|
2857 |
bool ret = false; |
807736f6e
|
2858 |
spin_lock_bh(&bat_priv->tt.roam_list_lock); |
cc47f66e6
|
2859 |
/* The new tt_req will be issued only if I'm not waiting for a |
9cfc7bd60
|
2860 2861 |
* reply from the same orig_node yet */ |
807736f6e
|
2862 |
list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) { |
1eda58bfc
|
2863 |
if (!batadv_compare_eth(tt_roam_node->addr, client)) |
cc47f66e6
|
2864 |
continue; |
1eda58bfc
|
2865 |
if (batadv_has_timed_out(tt_roam_node->first_time, |
42d0b044b
|
2866 |
BATADV_ROAMING_MAX_TIME)) |
cc47f66e6
|
2867 |
continue; |
3e34819e0
|
2868 |
if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter)) |
cc47f66e6
|
2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 |
/* Sorry, you roamed too many times! */ goto unlock; ret = true; break; } if (!ret) { tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC); if (!tt_roam_node) goto unlock; tt_roam_node->first_time = jiffies; |
42d0b044b
|
2881 2882 |
atomic_set(&tt_roam_node->counter, BATADV_ROAMING_MAX_COUNT - 1); |
8fdd01530
|
2883 |
ether_addr_copy(tt_roam_node->addr, client); |
cc47f66e6
|
2884 |
|
807736f6e
|
2885 |
list_add(&tt_roam_node->list, &bat_priv->tt.roam_list); |
cc47f66e6
|
2886 2887 2888 2889 |
ret = true; } unlock: |
807736f6e
|
2890 |
spin_unlock_bh(&bat_priv->tt.roam_list_lock); |
cc47f66e6
|
2891 2892 |
return ret; } |
c018ad3de
|
2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 |
/** * batadv_send_roam_adv - send a roaming advertisement message * @bat_priv: the bat priv with all the soft interface information * @client: mac address of the roaming client * @vid: VLAN identifier * @orig_node: message destination * * Send a ROAMING_ADV message to the node which was previously serving this * client. This is done to inform the node that from now on all traffic destined * for this particular roamed client has to be forwarded to the sender of the * roaming message. */ |
56303d34a
|
2905 |
static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, |
c018ad3de
|
2906 |
unsigned short vid, |
56303d34a
|
2907 |
struct batadv_orig_node *orig_node) |
cc47f66e6
|
2908 |
{ |
56303d34a
|
2909 |
struct batadv_hard_iface *primary_if; |
122edaa05
|
2910 2911 2912 2913 2914 |
struct batadv_tvlv_roam_adv tvlv_roam; primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if) goto out; |
cc47f66e6
|
2915 2916 |
/* before going on we have to check whether the client has |
9cfc7bd60
|
2917 2918 |
* already roamed to us too many times */ |
a513088d0
|
2919 |
if (!batadv_tt_check_roam_count(bat_priv, client)) |
cc47f66e6
|
2920 |
goto out; |
39c75a51e
|
2921 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
160527890
|
2922 2923 2924 |
"Sending ROAMING_ADV to %pM (client %pM, vid: %d) ", orig_node->orig, client, BATADV_PRINT_VID(vid)); |
cc47f66e6
|
2925 |
|
d69909d2f
|
2926 |
batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX); |
f8214865a
|
2927 |
|
122edaa05
|
2928 |
memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client)); |
c018ad3de
|
2929 |
tvlv_roam.vid = htons(vid); |
122edaa05
|
2930 2931 2932 2933 |
batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, orig_node->orig, BATADV_TVLV_ROAM, 1, &tvlv_roam, sizeof(tvlv_roam)); |
cc47f66e6
|
2934 2935 |
out: |
122edaa05
|
2936 2937 |
if (primary_if) batadv_hardif_free_ref(primary_if); |
a73105b8d
|
2938 |
} |
a513088d0
|
2939 |
static void batadv_tt_purge(struct work_struct *work) |
a73105b8d
|
2940 |
{ |
56303d34a
|
2941 |
struct delayed_work *delayed_work; |
807736f6e
|
2942 |
struct batadv_priv_tt *priv_tt; |
56303d34a
|
2943 2944 2945 |
struct batadv_priv *bat_priv; delayed_work = container_of(work, struct delayed_work, work); |
807736f6e
|
2946 2947 |
priv_tt = container_of(delayed_work, struct batadv_priv_tt, work); bat_priv = container_of(priv_tt, struct batadv_priv, tt); |
a73105b8d
|
2948 |
|
a19d3d85e
|
2949 |
batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT); |
30cfd02b6
|
2950 |
batadv_tt_global_purge(bat_priv); |
a513088d0
|
2951 2952 |
batadv_tt_req_purge(bat_priv); batadv_tt_roam_purge(bat_priv); |
a73105b8d
|
2953 |
|
724144420
|
2954 2955 |
queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); |
a73105b8d
|
2956 |
} |
cc47f66e6
|
2957 |
|
56303d34a
|
2958 |
void batadv_tt_free(struct batadv_priv *bat_priv) |
cc47f66e6
|
2959 |
{ |
e1bf0c140
|
2960 2961 |
batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1); batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1); |
807736f6e
|
2962 |
cancel_delayed_work_sync(&bat_priv->tt.work); |
cc47f66e6
|
2963 |
|
a513088d0
|
2964 2965 2966 2967 2968 |
batadv_tt_local_table_free(bat_priv); batadv_tt_global_table_free(bat_priv); batadv_tt_req_list_free(bat_priv); batadv_tt_changes_list_free(bat_priv); batadv_tt_roam_list_free(bat_priv); |
cc47f66e6
|
2969 |
|
807736f6e
|
2970 |
kfree(bat_priv->tt.last_changeset); |
cc47f66e6
|
2971 |
} |
058d0e269
|
2972 |
|
7ea7b4a14
|
2973 2974 2975 2976 2977 2978 2979 |
/** * batadv_tt_local_set_flags - set or unset the specified flags on the local * table and possibly count them in the TT size * @bat_priv: the bat priv with all the soft interface information * @flags: the flag to switch * @enable: whether to set or unset the flag * @count: whether to increase the TT size by the number of changed entries |
9cfc7bd60
|
2980 |
*/ |
7ea7b4a14
|
2981 2982 |
static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, uint16_t flags, bool enable, bool count) |
058d0e269
|
2983 |
{ |
7ea7b4a14
|
2984 2985 |
struct batadv_hashtable *hash = bat_priv->tt.local_hash; struct batadv_tt_common_entry *tt_common_entry; |
697f25314
|
2986 |
uint16_t changed_num = 0; |
058d0e269
|
2987 |
struct hlist_head *head; |
7ea7b4a14
|
2988 |
uint32_t i; |
058d0e269
|
2989 2990 |
if (!hash) |
7ea7b4a14
|
2991 |
return; |
058d0e269
|
2992 2993 2994 2995 2996 |
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; rcu_read_lock(); |
b67bfe0d4
|
2997 |
hlist_for_each_entry_rcu(tt_common_entry, |
058d0e269
|
2998 |
head, hash_entry) { |
697f25314
|
2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 |
if (enable) { if ((tt_common_entry->flags & flags) == flags) continue; tt_common_entry->flags |= flags; } else { if (!(tt_common_entry->flags & flags)) continue; tt_common_entry->flags &= ~flags; } changed_num++; |
7ea7b4a14
|
3009 3010 3011 3012 3013 3014 |
if (!count) continue; batadv_tt_local_size_inc(bat_priv, tt_common_entry->vid); |
058d0e269
|
3015 3016 3017 |
} rcu_read_unlock(); } |
058d0e269
|
3018 |
} |
acd34afa8
|
3019 |
/* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ |
56303d34a
|
3020 |
static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) |
058d0e269
|
3021 |
{ |
807736f6e
|
3022 |
struct batadv_hashtable *hash = bat_priv->tt.local_hash; |
56303d34a
|
3023 3024 |
struct batadv_tt_common_entry *tt_common; struct batadv_tt_local_entry *tt_local; |
b67bfe0d4
|
3025 |
struct hlist_node *node_tmp; |
058d0e269
|
3026 3027 |
struct hlist_head *head; spinlock_t *list_lock; /* protects write access to the hash lists */ |
c90681b85
|
3028 |
uint32_t i; |
058d0e269
|
3029 3030 3031 3032 3033 3034 3035 3036 3037 |
if (!hash) return; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; list_lock = &hash->list_locks[i]; spin_lock_bh(list_lock); |
b67bfe0d4
|
3038 |
hlist_for_each_entry_safe(tt_common, node_tmp, head, |
acd34afa8
|
3039 3040 |
hash_entry) { if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING)) |
058d0e269
|
3041 |
continue; |
39c75a51e
|
3042 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
160527890
|
3043 3044 3045 3046 |
"Deleting local tt entry (%pM, vid: %d): pending ", tt_common->addr, BATADV_PRINT_VID(tt_common->vid)); |
058d0e269
|
3047 |
|
7ea7b4a14
|
3048 |
batadv_tt_local_size_dec(bat_priv, tt_common->vid); |
b67bfe0d4
|
3049 |
hlist_del_rcu(&tt_common->hash_entry); |
56303d34a
|
3050 3051 3052 3053 |
tt_local = container_of(tt_common, struct batadv_tt_local_entry, common); batadv_tt_local_entry_free_ref(tt_local); |
058d0e269
|
3054 3055 3056 |
} spin_unlock_bh(list_lock); } |
058d0e269
|
3057 |
} |
e1bf0c140
|
3058 |
/** |
a19d3d85e
|
3059 3060 |
* batadv_tt_local_commit_changes_nolock - commit all pending local tt changes * which have been queued in the time since the last commit |
e1bf0c140
|
3061 |
* @bat_priv: the bat priv with all the soft interface information |
a19d3d85e
|
3062 3063 |
* * Caller must hold tt->commit_lock. |
e1bf0c140
|
3064 |
*/ |
a19d3d85e
|
3065 |
static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv) |
058d0e269
|
3066 |
{ |
c5caf4ef3
|
3067 3068 |
/* Update multicast addresses in local translation table */ batadv_mcast_mla_update(bat_priv); |
e1bf0c140
|
3069 3070 3071 |
if (atomic_read(&bat_priv->tt.local_changes) < 1) { if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) batadv_tt_tvlv_container_update(bat_priv); |
a19d3d85e
|
3072 |
return; |
e1bf0c140
|
3073 |
} |
be9aa4c1e
|
3074 |
|
7ea7b4a14
|
3075 |
batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true); |
be9aa4c1e
|
3076 |
|
a513088d0
|
3077 |
batadv_tt_local_purge_pending_clients(bat_priv); |
7ea7b4a14
|
3078 |
batadv_tt_local_update_crc(bat_priv); |
058d0e269
|
3079 3080 |
/* Increment the TTVN only once per OGM interval */ |
807736f6e
|
3081 |
atomic_inc(&bat_priv->tt.vn); |
39c75a51e
|
3082 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
1eda58bfc
|
3083 3084 |
"Local changes committed, updating to ttvn %u ", |
807736f6e
|
3085 |
(uint8_t)atomic_read(&bat_priv->tt.vn)); |
be9aa4c1e
|
3086 3087 |
/* reset the sending counter */ |
807736f6e
|
3088 |
atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); |
e1bf0c140
|
3089 |
batadv_tt_tvlv_container_update(bat_priv); |
a19d3d85e
|
3090 |
} |
a70a9aa99
|
3091 |
|
a19d3d85e
|
3092 3093 3094 3095 3096 3097 3098 3099 3100 |
/** * batadv_tt_local_commit_changes - commit all pending local tt changes which * have been queued in the time since the last commit * @bat_priv: the bat priv with all the soft interface information */ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) { spin_lock_bh(&bat_priv->tt.commit_lock); batadv_tt_local_commit_changes_nolock(bat_priv); |
a70a9aa99
|
3101 |
spin_unlock_bh(&bat_priv->tt.commit_lock); |
058d0e269
|
3102 |
} |
59b699cde
|
3103 |
|
56303d34a
|
3104 |
bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, |
b8cbd81d0
|
3105 |
uint8_t *dst, unsigned short vid) |
59b699cde
|
3106 |
{ |
56303d34a
|
3107 3108 |
struct batadv_tt_local_entry *tt_local_entry = NULL; struct batadv_tt_global_entry *tt_global_entry = NULL; |
b8cbd81d0
|
3109 |
struct batadv_softif_vlan *vlan; |
5870adc68
|
3110 |
bool ret = false; |
59b699cde
|
3111 |
|
b8cbd81d0
|
3112 3113 |
vlan = batadv_softif_vlan_get(bat_priv, vid); if (!vlan || !atomic_read(&vlan->ap_isolation)) |
5870adc68
|
3114 |
goto out; |
59b699cde
|
3115 |
|
b8cbd81d0
|
3116 |
tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid); |
59b699cde
|
3117 3118 |
if (!tt_local_entry) goto out; |
b8cbd81d0
|
3119 |
tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid); |
59b699cde
|
3120 3121 |
if (!tt_global_entry) goto out; |
1f129fefd
|
3122 |
if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry)) |
59b699cde
|
3123 |
goto out; |
5870adc68
|
3124 |
ret = true; |
59b699cde
|
3125 3126 |
out: |
b8cbd81d0
|
3127 3128 |
if (vlan) batadv_softif_vlan_free_ref(vlan); |
59b699cde
|
3129 |
if (tt_global_entry) |
a513088d0
|
3130 |
batadv_tt_global_entry_free_ref(tt_global_entry); |
59b699cde
|
3131 |
if (tt_local_entry) |
a513088d0
|
3132 |
batadv_tt_local_entry_free_ref(tt_local_entry); |
59b699cde
|
3133 3134 |
return ret; } |
a943cac14
|
3135 |
|
e1bf0c140
|
3136 3137 3138 3139 3140 |
/** * batadv_tt_update_orig - update global translation table with new tt * information received via ogms * @bat_priv: the bat priv with all the soft interface information * @orig: the orig_node of the ogm |
7ea7b4a14
|
3141 3142 3143 |
* @tt_vlan: pointer to the first tvlv VLAN entry * @tt_num_vlan: number of tvlv VLAN entries * @tt_change: pointer to the first entry in the TT buffer |
e1bf0c140
|
3144 3145 |
* @tt_num_changes: number of tt changes inside the tt buffer * @ttvn: translation table version number of this changeset |
ced72933a
|
3146 |
* @tt_crc: crc32 checksum of orig node's translation table |
e1bf0c140
|
3147 3148 3149 |
*/ static void batadv_tt_update_orig(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, |
7ea7b4a14
|
3150 3151 3152 |
const void *tt_buff, uint16_t tt_num_vlan, struct batadv_tvlv_tt_change *tt_change, uint16_t tt_num_changes, uint8_t ttvn) |
a943cac14
|
3153 3154 |
{ uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); |
7ea7b4a14
|
3155 |
struct batadv_tvlv_tt_vlan_data *tt_vlan; |
a943cac14
|
3156 |
bool full_table = true; |
e17931d1a
|
3157 |
bool has_tt_init; |
a943cac14
|
3158 |
|
7ea7b4a14
|
3159 |
tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff; |
e17931d1a
|
3160 |
has_tt_init = orig_node->capa_initialized & BATADV_ORIG_CAPA_HAS_TT; |
170715788
|
3161 |
/* orig table not initialised AND first diff is in the OGM OR the ttvn |
9cfc7bd60
|
3162 3163 |
* increased by one -> we can apply the attached changes */ |
e17931d1a
|
3164 |
if ((!has_tt_init && ttvn == 1) || ttvn - orig_ttvn == 1) { |
a943cac14
|
3165 |
/* the OGM could not contain the changes due to their size or |
42d0b044b
|
3166 3167 |
* because they have already been sent BATADV_TT_OGM_APPEND_MAX * times. |
9cfc7bd60
|
3168 3169 |
* In this case send a tt request */ |
a943cac14
|
3170 3171 3172 3173 |
if (!tt_num_changes) { full_table = false; goto request_table; } |
a70a9aa99
|
3174 |
spin_lock_bh(&orig_node->tt_lock); |
a513088d0
|
3175 |
batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, |
964126901
|
3176 |
ttvn, tt_change); |
a943cac14
|
3177 3178 3179 |
/* Even if we received the precomputed crc with the OGM, we * prefer to recompute it to spot any possible inconsistency |
9cfc7bd60
|
3180 3181 |
* in the global table */ |
7ea7b4a14
|
3182 |
batadv_tt_global_update_crc(bat_priv, orig_node); |
a943cac14
|
3183 |
|
a70a9aa99
|
3184 |
spin_unlock_bh(&orig_node->tt_lock); |
a943cac14
|
3185 3186 3187 3188 3189 3190 3191 |
/* The ttvn alone is not enough to guarantee consistency * because a single value could represent different states * (due to the wrap around). Thus a node has to check whether * the resulting table (after applying the changes) is still * consistent or not. E.g. a node could disconnect while its * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case * checking the CRC value is mandatory to detect the |
9cfc7bd60
|
3192 3193 |
* inconsistency */ |
7ea7b4a14
|
3194 3195 |
if (!batadv_tt_global_check_crc(orig_node, tt_vlan, tt_num_vlan)) |
a943cac14
|
3196 |
goto request_table; |
a943cac14
|
3197 3198 |
} else { /* if we missed more than one change or our tables are not |
9cfc7bd60
|
3199 3200 |
* in sync anymore -> request fresh tt data */ |
e17931d1a
|
3201 |
if (!has_tt_init || ttvn != orig_ttvn || |
7ea7b4a14
|
3202 3203 |
!batadv_tt_global_check_crc(orig_node, tt_vlan, tt_num_vlan)) { |
a943cac14
|
3204 |
request_table: |
39c75a51e
|
3205 |
batadv_dbg(BATADV_DBG_TT, bat_priv, |
7ea7b4a14
|
3206 3207 3208 3209 |
"TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u) ", orig_node->orig, ttvn, orig_ttvn, tt_num_changes); |
a513088d0
|
3210 |
batadv_send_tt_request(bat_priv, orig_node, ttvn, |
7ea7b4a14
|
3211 3212 |
tt_vlan, tt_num_vlan, full_table); |
a943cac14
|
3213 3214 3215 3216 |
return; } } } |
3275e7cc8
|
3217 |
|
c018ad3de
|
3218 3219 3220 3221 3222 3223 3224 3225 3226 |
/** * batadv_tt_global_client_is_roaming - check if a client is marked as roaming * @bat_priv: the bat priv with all the soft interface information * @addr: the mac address of the client to check * @vid: VLAN identifier * * Returns true if we know that the client has moved from its old originator * to another one. This entry is still kept for consistency purposes and will be * deleted later by a DEL or because of timeout |
3275e7cc8
|
3227 |
*/ |
56303d34a
|
3228 |
bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, |
c018ad3de
|
3229 |
uint8_t *addr, unsigned short vid) |
3275e7cc8
|
3230 |
{ |
56303d34a
|
3231 |
struct batadv_tt_global_entry *tt_global_entry; |
3275e7cc8
|
3232 |
bool ret = false; |
c018ad3de
|
3233 |
tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); |
3275e7cc8
|
3234 3235 |
if (!tt_global_entry) goto out; |
c1d07431b
|
3236 |
ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM; |
a513088d0
|
3237 |
batadv_tt_global_entry_free_ref(tt_global_entry); |
3275e7cc8
|
3238 3239 3240 |
out: return ret; } |
30cfd02b6
|
3241 |
|
7c1fd91da
|
3242 3243 3244 |
/** * batadv_tt_local_client_is_roaming - tells whether the client is roaming * @bat_priv: the bat priv with all the soft interface information |
c018ad3de
|
3245 3246 |
* @addr: the mac address of the local client to query * @vid: VLAN identifier |
7c1fd91da
|
3247 3248 3249 3250 3251 3252 |
* * Returns true if the local client is known to be roaming (it is not served by * this node anymore) or not. If yes, the client is still present in the table * to keep the latter consistent with the node TTVN */ bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, |
c018ad3de
|
3253 |
uint8_t *addr, unsigned short vid) |
7c1fd91da
|
3254 3255 3256 |
{ struct batadv_tt_local_entry *tt_local_entry; bool ret = false; |
c018ad3de
|
3257 |
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); |
7c1fd91da
|
3258 3259 3260 3261 3262 3263 3264 |
if (!tt_local_entry) goto out; ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM; batadv_tt_local_entry_free_ref(tt_local_entry); out: return ret; |
7c1fd91da
|
3265 |
} |
30cfd02b6
|
3266 3267 |
bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, |
c018ad3de
|
3268 |
const unsigned char *addr, |
160527890
|
3269 |
unsigned short vid) |
30cfd02b6
|
3270 3271 |
{ bool ret = false; |
160527890
|
3272 |
if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid, |
30cfd02b6
|
3273 3274 3275 3276 3277 |
BATADV_TT_CLIENT_TEMP, atomic_read(&orig_node->last_ttvn))) goto out; batadv_dbg(BATADV_DBG_TT, bat_priv, |
160527890
|
3278 3279 3280 |
"Added temporary global client (addr: %pM, vid: %d, orig: %pM) ", addr, BATADV_PRINT_VID(vid), orig_node->orig); |
30cfd02b6
|
3281 3282 3283 3284 |
ret = true; out: return ret; } |
e1bf0c140
|
3285 3286 |
/** |
a19d3d85e
|
3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 |
* batadv_tt_local_resize_to_mtu - resize the local translation table fit the * maximum packet size that can be transported through the mesh * @soft_iface: netdev struct of the mesh interface * * Remove entries older than 'timeout' and half timeout if more entries need * to be removed. */ void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface) { struct batadv_priv *bat_priv = netdev_priv(soft_iface); int packet_size_max = atomic_read(&bat_priv->packet_size_max); int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2; bool reduced = false; spin_lock_bh(&bat_priv->tt.commit_lock); while (true) { table_size = batadv_tt_local_table_transmit_size(bat_priv); if (packet_size_max >= table_size) break; batadv_tt_local_purge(bat_priv, timeout); batadv_tt_local_purge_pending_clients(bat_priv); timeout /= 2; reduced = true; net_ratelimited_function(batadv_info, soft_iface, "Forced to purge local tt entries to fit new maximum fragment MTU (%i) ", packet_size_max); } /* commit these changes immediately, to avoid synchronization problem * with the TTVN */ if (reduced) batadv_tt_local_commit_changes_nolock(bat_priv); spin_unlock_bh(&bat_priv->tt.commit_lock); } /** |
e1bf0c140
|
3329 3330 3331 3332 3333 3334 3335 3336 3337 |
* batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container * @bat_priv: the bat priv with all the soft interface information * @orig: the orig_node of the ogm * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) * @tvlv_value: tvlv buffer containing the gateway data * @tvlv_value_len: tvlv buffer length */ static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, |
7ea7b4a14
|
3338 |
uint8_t flags, void *tvlv_value, |
e1bf0c140
|
3339 3340 |
uint16_t tvlv_value_len) { |
7ea7b4a14
|
3341 3342 |
struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_tvlv_tt_change *tt_change; |
e1bf0c140
|
3343 |
struct batadv_tvlv_tt_data *tt_data; |
7ea7b4a14
|
3344 |
uint16_t num_entries, num_vlan; |
e1bf0c140
|
3345 3346 3347 3348 3349 3350 |
if (tvlv_value_len < sizeof(*tt_data)) return; tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; tvlv_value_len -= sizeof(*tt_data); |
7ea7b4a14
|
3351 3352 3353 3354 3355 3356 3357 3358 |
num_vlan = ntohs(tt_data->num_vlan); if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan) return; tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan); tvlv_value_len -= sizeof(*tt_vlan) * num_vlan; |
298e6e685
|
3359 |
num_entries = batadv_tt_entries(tvlv_value_len); |
e1bf0c140
|
3360 |
|
7ea7b4a14
|
3361 3362 |
batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change, num_entries, tt_data->ttvn); |
e1bf0c140
|
3363 3364 3365 |
} /** |
335fbe0f5
|
3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 |
* batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv * container * @bat_priv: the bat priv with all the soft interface information * @src: mac address of tt tvlv sender * @dst: mac address of tt tvlv recipient * @tvlv_value: tvlv buffer containing the tt data * @tvlv_value_len: tvlv buffer length * * Returns NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS * otherwise. */ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, uint8_t *src, uint8_t *dst, void *tvlv_value, uint16_t tvlv_value_len) { struct batadv_tvlv_tt_data *tt_data; |
7ea7b4a14
|
3383 |
uint16_t tt_vlan_len, tt_num_entries; |
335fbe0f5
|
3384 3385 3386 3387 3388 3389 3390 3391 |
char tt_flag; bool ret; if (tvlv_value_len < sizeof(*tt_data)) return NET_RX_SUCCESS; tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; tvlv_value_len -= sizeof(*tt_data); |
7ea7b4a14
|
3392 3393 3394 3395 3396 3397 3398 3399 |
tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data); tt_vlan_len *= ntohs(tt_data->num_vlan); if (tvlv_value_len < tt_vlan_len) return NET_RX_SUCCESS; tvlv_value_len -= tt_vlan_len; tt_num_entries = batadv_tt_entries(tvlv_value_len); |
335fbe0f5
|
3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 |
switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) { case BATADV_TT_REQUEST: batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX); /* If this node cannot provide a TT response the tt_request is * forwarded */ ret = batadv_send_tt_response(bat_priv, tt_data, src, dst); if (!ret) { if (tt_data->flags & BATADV_TT_FULL_TABLE) tt_flag = 'F'; else tt_flag = '.'; batadv_dbg(BATADV_DBG_TT, bat_priv, "Routing TT_REQUEST to %pM [%c] ", dst, tt_flag); /* tvlv API will re-route the packet */ return NET_RX_DROP; } break; case BATADV_TT_RESPONSE: batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX); if (batadv_is_my_mac(bat_priv, dst)) { batadv_handle_tt_response(bat_priv, tt_data, |
7ea7b4a14
|
3428 |
src, tt_num_entries); |
335fbe0f5
|
3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 |
return NET_RX_SUCCESS; } if (tt_data->flags & BATADV_TT_FULL_TABLE) tt_flag = 'F'; else tt_flag = '.'; batadv_dbg(BATADV_DBG_TT, bat_priv, "Routing TT_RESPONSE to %pM [%c] ", dst, tt_flag); /* tvlv API will re-route the packet */ return NET_RX_DROP; } return NET_RX_SUCCESS; } /** |
122edaa05
|
3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 |
* batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container * @bat_priv: the bat priv with all the soft interface information * @src: mac address of tt tvlv sender * @dst: mac address of tt tvlv recipient * @tvlv_value: tvlv buffer containing the tt data * @tvlv_value_len: tvlv buffer length * * Returns NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS * otherwise. */ static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, uint8_t *src, uint8_t *dst, void *tvlv_value, uint16_t tvlv_value_len) { struct batadv_tvlv_roam_adv *roaming_adv; struct batadv_orig_node *orig_node = NULL; /* If this node is not the intended recipient of the * roaming advertisement the packet is forwarded * (the tvlv API will re-route the packet). */ if (!batadv_is_my_mac(bat_priv, dst)) return NET_RX_DROP; |
122edaa05
|
3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 |
if (tvlv_value_len < sizeof(*roaming_adv)) goto out; orig_node = batadv_orig_hash_find(bat_priv, src); if (!orig_node) goto out; batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX); roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value; batadv_dbg(BATADV_DBG_TT, bat_priv, "Received ROAMING_ADV from %pM (client %pM) ", src, roaming_adv->client); batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, |
c018ad3de
|
3489 |
ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM, |
122edaa05
|
3490 3491 3492 3493 3494 3495 3496 3497 3498 |
atomic_read(&orig_node->last_ttvn) + 1); out: if (orig_node) batadv_orig_node_free_ref(orig_node); return NET_RX_SUCCESS; } /** |
e1bf0c140
|
3499 3500 3501 3502 3503 3504 3505 3506 |
* batadv_tt_init - initialise the translation table internals * @bat_priv: the bat priv with all the soft interface information * * Return 0 on success or negative error number in case of failure. */ int batadv_tt_init(struct batadv_priv *bat_priv) { int ret; |
0eb01568f
|
3507 3508 |
/* synchronized flags must be remote */ BUILD_BUG_ON(!(BATADV_TT_SYNC_MASK & BATADV_TT_REMOTE_MASK)); |
e1bf0c140
|
3509 3510 3511 3512 3513 3514 3515 3516 3517 |
ret = batadv_tt_local_init(bat_priv); if (ret < 0) return ret; ret = batadv_tt_global_init(bat_priv); if (ret < 0) return ret; batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1, |
335fbe0f5
|
3518 3519 |
batadv_tt_tvlv_unicast_handler_v1, BATADV_TVLV_TT, 1, BATADV_NO_FLAGS); |
e1bf0c140
|
3520 |
|
122edaa05
|
3521 3522 3523 |
batadv_tvlv_handler_register(bat_priv, NULL, batadv_roam_tvlv_unicast_handler_v1, BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS); |
e1bf0c140
|
3524 3525 3526 3527 3528 3529 |
INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); return 1; } |
42cb0bef0
|
3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 |
/** * batadv_tt_global_is_isolated - check if a client is marked as isolated * @bat_priv: the bat priv with all the soft interface information * @addr: the mac address of the client * @vid: the identifier of the VLAN where this client is connected * * Returns true if the client is marked with the TT_CLIENT_ISOLA flag, false * otherwise */ bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv, const uint8_t *addr, unsigned short vid) { struct batadv_tt_global_entry *tt; bool ret; tt = batadv_tt_global_hash_find(bat_priv, addr, vid); if (!tt) return false; ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA; batadv_tt_global_entry_free_ref(tt); return ret; } |