2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
4 * Marek Lindner, Simon Wunderlich
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.
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.
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
23 #include "translation-table.h"
24 #include "soft-interface.h"
27 #include "originator.h"
29 static void hna_local_purge(struct work_struct
*work
);
30 static void _hna_global_del_orig(struct bat_priv
*bat_priv
,
31 struct hna_global_entry
*hna_global_entry
,
34 static void hna_local_start_timer(struct bat_priv
*bat_priv
)
36 INIT_DELAYED_WORK(&bat_priv
->hna_work
, hna_local_purge
);
37 queue_delayed_work(bat_event_workqueue
, &bat_priv
->hna_work
, 10 * HZ
);
40 int hna_local_init(struct bat_priv
*bat_priv
)
42 if (bat_priv
->hna_local_hash
)
45 bat_priv
->hna_local_hash
= hash_new(128);
47 if (!bat_priv
->hna_local_hash
)
50 atomic_set(&bat_priv
->hna_local_changed
, 0);
51 hna_local_start_timer(bat_priv
);
56 void hna_local_add(struct net_device
*soft_iface
, uint8_t *addr
)
58 struct bat_priv
*bat_priv
= netdev_priv(soft_iface
);
59 struct hna_local_entry
*hna_local_entry
;
60 struct hna_global_entry
*hna_global_entry
;
61 struct hashtable_t
*swaphash
;
65 spin_lock_irqsave(&bat_priv
->hna_lhash_lock
, flags
);
67 ((struct hna_local_entry
*)hash_find(bat_priv
->hna_local_hash
,
68 compare_orig
, choose_orig
,
70 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
72 if (hna_local_entry
) {
73 hna_local_entry
->last_seen
= jiffies
;
77 /* only announce as many hosts as possible in the batman-packet and
78 space in batman_packet->num_hna That also should give a limit to
80 required_bytes
= (bat_priv
->num_local_hna
+ 1) * ETH_ALEN
;
81 required_bytes
+= BAT_PACKET_LEN
;
83 if ((required_bytes
> ETH_DATA_LEN
) ||
84 (atomic_read(&bat_priv
->aggregated_ogms
) &&
85 required_bytes
> MAX_AGGREGATION_BYTES
) ||
86 (bat_priv
->num_local_hna
+ 1 > 255)) {
87 bat_dbg(DBG_ROUTES
, bat_priv
,
88 "Can't add new local hna entry (%pM): "
89 "number of local hna entries exceeds packet size\n",
94 bat_dbg(DBG_ROUTES
, bat_priv
,
95 "Creating new local hna entry: %pM\n", addr
);
97 hna_local_entry
= kmalloc(sizeof(struct hna_local_entry
), GFP_ATOMIC
);
101 memcpy(hna_local_entry
->addr
, addr
, ETH_ALEN
);
102 hna_local_entry
->last_seen
= jiffies
;
104 /* the batman interface mac address should never be purged */
105 if (compare_orig(addr
, soft_iface
->dev_addr
))
106 hna_local_entry
->never_purge
= 1;
108 hna_local_entry
->never_purge
= 0;
110 spin_lock_irqsave(&bat_priv
->hna_lhash_lock
, flags
);
112 hash_add(bat_priv
->hna_local_hash
, compare_orig
, choose_orig
,
114 bat_priv
->num_local_hna
++;
115 atomic_set(&bat_priv
->hna_local_changed
, 1);
117 if (bat_priv
->hna_local_hash
->elements
* 4 >
118 bat_priv
->hna_local_hash
->size
) {
119 swaphash
= hash_resize(bat_priv
->hna_local_hash
, compare_orig
,
121 bat_priv
->hna_local_hash
->size
* 2);
124 pr_err("Couldn't resize local hna hash table\n");
126 bat_priv
->hna_local_hash
= swaphash
;
129 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
131 /* remove address from global hash if present */
132 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
134 hna_global_entry
= ((struct hna_global_entry
*)
135 hash_find(bat_priv
->hna_global_hash
,
136 compare_orig
, choose_orig
, addr
));
138 if (hna_global_entry
)
139 _hna_global_del_orig(bat_priv
, hna_global_entry
,
140 "local hna received");
142 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
145 int hna_local_fill_buffer(struct bat_priv
*bat_priv
,
146 unsigned char *buff
, int buff_len
)
148 struct hna_local_entry
*hna_local_entry
;
153 spin_lock_irqsave(&bat_priv
->hna_lhash_lock
, flags
);
155 while (hash_iterate(bat_priv
->hna_local_hash
, &hashit
)) {
157 if (buff_len
< (i
+ 1) * ETH_ALEN
)
160 hna_local_entry
= hashit
.bucket
->data
;
161 memcpy(buff
+ (i
* ETH_ALEN
), hna_local_entry
->addr
, ETH_ALEN
);
166 /* if we did not get all new local hnas see you next time ;-) */
167 if (i
== bat_priv
->num_local_hna
)
168 atomic_set(&bat_priv
->hna_local_changed
, 0);
170 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
174 int hna_local_seq_print_text(struct seq_file
*seq
, void *offset
)
176 struct net_device
*net_dev
= (struct net_device
*)seq
->private;
177 struct bat_priv
*bat_priv
= netdev_priv(net_dev
);
178 struct hna_local_entry
*hna_local_entry
;
180 HASHIT(hashit_count
);
182 size_t buf_size
, pos
;
185 if (!bat_priv
->primary_if
) {
186 return seq_printf(seq
, "BATMAN mesh %s disabled - "
187 "please specify interfaces to enable it\n",
191 seq_printf(seq
, "Locally retrieved addresses (from %s) "
192 "announced via HNA:\n",
195 spin_lock_irqsave(&bat_priv
->hna_lhash_lock
, flags
);
198 /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
199 while (hash_iterate(bat_priv
->hna_local_hash
, &hashit_count
))
202 buff
= kmalloc(buf_size
, GFP_ATOMIC
);
204 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
210 while (hash_iterate(bat_priv
->hna_local_hash
, &hashit
)) {
211 hna_local_entry
= hashit
.bucket
->data
;
213 pos
+= snprintf(buff
+ pos
, 22, " * %pM\n",
214 hna_local_entry
->addr
);
217 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
219 seq_printf(seq
, "%s", buff
);
224 static void _hna_local_del(void *data
, void *arg
)
226 struct bat_priv
*bat_priv
= (struct bat_priv
*)arg
;
229 bat_priv
->num_local_hna
--;
230 atomic_set(&bat_priv
->hna_local_changed
, 1);
233 static void hna_local_del(struct bat_priv
*bat_priv
,
234 struct hna_local_entry
*hna_local_entry
,
237 bat_dbg(DBG_ROUTES
, bat_priv
, "Deleting local hna entry (%pM): %s\n",
238 hna_local_entry
->addr
, message
);
240 hash_remove(bat_priv
->hna_local_hash
, compare_orig
, choose_orig
,
241 hna_local_entry
->addr
);
242 _hna_local_del(hna_local_entry
, bat_priv
);
245 void hna_local_remove(struct bat_priv
*bat_priv
,
246 uint8_t *addr
, char *message
)
248 struct hna_local_entry
*hna_local_entry
;
251 spin_lock_irqsave(&bat_priv
->hna_lhash_lock
, flags
);
253 hna_local_entry
= (struct hna_local_entry
*)
254 hash_find(bat_priv
->hna_local_hash
, compare_orig
, choose_orig
,
257 hna_local_del(bat_priv
, hna_local_entry
, message
);
259 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
262 static void hna_local_purge(struct work_struct
*work
)
264 struct delayed_work
*delayed_work
=
265 container_of(work
, struct delayed_work
, work
);
266 struct bat_priv
*bat_priv
=
267 container_of(delayed_work
, struct bat_priv
, hna_work
);
268 struct hna_local_entry
*hna_local_entry
;
271 unsigned long timeout
;
273 spin_lock_irqsave(&bat_priv
->hna_lhash_lock
, flags
);
275 while (hash_iterate(bat_priv
->hna_local_hash
, &hashit
)) {
276 hna_local_entry
= hashit
.bucket
->data
;
278 timeout
= hna_local_entry
->last_seen
+ LOCAL_HNA_TIMEOUT
* HZ
;
280 if ((!hna_local_entry
->never_purge
) &&
281 time_after(jiffies
, timeout
))
282 hna_local_del(bat_priv
, hna_local_entry
,
283 "address timed out");
286 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
287 hna_local_start_timer(bat_priv
);
290 void hna_local_free(struct bat_priv
*bat_priv
)
292 if (!bat_priv
->hna_local_hash
)
295 cancel_delayed_work_sync(&bat_priv
->hna_work
);
296 hash_delete(bat_priv
->hna_local_hash
, _hna_local_del
, bat_priv
);
297 bat_priv
->hna_local_hash
= NULL
;
300 int hna_global_init(struct bat_priv
*bat_priv
)
302 if (bat_priv
->hna_global_hash
)
305 bat_priv
->hna_global_hash
= hash_new(128);
307 if (!bat_priv
->hna_global_hash
)
313 void hna_global_add_orig(struct bat_priv
*bat_priv
,
314 struct orig_node
*orig_node
,
315 unsigned char *hna_buff
, int hna_buff_len
)
317 struct hna_global_entry
*hna_global_entry
;
318 struct hna_local_entry
*hna_local_entry
;
319 struct hashtable_t
*swaphash
;
320 int hna_buff_count
= 0;
322 unsigned char *hna_ptr
;
324 while ((hna_buff_count
+ 1) * ETH_ALEN
<= hna_buff_len
) {
325 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
327 hna_ptr
= hna_buff
+ (hna_buff_count
* ETH_ALEN
);
328 hna_global_entry
= (struct hna_global_entry
*)
329 hash_find(bat_priv
->hna_global_hash
, compare_orig
,
330 choose_orig
, hna_ptr
);
332 if (!hna_global_entry
) {
333 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
,
337 kmalloc(sizeof(struct hna_global_entry
),
340 if (!hna_global_entry
)
343 memcpy(hna_global_entry
->addr
, hna_ptr
, ETH_ALEN
);
345 bat_dbg(DBG_ROUTES
, bat_priv
,
346 "Creating new global hna entry: "
348 hna_global_entry
->addr
, orig_node
->orig
);
350 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
351 hash_add(bat_priv
->hna_global_hash
, compare_orig
,
352 choose_orig
, hna_global_entry
);
356 hna_global_entry
->orig_node
= orig_node
;
357 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
359 /* remove address from local hash if present */
360 spin_lock_irqsave(&bat_priv
->hna_lhash_lock
, flags
);
362 hna_ptr
= hna_buff
+ (hna_buff_count
* ETH_ALEN
);
363 hna_local_entry
= (struct hna_local_entry
*)
364 hash_find(bat_priv
->hna_local_hash
, compare_orig
,
365 choose_orig
, hna_ptr
);
368 hna_local_del(bat_priv
, hna_local_entry
,
369 "global hna received");
371 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
376 /* initialize, and overwrite if malloc succeeds */
377 orig_node
->hna_buff
= NULL
;
378 orig_node
->hna_buff_len
= 0;
380 if (hna_buff_len
> 0) {
381 orig_node
->hna_buff
= kmalloc(hna_buff_len
, GFP_ATOMIC
);
382 if (orig_node
->hna_buff
) {
383 memcpy(orig_node
->hna_buff
, hna_buff
, hna_buff_len
);
384 orig_node
->hna_buff_len
= hna_buff_len
;
388 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
390 if (bat_priv
->hna_global_hash
->elements
* 4 >
391 bat_priv
->hna_global_hash
->size
) {
392 swaphash
= hash_resize(bat_priv
->hna_global_hash
, compare_orig
,
394 bat_priv
->hna_global_hash
->size
* 2);
397 pr_err("Couldn't resize global hna hash table\n");
399 bat_priv
->hna_global_hash
= swaphash
;
402 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
405 int hna_global_seq_print_text(struct seq_file
*seq
, void *offset
)
407 struct net_device
*net_dev
= (struct net_device
*)seq
->private;
408 struct bat_priv
*bat_priv
= netdev_priv(net_dev
);
409 struct hna_global_entry
*hna_global_entry
;
411 HASHIT(hashit_count
);
413 size_t buf_size
, pos
;
416 if (!bat_priv
->primary_if
) {
417 return seq_printf(seq
, "BATMAN mesh %s disabled - "
418 "please specify interfaces to enable it\n",
422 seq_printf(seq
, "Globally announced HNAs received via the mesh %s\n",
425 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
428 /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/
429 while (hash_iterate(bat_priv
->hna_global_hash
, &hashit_count
))
432 buff
= kmalloc(buf_size
, GFP_ATOMIC
);
434 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
440 while (hash_iterate(bat_priv
->hna_global_hash
, &hashit
)) {
441 hna_global_entry
= hashit
.bucket
->data
;
443 pos
+= snprintf(buff
+ pos
, 44,
444 " * %pM via %pM\n", hna_global_entry
->addr
,
445 hna_global_entry
->orig_node
->orig
);
448 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
450 seq_printf(seq
, "%s", buff
);
455 static void _hna_global_del_orig(struct bat_priv
*bat_priv
,
456 struct hna_global_entry
*hna_global_entry
,
459 bat_dbg(DBG_ROUTES
, bat_priv
,
460 "Deleting global hna entry %pM (via %pM): %s\n",
461 hna_global_entry
->addr
, hna_global_entry
->orig_node
->orig
,
464 hash_remove(bat_priv
->hna_global_hash
, compare_orig
, choose_orig
,
465 hna_global_entry
->addr
);
466 kfree(hna_global_entry
);
469 void hna_global_del_orig(struct bat_priv
*bat_priv
,
470 struct orig_node
*orig_node
, char *message
)
472 struct hna_global_entry
*hna_global_entry
;
473 int hna_buff_count
= 0;
475 unsigned char *hna_ptr
;
477 if (orig_node
->hna_buff_len
== 0)
480 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
482 while ((hna_buff_count
+ 1) * ETH_ALEN
<= orig_node
->hna_buff_len
) {
483 hna_ptr
= orig_node
->hna_buff
+ (hna_buff_count
* ETH_ALEN
);
484 hna_global_entry
= (struct hna_global_entry
*)
485 hash_find(bat_priv
->hna_global_hash
, compare_orig
,
486 choose_orig
, hna_ptr
);
488 if ((hna_global_entry
) &&
489 (hna_global_entry
->orig_node
== orig_node
))
490 _hna_global_del_orig(bat_priv
, hna_global_entry
,
496 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
498 orig_node
->hna_buff_len
= 0;
499 kfree(orig_node
->hna_buff
);
500 orig_node
->hna_buff
= NULL
;
503 static void hna_global_del(void *data
, void *arg
)
508 void hna_global_free(struct bat_priv
*bat_priv
)
510 if (!bat_priv
->hna_global_hash
)
513 hash_delete(bat_priv
->hna_global_hash
, hna_global_del
, NULL
);
514 bat_priv
->hna_global_hash
= NULL
;
517 struct orig_node
*transtable_search(struct bat_priv
*bat_priv
, uint8_t *addr
)
519 struct hna_global_entry
*hna_global_entry
;
522 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
523 hna_global_entry
= (struct hna_global_entry
*)
524 hash_find(bat_priv
->hna_global_hash
,
525 compare_orig
, choose_orig
, addr
);
526 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
528 if (!hna_global_entry
)
531 return hna_global_entry
->orig_node
;