]>
Commit | Line | Data |
---|---|---|
c6c8fea2 | 1 | /* |
64afe353 | 2 | * Copyright (C) 2008-2011 B.A.T.M.A.N. contributors: |
c6c8fea2 SE |
3 | * |
4 | * Simon Wunderlich | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of version 2 of the GNU General Public | |
8 | * License as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
18 | * 02110-1301, USA | |
19 | * | |
20 | */ | |
21 | ||
22 | #include "main.h" | |
23 | #include "send.h" | |
24 | #include "translation-table.h" | |
25 | #include "vis.h" | |
26 | #include "soft-interface.h" | |
27 | #include "hard-interface.h" | |
28 | #include "hash.h" | |
29 | #include "originator.h" | |
30 | ||
31 | #define MAX_VIS_PACKET_SIZE 1000 | |
32 | ||
33 | /* Returns the smallest signed integer in two's complement with the sizeof x */ | |
34 | #define smallest_signed_int(x) (1u << (7u + 8u * (sizeof(x) - 1u))) | |
35 | ||
36 | /* Checks if a sequence number x is a predecessor/successor of y. | |
37 | * they handle overflows/underflows and can correctly check for a | |
38 | * predecessor/successor unless the variable sequence number has grown by | |
39 | * more then 2**(bitwidth(x)-1)-1. | |
40 | * This means that for a uint8_t with the maximum value 255, it would think: | |
41 | * - when adding nothing - it is neither a predecessor nor a successor | |
42 | * - before adding more than 127 to the starting value - it is a predecessor, | |
43 | * - when adding 128 - it is neither a predecessor nor a successor, | |
44 | * - after adding more than 127 to the starting value - it is a successor */ | |
45 | #define seq_before(x, y) ({typeof(x) _dummy = (x - y); \ | |
46 | _dummy > smallest_signed_int(_dummy); }) | |
47 | #define seq_after(x, y) seq_before(y, x) | |
48 | ||
49 | static void start_vis_timer(struct bat_priv *bat_priv); | |
50 | ||
51 | /* free the info */ | |
52 | static void free_info(struct kref *ref) | |
53 | { | |
54 | struct vis_info *info = container_of(ref, struct vis_info, refcount); | |
55 | struct bat_priv *bat_priv = info->bat_priv; | |
56 | struct recvlist_node *entry, *tmp; | |
57 | ||
58 | list_del_init(&info->send_list); | |
59 | spin_lock_bh(&bat_priv->vis_list_lock); | |
60 | list_for_each_entry_safe(entry, tmp, &info->recv_list, list) { | |
61 | list_del(&entry->list); | |
62 | kfree(entry); | |
63 | } | |
64 | ||
65 | spin_unlock_bh(&bat_priv->vis_list_lock); | |
66 | kfree_skb(info->skb_packet); | |
dda9fc6b | 67 | kfree(info); |
c6c8fea2 SE |
68 | } |
69 | ||
70 | /* Compare two vis packets, used by the hashing algorithm */ | |
747e4221 | 71 | static int vis_info_cmp(const struct hlist_node *node, const void *data2) |
c6c8fea2 | 72 | { |
747e4221 SE |
73 | const struct vis_info *d1, *d2; |
74 | const struct vis_packet *p1, *p2; | |
7aadf889 ML |
75 | |
76 | d1 = container_of(node, struct vis_info, hash_entry); | |
c6c8fea2 SE |
77 | d2 = data2; |
78 | p1 = (struct vis_packet *)d1->skb_packet->data; | |
79 | p2 = (struct vis_packet *)d2->skb_packet->data; | |
39901e71 | 80 | return compare_eth(p1->vis_orig, p2->vis_orig); |
c6c8fea2 SE |
81 | } |
82 | ||
83 | /* hash function to choose an entry in a hash table of given size */ | |
84 | /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ | |
747e4221 | 85 | static int vis_info_choose(const void *data, int size) |
c6c8fea2 | 86 | { |
747e4221 SE |
87 | const struct vis_info *vis_info = data; |
88 | const struct vis_packet *packet; | |
89 | const unsigned char *key; | |
c6c8fea2 SE |
90 | uint32_t hash = 0; |
91 | size_t i; | |
92 | ||
93 | packet = (struct vis_packet *)vis_info->skb_packet->data; | |
94 | key = packet->vis_orig; | |
95 | for (i = 0; i < ETH_ALEN; i++) { | |
96 | hash += key[i]; | |
97 | hash += (hash << 10); | |
98 | hash ^= (hash >> 6); | |
99 | } | |
100 | ||
101 | hash += (hash << 3); | |
102 | hash ^= (hash >> 11); | |
103 | hash += (hash << 15); | |
104 | ||
105 | return hash % size; | |
106 | } | |
107 | ||
7aadf889 | 108 | static struct vis_info *vis_hash_find(struct bat_priv *bat_priv, |
747e4221 | 109 | const void *data) |
7aadf889 ML |
110 | { |
111 | struct hashtable_t *hash = bat_priv->vis_hash; | |
112 | struct hlist_head *head; | |
113 | struct hlist_node *node; | |
114 | struct vis_info *vis_info, *vis_info_tmp = NULL; | |
115 | int index; | |
116 | ||
117 | if (!hash) | |
118 | return NULL; | |
119 | ||
120 | index = vis_info_choose(data, hash->size); | |
121 | head = &hash->table[index]; | |
122 | ||
123 | rcu_read_lock(); | |
124 | hlist_for_each_entry_rcu(vis_info, node, head, hash_entry) { | |
125 | if (!vis_info_cmp(node, data)) | |
126 | continue; | |
127 | ||
128 | vis_info_tmp = vis_info; | |
129 | break; | |
130 | } | |
131 | rcu_read_unlock(); | |
132 | ||
133 | return vis_info_tmp; | |
134 | } | |
135 | ||
c6c8fea2 SE |
136 | /* insert interface to the list of interfaces of one originator, if it |
137 | * does not already exist in the list */ | |
138 | static void vis_data_insert_interface(const uint8_t *interface, | |
139 | struct hlist_head *if_list, | |
140 | bool primary) | |
141 | { | |
142 | struct if_list_entry *entry; | |
143 | struct hlist_node *pos; | |
144 | ||
145 | hlist_for_each_entry(entry, pos, if_list, list) { | |
747e4221 | 146 | if (compare_eth(entry->addr, interface)) |
c6c8fea2 SE |
147 | return; |
148 | } | |
149 | ||
150 | /* its a new address, add it to the list */ | |
151 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | |
152 | if (!entry) | |
153 | return; | |
154 | memcpy(entry->addr, interface, ETH_ALEN); | |
155 | entry->primary = primary; | |
156 | hlist_add_head(&entry->list, if_list); | |
157 | } | |
158 | ||
747e4221 SE |
159 | static ssize_t vis_data_read_prim_sec(char *buff, |
160 | const struct hlist_head *if_list) | |
c6c8fea2 SE |
161 | { |
162 | struct if_list_entry *entry; | |
163 | struct hlist_node *pos; | |
164 | size_t len = 0; | |
165 | ||
166 | hlist_for_each_entry(entry, pos, if_list, list) { | |
167 | if (entry->primary) | |
168 | len += sprintf(buff + len, "PRIMARY, "); | |
169 | else | |
170 | len += sprintf(buff + len, "SEC %pM, ", entry->addr); | |
171 | } | |
172 | ||
173 | return len; | |
174 | } | |
175 | ||
176 | static size_t vis_data_count_prim_sec(struct hlist_head *if_list) | |
177 | { | |
178 | struct if_list_entry *entry; | |
179 | struct hlist_node *pos; | |
180 | size_t count = 0; | |
181 | ||
182 | hlist_for_each_entry(entry, pos, if_list, list) { | |
183 | if (entry->primary) | |
184 | count += 9; | |
185 | else | |
186 | count += 23; | |
187 | } | |
188 | ||
189 | return count; | |
190 | } | |
191 | ||
192 | /* read an entry */ | |
747e4221 SE |
193 | static ssize_t vis_data_read_entry(char *buff, |
194 | const struct vis_info_entry *entry, | |
195 | const uint8_t *src, bool primary) | |
c6c8fea2 SE |
196 | { |
197 | /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */ | |
198 | if (primary && entry->quality == 0) | |
2dafb49d | 199 | return sprintf(buff, "TT %pM, ", entry->dest); |
39901e71 | 200 | else if (compare_eth(entry->src, src)) |
c6c8fea2 SE |
201 | return sprintf(buff, "TQ %pM %d, ", entry->dest, |
202 | entry->quality); | |
203 | ||
204 | return 0; | |
205 | } | |
206 | ||
207 | int vis_seq_print_text(struct seq_file *seq, void *offset) | |
208 | { | |
32ae9b22 | 209 | struct hard_iface *primary_if; |
7aadf889 | 210 | struct hlist_node *node; |
c6c8fea2 | 211 | struct hlist_head *head; |
c6c8fea2 SE |
212 | struct vis_info *info; |
213 | struct vis_packet *packet; | |
214 | struct vis_info_entry *entries; | |
215 | struct net_device *net_dev = (struct net_device *)seq->private; | |
216 | struct bat_priv *bat_priv = netdev_priv(net_dev); | |
217 | struct hashtable_t *hash = bat_priv->vis_hash; | |
218 | HLIST_HEAD(vis_if_list); | |
219 | struct if_list_entry *entry; | |
220 | struct hlist_node *pos, *n; | |
32ae9b22 | 221 | int i, j, ret = 0; |
c6c8fea2 SE |
222 | int vis_server = atomic_read(&bat_priv->vis_mode); |
223 | size_t buff_pos, buf_size; | |
224 | char *buff; | |
225 | int compare; | |
226 | ||
32ae9b22 ML |
227 | primary_if = primary_if_get_selected(bat_priv); |
228 | if (!primary_if) | |
229 | goto out; | |
230 | ||
231 | if (vis_server == VIS_TYPE_CLIENT_UPDATE) | |
232 | goto out; | |
c6c8fea2 SE |
233 | |
234 | buf_size = 1; | |
235 | /* Estimate length */ | |
236 | spin_lock_bh(&bat_priv->vis_hash_lock); | |
237 | for (i = 0; i < hash->size; i++) { | |
238 | head = &hash->table[i]; | |
239 | ||
7aadf889 ML |
240 | rcu_read_lock(); |
241 | hlist_for_each_entry_rcu(info, node, head, hash_entry) { | |
c6c8fea2 SE |
242 | packet = (struct vis_packet *)info->skb_packet->data; |
243 | entries = (struct vis_info_entry *) | |
244 | ((char *)packet + sizeof(struct vis_packet)); | |
245 | ||
246 | for (j = 0; j < packet->entries; j++) { | |
247 | if (entries[j].quality == 0) | |
248 | continue; | |
249 | compare = | |
39901e71 | 250 | compare_eth(entries[j].src, packet->vis_orig); |
c6c8fea2 SE |
251 | vis_data_insert_interface(entries[j].src, |
252 | &vis_if_list, | |
253 | compare); | |
254 | } | |
255 | ||
256 | hlist_for_each_entry(entry, pos, &vis_if_list, list) { | |
257 | buf_size += 18 + 26 * packet->entries; | |
258 | ||
259 | /* add primary/secondary records */ | |
39901e71 | 260 | if (compare_eth(entry->addr, packet->vis_orig)) |
c6c8fea2 SE |
261 | buf_size += |
262 | vis_data_count_prim_sec(&vis_if_list); | |
263 | ||
264 | buf_size += 1; | |
265 | } | |
266 | ||
267 | hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, | |
268 | list) { | |
269 | hlist_del(&entry->list); | |
270 | kfree(entry); | |
271 | } | |
272 | } | |
7aadf889 | 273 | rcu_read_unlock(); |
c6c8fea2 SE |
274 | } |
275 | ||
276 | buff = kmalloc(buf_size, GFP_ATOMIC); | |
277 | if (!buff) { | |
278 | spin_unlock_bh(&bat_priv->vis_hash_lock); | |
32ae9b22 ML |
279 | ret = -ENOMEM; |
280 | goto out; | |
c6c8fea2 SE |
281 | } |
282 | buff[0] = '\0'; | |
283 | buff_pos = 0; | |
284 | ||
285 | for (i = 0; i < hash->size; i++) { | |
286 | head = &hash->table[i]; | |
287 | ||
7aadf889 ML |
288 | rcu_read_lock(); |
289 | hlist_for_each_entry_rcu(info, node, head, hash_entry) { | |
c6c8fea2 SE |
290 | packet = (struct vis_packet *)info->skb_packet->data; |
291 | entries = (struct vis_info_entry *) | |
292 | ((char *)packet + sizeof(struct vis_packet)); | |
293 | ||
294 | for (j = 0; j < packet->entries; j++) { | |
295 | if (entries[j].quality == 0) | |
296 | continue; | |
297 | compare = | |
39901e71 | 298 | compare_eth(entries[j].src, packet->vis_orig); |
c6c8fea2 SE |
299 | vis_data_insert_interface(entries[j].src, |
300 | &vis_if_list, | |
301 | compare); | |
302 | } | |
303 | ||
304 | hlist_for_each_entry(entry, pos, &vis_if_list, list) { | |
305 | buff_pos += sprintf(buff + buff_pos, "%pM,", | |
306 | entry->addr); | |
307 | ||
dd58ddc6 | 308 | for (j = 0; j < packet->entries; j++) |
c6c8fea2 SE |
309 | buff_pos += vis_data_read_entry( |
310 | buff + buff_pos, | |
dd58ddc6 | 311 | &entries[j], |
c6c8fea2 SE |
312 | entry->addr, |
313 | entry->primary); | |
314 | ||
315 | /* add primary/secondary records */ | |
39901e71 | 316 | if (compare_eth(entry->addr, packet->vis_orig)) |
c6c8fea2 SE |
317 | buff_pos += |
318 | vis_data_read_prim_sec(buff + buff_pos, | |
319 | &vis_if_list); | |
320 | ||
321 | buff_pos += sprintf(buff + buff_pos, "\n"); | |
322 | } | |
323 | ||
324 | hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, | |
325 | list) { | |
326 | hlist_del(&entry->list); | |
327 | kfree(entry); | |
328 | } | |
329 | } | |
7aadf889 | 330 | rcu_read_unlock(); |
c6c8fea2 SE |
331 | } |
332 | ||
333 | spin_unlock_bh(&bat_priv->vis_hash_lock); | |
334 | ||
335 | seq_printf(seq, "%s", buff); | |
336 | kfree(buff); | |
337 | ||
32ae9b22 ML |
338 | out: |
339 | if (primary_if) | |
340 | hardif_free_ref(primary_if); | |
341 | return ret; | |
c6c8fea2 SE |
342 | } |
343 | ||
344 | /* add the info packet to the send list, if it was not | |
345 | * already linked in. */ | |
346 | static void send_list_add(struct bat_priv *bat_priv, struct vis_info *info) | |
347 | { | |
348 | if (list_empty(&info->send_list)) { | |
349 | kref_get(&info->refcount); | |
350 | list_add_tail(&info->send_list, &bat_priv->vis_send_list); | |
351 | } | |
352 | } | |
353 | ||
354 | /* delete the info packet from the send list, if it was | |
355 | * linked in. */ | |
356 | static void send_list_del(struct vis_info *info) | |
357 | { | |
358 | if (!list_empty(&info->send_list)) { | |
359 | list_del_init(&info->send_list); | |
360 | kref_put(&info->refcount, free_info); | |
361 | } | |
362 | } | |
363 | ||
364 | /* tries to add one entry to the receive list. */ | |
365 | static void recv_list_add(struct bat_priv *bat_priv, | |
747e4221 | 366 | struct list_head *recv_list, const char *mac) |
c6c8fea2 SE |
367 | { |
368 | struct recvlist_node *entry; | |
369 | ||
370 | entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC); | |
371 | if (!entry) | |
372 | return; | |
373 | ||
374 | memcpy(entry->mac, mac, ETH_ALEN); | |
375 | spin_lock_bh(&bat_priv->vis_list_lock); | |
376 | list_add_tail(&entry->list, recv_list); | |
377 | spin_unlock_bh(&bat_priv->vis_list_lock); | |
378 | } | |
379 | ||
380 | /* returns 1 if this mac is in the recv_list */ | |
381 | static int recv_list_is_in(struct bat_priv *bat_priv, | |
747e4221 | 382 | const struct list_head *recv_list, const char *mac) |
c6c8fea2 | 383 | { |
747e4221 | 384 | const struct recvlist_node *entry; |
c6c8fea2 SE |
385 | |
386 | spin_lock_bh(&bat_priv->vis_list_lock); | |
387 | list_for_each_entry(entry, recv_list, list) { | |
39901e71 | 388 | if (compare_eth(entry->mac, mac)) { |
c6c8fea2 SE |
389 | spin_unlock_bh(&bat_priv->vis_list_lock); |
390 | return 1; | |
391 | } | |
392 | } | |
393 | spin_unlock_bh(&bat_priv->vis_list_lock); | |
394 | return 0; | |
395 | } | |
396 | ||
397 | /* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old, | |
398 | * broken.. ). vis hash must be locked outside. is_new is set when the packet | |
399 | * is newer than old entries in the hash. */ | |
400 | static struct vis_info *add_packet(struct bat_priv *bat_priv, | |
401 | struct vis_packet *vis_packet, | |
402 | int vis_info_len, int *is_new, | |
403 | int make_broadcast) | |
404 | { | |
405 | struct vis_info *info, *old_info; | |
406 | struct vis_packet *search_packet, *old_packet; | |
407 | struct vis_info search_elem; | |
408 | struct vis_packet *packet; | |
409 | int hash_added; | |
410 | ||
411 | *is_new = 0; | |
412 | /* sanity check */ | |
413 | if (!bat_priv->vis_hash) | |
414 | return NULL; | |
415 | ||
416 | /* see if the packet is already in vis_hash */ | |
417 | search_elem.skb_packet = dev_alloc_skb(sizeof(struct vis_packet)); | |
418 | if (!search_elem.skb_packet) | |
419 | return NULL; | |
420 | search_packet = (struct vis_packet *)skb_put(search_elem.skb_packet, | |
421 | sizeof(struct vis_packet)); | |
422 | ||
423 | memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN); | |
7aadf889 | 424 | old_info = vis_hash_find(bat_priv, &search_elem); |
c6c8fea2 SE |
425 | kfree_skb(search_elem.skb_packet); |
426 | ||
427 | if (old_info) { | |
428 | old_packet = (struct vis_packet *)old_info->skb_packet->data; | |
429 | if (!seq_after(ntohl(vis_packet->seqno), | |
430 | ntohl(old_packet->seqno))) { | |
431 | if (old_packet->seqno == vis_packet->seqno) { | |
432 | recv_list_add(bat_priv, &old_info->recv_list, | |
433 | vis_packet->sender_orig); | |
434 | return old_info; | |
435 | } else { | |
436 | /* newer packet is already in hash. */ | |
437 | return NULL; | |
438 | } | |
439 | } | |
440 | /* remove old entry */ | |
441 | hash_remove(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | |
442 | old_info); | |
443 | send_list_del(old_info); | |
444 | kref_put(&old_info->refcount, free_info); | |
445 | } | |
446 | ||
447 | info = kmalloc(sizeof(struct vis_info), GFP_ATOMIC); | |
448 | if (!info) | |
449 | return NULL; | |
450 | ||
451 | info->skb_packet = dev_alloc_skb(sizeof(struct vis_packet) + | |
452 | vis_info_len + sizeof(struct ethhdr)); | |
453 | if (!info->skb_packet) { | |
454 | kfree(info); | |
455 | return NULL; | |
456 | } | |
457 | skb_reserve(info->skb_packet, sizeof(struct ethhdr)); | |
458 | packet = (struct vis_packet *)skb_put(info->skb_packet, | |
459 | sizeof(struct vis_packet) + | |
460 | vis_info_len); | |
461 | ||
462 | kref_init(&info->refcount); | |
463 | INIT_LIST_HEAD(&info->send_list); | |
464 | INIT_LIST_HEAD(&info->recv_list); | |
465 | info->first_seen = jiffies; | |
466 | info->bat_priv = bat_priv; | |
467 | memcpy(packet, vis_packet, sizeof(struct vis_packet) + vis_info_len); | |
468 | ||
469 | /* initialize and add new packet. */ | |
470 | *is_new = 1; | |
471 | ||
472 | /* Make it a broadcast packet, if required */ | |
473 | if (make_broadcast) | |
474 | memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); | |
475 | ||
476 | /* repair if entries is longer than packet. */ | |
477 | if (packet->entries * sizeof(struct vis_info_entry) > vis_info_len) | |
478 | packet->entries = vis_info_len / sizeof(struct vis_info_entry); | |
479 | ||
480 | recv_list_add(bat_priv, &info->recv_list, packet->sender_orig); | |
481 | ||
482 | /* try to add it */ | |
483 | hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | |
7aadf889 | 484 | info, &info->hash_entry); |
c6c8fea2 SE |
485 | if (hash_added < 0) { |
486 | /* did not work (for some reason) */ | |
2674c158 | 487 | kref_put(&info->refcount, free_info); |
c6c8fea2 SE |
488 | info = NULL; |
489 | } | |
490 | ||
491 | return info; | |
492 | } | |
493 | ||
494 | /* handle the server sync packet, forward if needed. */ | |
495 | void receive_server_sync_packet(struct bat_priv *bat_priv, | |
496 | struct vis_packet *vis_packet, | |
497 | int vis_info_len) | |
498 | { | |
499 | struct vis_info *info; | |
500 | int is_new, make_broadcast; | |
501 | int vis_server = atomic_read(&bat_priv->vis_mode); | |
502 | ||
503 | make_broadcast = (vis_server == VIS_TYPE_SERVER_SYNC); | |
504 | ||
505 | spin_lock_bh(&bat_priv->vis_hash_lock); | |
506 | info = add_packet(bat_priv, vis_packet, vis_info_len, | |
507 | &is_new, make_broadcast); | |
508 | if (!info) | |
509 | goto end; | |
510 | ||
511 | /* only if we are server ourselves and packet is newer than the one in | |
512 | * hash.*/ | |
513 | if (vis_server == VIS_TYPE_SERVER_SYNC && is_new) | |
514 | send_list_add(bat_priv, info); | |
515 | end: | |
516 | spin_unlock_bh(&bat_priv->vis_hash_lock); | |
517 | } | |
518 | ||
519 | /* handle an incoming client update packet and schedule forward if needed. */ | |
520 | void receive_client_update_packet(struct bat_priv *bat_priv, | |
521 | struct vis_packet *vis_packet, | |
522 | int vis_info_len) | |
523 | { | |
524 | struct vis_info *info; | |
525 | struct vis_packet *packet; | |
526 | int is_new; | |
527 | int vis_server = atomic_read(&bat_priv->vis_mode); | |
528 | int are_target = 0; | |
529 | ||
530 | /* clients shall not broadcast. */ | |
531 | if (is_broadcast_ether_addr(vis_packet->target_orig)) | |
532 | return; | |
533 | ||
534 | /* Are we the target for this VIS packet? */ | |
535 | if (vis_server == VIS_TYPE_SERVER_SYNC && | |
536 | is_my_mac(vis_packet->target_orig)) | |
537 | are_target = 1; | |
538 | ||
539 | spin_lock_bh(&bat_priv->vis_hash_lock); | |
540 | info = add_packet(bat_priv, vis_packet, vis_info_len, | |
541 | &is_new, are_target); | |
542 | ||
543 | if (!info) | |
544 | goto end; | |
545 | /* note that outdated packets will be dropped at this point. */ | |
546 | ||
547 | packet = (struct vis_packet *)info->skb_packet->data; | |
548 | ||
549 | /* send only if we're the target server or ... */ | |
550 | if (are_target && is_new) { | |
551 | packet->vis_type = VIS_TYPE_SERVER_SYNC; /* upgrade! */ | |
552 | send_list_add(bat_priv, info); | |
553 | ||
554 | /* ... we're not the recipient (and thus need to forward). */ | |
555 | } else if (!is_my_mac(packet->target_orig)) { | |
556 | send_list_add(bat_priv, info); | |
557 | } | |
558 | ||
559 | end: | |
560 | spin_unlock_bh(&bat_priv->vis_hash_lock); | |
561 | } | |
562 | ||
563 | /* Walk the originators and find the VIS server with the best tq. Set the packet | |
564 | * address to its address and return the best_tq. | |
565 | * | |
566 | * Must be called with the originator hash locked */ | |
567 | static int find_best_vis_server(struct bat_priv *bat_priv, | |
568 | struct vis_info *info) | |
569 | { | |
570 | struct hashtable_t *hash = bat_priv->orig_hash; | |
e1a5382f | 571 | struct neigh_node *router; |
7aadf889 | 572 | struct hlist_node *node; |
c6c8fea2 | 573 | struct hlist_head *head; |
c6c8fea2 SE |
574 | struct orig_node *orig_node; |
575 | struct vis_packet *packet; | |
576 | int best_tq = -1, i; | |
577 | ||
578 | packet = (struct vis_packet *)info->skb_packet->data; | |
579 | ||
580 | for (i = 0; i < hash->size; i++) { | |
581 | head = &hash->table[i]; | |
582 | ||
fb778ea1 | 583 | rcu_read_lock(); |
7aadf889 | 584 | hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { |
e1a5382f LL |
585 | router = orig_node_get_router(orig_node); |
586 | if (!router) | |
587 | continue; | |
588 | ||
589 | if ((orig_node->flags & VIS_SERVER) && | |
590 | (router->tq_avg > best_tq)) { | |
591 | best_tq = router->tq_avg; | |
c6c8fea2 SE |
592 | memcpy(packet->target_orig, orig_node->orig, |
593 | ETH_ALEN); | |
594 | } | |
e1a5382f | 595 | neigh_node_free_ref(router); |
c6c8fea2 | 596 | } |
fb778ea1 | 597 | rcu_read_unlock(); |
c6c8fea2 SE |
598 | } |
599 | ||
600 | return best_tq; | |
601 | } | |
602 | ||
603 | /* Return true if the vis packet is full. */ | |
747e4221 | 604 | static bool vis_packet_full(const struct vis_info *info) |
c6c8fea2 | 605 | { |
747e4221 | 606 | const struct vis_packet *packet; |
c6c8fea2 SE |
607 | packet = (struct vis_packet *)info->skb_packet->data; |
608 | ||
609 | if (MAX_VIS_PACKET_SIZE / sizeof(struct vis_info_entry) | |
610 | < packet->entries + 1) | |
611 | return true; | |
612 | return false; | |
613 | } | |
614 | ||
615 | /* generates a packet of own vis data, | |
616 | * returns 0 on success, -1 if no packet could be generated */ | |
617 | static int generate_vis_packet(struct bat_priv *bat_priv) | |
618 | { | |
619 | struct hashtable_t *hash = bat_priv->orig_hash; | |
7aadf889 | 620 | struct hlist_node *node; |
c6c8fea2 | 621 | struct hlist_head *head; |
c6c8fea2 | 622 | struct orig_node *orig_node; |
e1a5382f | 623 | struct neigh_node *router; |
c6c8fea2 SE |
624 | struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; |
625 | struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data; | |
626 | struct vis_info_entry *entry; | |
2dafb49d | 627 | struct tt_local_entry *tt_local_entry; |
c6c8fea2 SE |
628 | int best_tq = -1, i; |
629 | ||
630 | info->first_seen = jiffies; | |
631 | packet->vis_type = atomic_read(&bat_priv->vis_mode); | |
632 | ||
c6c8fea2 SE |
633 | memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); |
634 | packet->ttl = TTL; | |
635 | packet->seqno = htonl(ntohl(packet->seqno) + 1); | |
636 | packet->entries = 0; | |
637 | skb_trim(info->skb_packet, sizeof(struct vis_packet)); | |
638 | ||
639 | if (packet->vis_type == VIS_TYPE_CLIENT_UPDATE) { | |
640 | best_tq = find_best_vis_server(bat_priv, info); | |
641 | ||
d0072609 | 642 | if (best_tq < 0) |
c6c8fea2 | 643 | return -1; |
c6c8fea2 SE |
644 | } |
645 | ||
646 | for (i = 0; i < hash->size; i++) { | |
647 | head = &hash->table[i]; | |
648 | ||
fb778ea1 | 649 | rcu_read_lock(); |
7aadf889 | 650 | hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { |
e1a5382f LL |
651 | router = orig_node_get_router(orig_node); |
652 | if (!router) | |
c6c8fea2 SE |
653 | continue; |
654 | ||
e1a5382f LL |
655 | if (!compare_eth(router->addr, orig_node->orig)) |
656 | goto next; | |
c6c8fea2 | 657 | |
e1a5382f LL |
658 | if (router->if_incoming->if_status != IF_ACTIVE) |
659 | goto next; | |
c6c8fea2 | 660 | |
e1a5382f LL |
661 | if (router->tq_avg < 1) |
662 | goto next; | |
c6c8fea2 SE |
663 | |
664 | /* fill one entry into buffer. */ | |
665 | entry = (struct vis_info_entry *) | |
666 | skb_put(info->skb_packet, sizeof(*entry)); | |
667 | memcpy(entry->src, | |
e1a5382f | 668 | router->if_incoming->net_dev->dev_addr, |
c6c8fea2 SE |
669 | ETH_ALEN); |
670 | memcpy(entry->dest, orig_node->orig, ETH_ALEN); | |
e1a5382f | 671 | entry->quality = router->tq_avg; |
c6c8fea2 SE |
672 | packet->entries++; |
673 | ||
e1a5382f LL |
674 | next: |
675 | neigh_node_free_ref(router); | |
676 | ||
d0072609 ML |
677 | if (vis_packet_full(info)) |
678 | goto unlock; | |
c6c8fea2 | 679 | } |
fb778ea1 | 680 | rcu_read_unlock(); |
c6c8fea2 SE |
681 | } |
682 | ||
2dafb49d | 683 | hash = bat_priv->tt_local_hash; |
c6c8fea2 | 684 | |
2dafb49d | 685 | spin_lock_bh(&bat_priv->tt_lhash_lock); |
c6c8fea2 SE |
686 | for (i = 0; i < hash->size; i++) { |
687 | head = &hash->table[i]; | |
688 | ||
2dafb49d | 689 | hlist_for_each_entry(tt_local_entry, node, head, hash_entry) { |
c6c8fea2 SE |
690 | entry = (struct vis_info_entry *) |
691 | skb_put(info->skb_packet, | |
692 | sizeof(*entry)); | |
693 | memset(entry->src, 0, ETH_ALEN); | |
2dafb49d AQ |
694 | memcpy(entry->dest, tt_local_entry->addr, ETH_ALEN); |
695 | entry->quality = 0; /* 0 means TT */ | |
c6c8fea2 SE |
696 | packet->entries++; |
697 | ||
698 | if (vis_packet_full(info)) { | |
2dafb49d | 699 | spin_unlock_bh(&bat_priv->tt_lhash_lock); |
c6c8fea2 SE |
700 | return 0; |
701 | } | |
702 | } | |
703 | } | |
704 | ||
2dafb49d | 705 | spin_unlock_bh(&bat_priv->tt_lhash_lock); |
c6c8fea2 | 706 | return 0; |
d0072609 ML |
707 | |
708 | unlock: | |
709 | rcu_read_unlock(); | |
710 | return 0; | |
c6c8fea2 SE |
711 | } |
712 | ||
713 | /* free old vis packets. Must be called with this vis_hash_lock | |
714 | * held */ | |
715 | static void purge_vis_packets(struct bat_priv *bat_priv) | |
716 | { | |
717 | int i; | |
718 | struct hashtable_t *hash = bat_priv->vis_hash; | |
7aadf889 | 719 | struct hlist_node *node, *node_tmp; |
c6c8fea2 | 720 | struct hlist_head *head; |
c6c8fea2 SE |
721 | struct vis_info *info; |
722 | ||
723 | for (i = 0; i < hash->size; i++) { | |
724 | head = &hash->table[i]; | |
725 | ||
7aadf889 ML |
726 | hlist_for_each_entry_safe(info, node, node_tmp, |
727 | head, hash_entry) { | |
c6c8fea2 SE |
728 | /* never purge own data. */ |
729 | if (info == bat_priv->my_vis_info) | |
730 | continue; | |
731 | ||
732 | if (time_after(jiffies, | |
733 | info->first_seen + VIS_TIMEOUT * HZ)) { | |
7aadf889 | 734 | hlist_del(node); |
c6c8fea2 SE |
735 | send_list_del(info); |
736 | kref_put(&info->refcount, free_info); | |
737 | } | |
738 | } | |
739 | } | |
740 | } | |
741 | ||
742 | static void broadcast_vis_packet(struct bat_priv *bat_priv, | |
743 | struct vis_info *info) | |
744 | { | |
e1a5382f | 745 | struct neigh_node *router; |
c6c8fea2 | 746 | struct hashtable_t *hash = bat_priv->orig_hash; |
7aadf889 | 747 | struct hlist_node *node; |
c6c8fea2 | 748 | struct hlist_head *head; |
c6c8fea2 SE |
749 | struct orig_node *orig_node; |
750 | struct vis_packet *packet; | |
751 | struct sk_buff *skb; | |
e6c10f43 | 752 | struct hard_iface *hard_iface; |
c6c8fea2 SE |
753 | uint8_t dstaddr[ETH_ALEN]; |
754 | int i; | |
755 | ||
756 | ||
c6c8fea2 SE |
757 | packet = (struct vis_packet *)info->skb_packet->data; |
758 | ||
759 | /* send to all routers in range. */ | |
760 | for (i = 0; i < hash->size; i++) { | |
761 | head = &hash->table[i]; | |
762 | ||
fb778ea1 | 763 | rcu_read_lock(); |
7aadf889 | 764 | hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { |
c6c8fea2 | 765 | /* if it's a vis server and reachable, send it. */ |
c6c8fea2 SE |
766 | if (!(orig_node->flags & VIS_SERVER)) |
767 | continue; | |
e1a5382f LL |
768 | |
769 | router = orig_node_get_router(orig_node); | |
770 | if (!router) | |
771 | continue; | |
772 | ||
c6c8fea2 | 773 | /* don't send it if we already received the packet from |
e1a5382f | 774 | * this node. */ |
c6c8fea2 | 775 | if (recv_list_is_in(bat_priv, &info->recv_list, |
e1a5382f LL |
776 | orig_node->orig)) { |
777 | neigh_node_free_ref(router); | |
c6c8fea2 | 778 | continue; |
e1a5382f | 779 | } |
c6c8fea2 SE |
780 | |
781 | memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); | |
e1a5382f LL |
782 | hard_iface = router->if_incoming; |
783 | memcpy(dstaddr, router->addr, ETH_ALEN); | |
784 | ||
785 | neigh_node_free_ref(router); | |
c6c8fea2 SE |
786 | |
787 | skb = skb_clone(info->skb_packet, GFP_ATOMIC); | |
788 | if (skb) | |
e6c10f43 | 789 | send_skb_packet(skb, hard_iface, dstaddr); |
c6c8fea2 | 790 | |
c6c8fea2 | 791 | } |
fb778ea1 | 792 | rcu_read_unlock(); |
c6c8fea2 | 793 | } |
c6c8fea2 SE |
794 | } |
795 | ||
796 | static void unicast_vis_packet(struct bat_priv *bat_priv, | |
797 | struct vis_info *info) | |
798 | { | |
799 | struct orig_node *orig_node; | |
e1a5382f | 800 | struct neigh_node *router = NULL; |
c6c8fea2 SE |
801 | struct sk_buff *skb; |
802 | struct vis_packet *packet; | |
c6c8fea2 | 803 | |
c6c8fea2 | 804 | packet = (struct vis_packet *)info->skb_packet->data; |
c6c8fea2 | 805 | |
7aadf889 | 806 | orig_node = orig_hash_find(bat_priv, packet->target_orig); |
44524fcd | 807 | if (!orig_node) |
e1a5382f | 808 | goto out; |
44524fcd | 809 | |
e1a5382f LL |
810 | router = orig_node_get_router(orig_node); |
811 | if (!router) | |
812 | goto out; | |
c6c8fea2 SE |
813 | |
814 | skb = skb_clone(info->skb_packet, GFP_ATOMIC); | |
815 | if (skb) | |
e1a5382f | 816 | send_skb_packet(skb, router->if_incoming, router->addr); |
c6c8fea2 SE |
817 | |
818 | out: | |
e1a5382f LL |
819 | if (router) |
820 | neigh_node_free_ref(router); | |
44524fcd | 821 | if (orig_node) |
7b36e8ee | 822 | orig_node_free_ref(orig_node); |
c6c8fea2 SE |
823 | } |
824 | ||
825 | /* only send one vis packet. called from send_vis_packets() */ | |
826 | static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) | |
827 | { | |
32ae9b22 | 828 | struct hard_iface *primary_if; |
c6c8fea2 SE |
829 | struct vis_packet *packet; |
830 | ||
32ae9b22 ML |
831 | primary_if = primary_if_get_selected(bat_priv); |
832 | if (!primary_if) | |
833 | goto out; | |
834 | ||
c6c8fea2 SE |
835 | packet = (struct vis_packet *)info->skb_packet->data; |
836 | if (packet->ttl < 2) { | |
837 | pr_debug("Error - can't send vis packet: ttl exceeded\n"); | |
32ae9b22 | 838 | goto out; |
c6c8fea2 SE |
839 | } |
840 | ||
32ae9b22 | 841 | memcpy(packet->sender_orig, primary_if->net_dev->dev_addr, ETH_ALEN); |
c6c8fea2 SE |
842 | packet->ttl--; |
843 | ||
844 | if (is_broadcast_ether_addr(packet->target_orig)) | |
845 | broadcast_vis_packet(bat_priv, info); | |
846 | else | |
847 | unicast_vis_packet(bat_priv, info); | |
848 | packet->ttl++; /* restore TTL */ | |
32ae9b22 ML |
849 | |
850 | out: | |
851 | if (primary_if) | |
852 | hardif_free_ref(primary_if); | |
c6c8fea2 SE |
853 | } |
854 | ||
855 | /* called from timer; send (and maybe generate) vis packet. */ | |
856 | static void send_vis_packets(struct work_struct *work) | |
857 | { | |
858 | struct delayed_work *delayed_work = | |
859 | container_of(work, struct delayed_work, work); | |
860 | struct bat_priv *bat_priv = | |
861 | container_of(delayed_work, struct bat_priv, vis_work); | |
1181e1da | 862 | struct vis_info *info; |
c6c8fea2 SE |
863 | |
864 | spin_lock_bh(&bat_priv->vis_hash_lock); | |
865 | purge_vis_packets(bat_priv); | |
866 | ||
867 | if (generate_vis_packet(bat_priv) == 0) { | |
868 | /* schedule if generation was successful */ | |
869 | send_list_add(bat_priv, bat_priv->my_vis_info); | |
870 | } | |
871 | ||
1181e1da SE |
872 | while (!list_empty(&bat_priv->vis_send_list)) { |
873 | info = list_first_entry(&bat_priv->vis_send_list, | |
874 | typeof(*info), send_list); | |
c6c8fea2 SE |
875 | |
876 | kref_get(&info->refcount); | |
877 | spin_unlock_bh(&bat_priv->vis_hash_lock); | |
878 | ||
32ae9b22 | 879 | send_vis_packet(bat_priv, info); |
c6c8fea2 SE |
880 | |
881 | spin_lock_bh(&bat_priv->vis_hash_lock); | |
882 | send_list_del(info); | |
883 | kref_put(&info->refcount, free_info); | |
884 | } | |
885 | spin_unlock_bh(&bat_priv->vis_hash_lock); | |
886 | start_vis_timer(bat_priv); | |
887 | } | |
888 | ||
889 | /* init the vis server. this may only be called when if_list is already | |
890 | * initialized (e.g. bat0 is initialized, interfaces have been added) */ | |
891 | int vis_init(struct bat_priv *bat_priv) | |
892 | { | |
893 | struct vis_packet *packet; | |
894 | int hash_added; | |
895 | ||
896 | if (bat_priv->vis_hash) | |
897 | return 1; | |
898 | ||
899 | spin_lock_bh(&bat_priv->vis_hash_lock); | |
900 | ||
901 | bat_priv->vis_hash = hash_new(256); | |
902 | if (!bat_priv->vis_hash) { | |
903 | pr_err("Can't initialize vis_hash\n"); | |
904 | goto err; | |
905 | } | |
906 | ||
907 | bat_priv->my_vis_info = kmalloc(MAX_VIS_PACKET_SIZE, GFP_ATOMIC); | |
908 | if (!bat_priv->my_vis_info) { | |
909 | pr_err("Can't initialize vis packet\n"); | |
910 | goto err; | |
911 | } | |
912 | ||
913 | bat_priv->my_vis_info->skb_packet = dev_alloc_skb( | |
914 | sizeof(struct vis_packet) + | |
915 | MAX_VIS_PACKET_SIZE + | |
916 | sizeof(struct ethhdr)); | |
917 | if (!bat_priv->my_vis_info->skb_packet) | |
918 | goto free_info; | |
919 | ||
920 | skb_reserve(bat_priv->my_vis_info->skb_packet, sizeof(struct ethhdr)); | |
921 | packet = (struct vis_packet *)skb_put( | |
922 | bat_priv->my_vis_info->skb_packet, | |
923 | sizeof(struct vis_packet)); | |
924 | ||
925 | /* prefill the vis info */ | |
926 | bat_priv->my_vis_info->first_seen = jiffies - | |
927 | msecs_to_jiffies(VIS_INTERVAL); | |
928 | INIT_LIST_HEAD(&bat_priv->my_vis_info->recv_list); | |
929 | INIT_LIST_HEAD(&bat_priv->my_vis_info->send_list); | |
930 | kref_init(&bat_priv->my_vis_info->refcount); | |
931 | bat_priv->my_vis_info->bat_priv = bat_priv; | |
932 | packet->version = COMPAT_VERSION; | |
933 | packet->packet_type = BAT_VIS; | |
934 | packet->ttl = TTL; | |
935 | packet->seqno = 0; | |
936 | packet->entries = 0; | |
937 | ||
938 | INIT_LIST_HEAD(&bat_priv->vis_send_list); | |
939 | ||
940 | hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | |
7aadf889 ML |
941 | bat_priv->my_vis_info, |
942 | &bat_priv->my_vis_info->hash_entry); | |
c6c8fea2 SE |
943 | if (hash_added < 0) { |
944 | pr_err("Can't add own vis packet into hash\n"); | |
945 | /* not in hash, need to remove it manually. */ | |
946 | kref_put(&bat_priv->my_vis_info->refcount, free_info); | |
947 | goto err; | |
948 | } | |
949 | ||
950 | spin_unlock_bh(&bat_priv->vis_hash_lock); | |
951 | start_vis_timer(bat_priv); | |
952 | return 1; | |
953 | ||
954 | free_info: | |
955 | kfree(bat_priv->my_vis_info); | |
956 | bat_priv->my_vis_info = NULL; | |
957 | err: | |
958 | spin_unlock_bh(&bat_priv->vis_hash_lock); | |
959 | vis_quit(bat_priv); | |
960 | return 0; | |
961 | } | |
962 | ||
963 | /* Decrease the reference count on a hash item info */ | |
7aadf889 | 964 | static void free_info_ref(struct hlist_node *node, void *arg) |
c6c8fea2 | 965 | { |
7aadf889 | 966 | struct vis_info *info; |
c6c8fea2 | 967 | |
7aadf889 | 968 | info = container_of(node, struct vis_info, hash_entry); |
c6c8fea2 SE |
969 | send_list_del(info); |
970 | kref_put(&info->refcount, free_info); | |
971 | } | |
972 | ||
973 | /* shutdown vis-server */ | |
974 | void vis_quit(struct bat_priv *bat_priv) | |
975 | { | |
976 | if (!bat_priv->vis_hash) | |
977 | return; | |
978 | ||
979 | cancel_delayed_work_sync(&bat_priv->vis_work); | |
980 | ||
981 | spin_lock_bh(&bat_priv->vis_hash_lock); | |
982 | /* properly remove, kill timers ... */ | |
983 | hash_delete(bat_priv->vis_hash, free_info_ref, NULL); | |
984 | bat_priv->vis_hash = NULL; | |
985 | bat_priv->my_vis_info = NULL; | |
986 | spin_unlock_bh(&bat_priv->vis_hash_lock); | |
987 | } | |
988 | ||
989 | /* schedule packets for (re)transmission */ | |
990 | static void start_vis_timer(struct bat_priv *bat_priv) | |
991 | { | |
992 | INIT_DELAYED_WORK(&bat_priv->vis_work, send_vis_packets); | |
993 | queue_delayed_work(bat_event_workqueue, &bat_priv->vis_work, | |
994 | msecs_to_jiffies(VIS_INTERVAL)); | |
995 | } |