2 * Copyright (C) 2007-2009 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"
28 struct hashtable_t
*hna_local_hash
;
29 static struct hashtable_t
*hna_global_hash
;
30 atomic_t hna_local_changed
;
32 DEFINE_SPINLOCK(hna_local_hash_lock
);
33 static DEFINE_SPINLOCK(hna_global_hash_lock
);
35 static DECLARE_DELAYED_WORK(hna_local_purge_wq
, hna_local_purge
);
37 static void hna_local_start_timer(void)
39 queue_delayed_work(bat_event_workqueue
, &hna_local_purge_wq
, 10 * HZ
);
42 int hna_local_init(void)
47 hna_local_hash
= hash_new(128, compare_orig
, choose_orig
);
52 atomic_set(&hna_local_changed
, 0);
53 hna_local_start_timer();
58 void hna_local_add(uint8_t *addr
)
60 struct hna_local_entry
*hna_local_entry
;
61 struct hna_global_entry
*hna_global_entry
;
62 struct hashtable_t
*swaphash
;
65 spin_lock_irqsave(&hna_local_hash_lock
, flags
);
67 ((struct hna_local_entry
*)hash_find(hna_local_hash
, addr
));
68 spin_unlock_irqrestore(&hna_local_hash_lock
, flags
);
70 if (hna_local_entry
!= NULL
) {
71 hna_local_entry
->last_seen
= jiffies
;
75 /* only announce as many hosts as possible in the batman-packet and
76 space in batman_packet->num_hna That also should give a limit to
78 if ((num_hna
+ 1 > (ETH_DATA_LEN
- BAT_PACKET_LEN
) / ETH_ALEN
) ||
79 (num_hna
+ 1 > 255)) {
80 bat_dbg(DBG_ROUTES
, "Can't add new local hna entry (%pM): number of local hna entries exceeds packet size \n", addr
);
84 bat_dbg(DBG_ROUTES
, "Creating new local hna entry: %pM \n",
87 hna_local_entry
= kmalloc(sizeof(struct hna_local_entry
), GFP_ATOMIC
);
91 memcpy(hna_local_entry
->addr
, addr
, ETH_ALEN
);
92 hna_local_entry
->last_seen
= jiffies
;
94 /* the batman interface mac address should never be purged */
95 if (compare_orig(addr
, soft_device
->dev_addr
))
96 hna_local_entry
->never_purge
= 1;
98 hna_local_entry
->never_purge
= 0;
100 spin_lock_irqsave(&hna_local_hash_lock
, flags
);
102 hash_add(hna_local_hash
, hna_local_entry
);
104 atomic_set(&hna_local_changed
, 1);
106 if (hna_local_hash
->elements
* 4 > hna_local_hash
->size
) {
107 swaphash
= hash_resize(hna_local_hash
,
108 hna_local_hash
->size
* 2);
110 if (swaphash
== NULL
)
111 printk(KERN_ERR
"batman-adv:Couldn't resize local hna hash table \n");
113 hna_local_hash
= swaphash
;
116 spin_unlock_irqrestore(&hna_local_hash_lock
, flags
);
118 /* remove address from global hash if present */
119 spin_lock_irqsave(&hna_global_hash_lock
, flags
);
122 ((struct hna_global_entry
*)hash_find(hna_global_hash
, addr
));
124 if (hna_global_entry
!= NULL
)
125 _hna_global_del_orig(hna_global_entry
, "local hna received");
127 spin_unlock_irqrestore(&hna_global_hash_lock
, flags
);
130 int hna_local_fill_buffer(unsigned char *buff
, int buff_len
)
132 struct hna_local_entry
*hna_local_entry
;
137 spin_lock_irqsave(&hna_local_hash_lock
, flags
);
139 while (hash_iterate(hna_local_hash
, &hashit
)) {
141 if (buff_len
< (i
+ 1) * ETH_ALEN
)
144 hna_local_entry
= hashit
.bucket
->data
;
145 memcpy(buff
+ (i
* ETH_ALEN
), hna_local_entry
->addr
, ETH_ALEN
);
150 /* if we did not get all new local hnas see you next time ;-) */
152 atomic_set(&hna_local_changed
, 0);
154 spin_unlock_irqrestore(&hna_local_hash_lock
, flags
);
159 int hna_local_fill_buffer_text(unsigned char *buff
, int buff_len
)
161 struct hna_local_entry
*hna_local_entry
;
163 int bytes_written
= 0;
166 spin_lock_irqsave(&hna_local_hash_lock
, flags
);
168 while (hash_iterate(hna_local_hash
, &hashit
)) {
170 if (buff_len
< bytes_written
+ ETH_STR_LEN
+ 4)
173 hna_local_entry
= hashit
.bucket
->data
;
175 bytes_written
+= snprintf(buff
+ bytes_written
, ETH_STR_LEN
+ 4,
176 " * %02x:%02x:%02x:%02x:%02x:%02x\n",
177 hna_local_entry
->addr
[0],
178 hna_local_entry
->addr
[1],
179 hna_local_entry
->addr
[2],
180 hna_local_entry
->addr
[3],
181 hna_local_entry
->addr
[4],
182 hna_local_entry
->addr
[5]);
185 spin_unlock_irqrestore(&hna_local_hash_lock
, flags
);
187 return bytes_written
;
190 static void _hna_local_del(void *data
)
194 atomic_set(&hna_local_changed
, 1);
197 static void hna_local_del(struct hna_local_entry
*hna_local_entry
,
200 bat_dbg(DBG_ROUTES
, "Deleting local hna entry (%pM): %s \n",
201 hna_local_entry
->addr
, message
);
203 hash_remove(hna_local_hash
, hna_local_entry
->addr
);
204 _hna_local_del(hna_local_entry
);
207 void hna_local_remove(uint8_t *addr
, char *message
)
209 struct hna_local_entry
*hna_local_entry
;
212 spin_lock_irqsave(&hna_local_hash_lock
, flags
);
214 hna_local_entry
= (struct hna_local_entry
*)
215 hash_find(hna_local_hash
, addr
);
217 hna_local_del(hna_local_entry
, message
);
219 spin_unlock_irqrestore(&hna_local_hash_lock
, flags
);
222 void hna_local_purge(struct work_struct
*work
)
224 struct hna_local_entry
*hna_local_entry
;
227 unsigned long timeout
;
229 spin_lock_irqsave(&hna_local_hash_lock
, flags
);
231 while (hash_iterate(hna_local_hash
, &hashit
)) {
232 hna_local_entry
= hashit
.bucket
->data
;
234 timeout
= hna_local_entry
->last_seen
+
235 ((LOCAL_HNA_TIMEOUT
/ 1000) * HZ
);
236 if ((!hna_local_entry
->never_purge
) &&
237 time_after(jiffies
, timeout
))
238 hna_local_del(hna_local_entry
, "address timed out");
241 spin_unlock_irqrestore(&hna_local_hash_lock
, flags
);
242 hna_local_start_timer();
245 void hna_local_free(void)
250 cancel_delayed_work_sync(&hna_local_purge_wq
);
251 hash_delete(hna_local_hash
, _hna_local_del
);
252 hna_local_hash
= NULL
;
255 int hna_global_init(void)
260 hna_global_hash
= hash_new(128, compare_orig
, choose_orig
);
262 if (!hna_global_hash
)
268 void hna_global_add_orig(struct orig_node
*orig_node
,
269 unsigned char *hna_buff
, int hna_buff_len
)
271 struct hna_global_entry
*hna_global_entry
;
272 struct hna_local_entry
*hna_local_entry
;
273 struct hashtable_t
*swaphash
;
274 int hna_buff_count
= 0;
276 unsigned char *hna_ptr
;
278 while ((hna_buff_count
+ 1) * ETH_ALEN
<= hna_buff_len
) {
279 spin_lock_irqsave(&hna_global_hash_lock
, flags
);
281 hna_ptr
= hna_buff
+ (hna_buff_count
* ETH_ALEN
);
282 hna_global_entry
= (struct hna_global_entry
*)
283 hash_find(hna_global_hash
, hna_ptr
);
285 if (hna_global_entry
== NULL
) {
286 spin_unlock_irqrestore(&hna_global_hash_lock
, flags
);
289 kmalloc(sizeof(struct hna_global_entry
),
292 if (!hna_global_entry
)
295 memcpy(hna_global_entry
->addr
, hna_ptr
, ETH_ALEN
);
298 "Creating new global hna entry: %pM (via %pM)\n",
299 hna_global_entry
->addr
, orig_node
->orig
);
301 spin_lock_irqsave(&hna_global_hash_lock
, flags
);
302 hash_add(hna_global_hash
, hna_global_entry
);
306 hna_global_entry
->orig_node
= orig_node
;
307 spin_unlock_irqrestore(&hna_global_hash_lock
, flags
);
309 /* remove address from local hash if present */
310 spin_lock_irqsave(&hna_local_hash_lock
, flags
);
312 hna_ptr
= hna_buff
+ (hna_buff_count
* ETH_ALEN
);
313 hna_local_entry
= (struct hna_local_entry
*)
314 hash_find(hna_local_hash
, hna_ptr
);
316 if (hna_local_entry
!= NULL
)
317 hna_local_del(hna_local_entry
, "global hna received");
319 spin_unlock_irqrestore(&hna_local_hash_lock
, flags
);
324 /* initialize, and overwrite if malloc succeeds */
325 orig_node
->hna_buff
= NULL
;
326 orig_node
->hna_buff_len
= 0;
328 if (hna_buff_len
> 0) {
329 orig_node
->hna_buff
= kmalloc(hna_buff_len
, GFP_ATOMIC
);
330 if (orig_node
->hna_buff
) {
331 memcpy(orig_node
->hna_buff
, hna_buff
, hna_buff_len
);
332 orig_node
->hna_buff_len
= hna_buff_len
;
336 spin_lock_irqsave(&hna_global_hash_lock
, flags
);
338 if (hna_global_hash
->elements
* 4 > hna_global_hash
->size
) {
339 swaphash
= hash_resize(hna_global_hash
,
340 hna_global_hash
->size
* 2);
342 if (swaphash
== NULL
)
343 printk(KERN_ERR
"batman-adv:Couldn't resize global hna hash table \n");
345 hna_global_hash
= swaphash
;
348 spin_unlock_irqrestore(&hna_global_hash_lock
, flags
);
351 int hna_global_fill_buffer_text(unsigned char *buff
, int buff_len
)
353 struct hna_global_entry
*hna_global_entry
;
355 int bytes_written
= 0;
358 spin_lock_irqsave(&hna_global_hash_lock
, flags
);
360 while (hash_iterate(hna_global_hash
, &hashit
)) {
361 if (buff_len
< bytes_written
+ (2 * ETH_STR_LEN
) + 10)
364 hna_global_entry
= hashit
.bucket
->data
;
366 bytes_written
+= snprintf(buff
+ bytes_written
,
367 (2 * ETH_STR_LEN
) + 10,
368 " * %02x:%02x:%02x:%02x:%02x:%02x via %02x:%02x:%02x:%02x:%02x:%02x \n",
369 hna_global_entry
->addr
[0],
370 hna_global_entry
->addr
[1],
371 hna_global_entry
->addr
[2],
372 hna_global_entry
->addr
[3],
373 hna_global_entry
->addr
[4],
374 hna_global_entry
->addr
[5],
375 hna_global_entry
->orig_node
->orig
[0],
376 hna_global_entry
->orig_node
->orig
[1],
377 hna_global_entry
->orig_node
->orig
[2],
378 hna_global_entry
->orig_node
->orig
[3],
379 hna_global_entry
->orig_node
->orig
[4],
380 hna_global_entry
->orig_node
->orig
[5]);
383 spin_unlock_irqrestore(&hna_global_hash_lock
, flags
);
385 return bytes_written
;
388 void _hna_global_del_orig(struct hna_global_entry
*hna_global_entry
,
391 bat_dbg(DBG_ROUTES
, "Deleting global hna entry %pM (via %pM): %s \n",
392 hna_global_entry
->addr
, hna_global_entry
->orig_node
->orig
,
395 hash_remove(hna_global_hash
, hna_global_entry
->addr
);
396 kfree(hna_global_entry
);
399 void hna_global_del_orig(struct orig_node
*orig_node
, char *message
)
401 struct hna_global_entry
*hna_global_entry
;
402 int hna_buff_count
= 0;
404 unsigned char *hna_ptr
;
406 if (orig_node
->hna_buff_len
== 0)
409 spin_lock_irqsave(&hna_global_hash_lock
, flags
);
411 while ((hna_buff_count
+ 1) * ETH_ALEN
<= orig_node
->hna_buff_len
) {
412 hna_ptr
= orig_node
->hna_buff
+ (hna_buff_count
* ETH_ALEN
);
413 hna_global_entry
= (struct hna_global_entry
*)
414 hash_find(hna_global_hash
, hna_ptr
);
416 if ((hna_global_entry
!= NULL
) &&
417 (hna_global_entry
->orig_node
== orig_node
))
418 _hna_global_del_orig(hna_global_entry
, message
);
423 spin_unlock_irqrestore(&hna_global_hash_lock
, flags
);
425 orig_node
->hna_buff_len
= 0;
426 kfree(orig_node
->hna_buff
);
427 orig_node
->hna_buff
= NULL
;
430 static void hna_global_del(void *data
)
435 void hna_global_free(void)
437 if (!hna_global_hash
)
440 hash_delete(hna_global_hash
, hna_global_del
);
441 hna_global_hash
= NULL
;
444 struct orig_node
*transtable_search(uint8_t *addr
)
446 struct hna_global_entry
*hna_global_entry
;
449 spin_lock_irqsave(&hna_global_hash_lock
, flags
);
450 hna_global_entry
= (struct hna_global_entry
*)
451 hash_find(hna_global_hash
, addr
);
452 spin_unlock_irqrestore(&hna_global_hash_lock
, flags
);
454 if (hna_global_entry
== NULL
)
457 return hna_global_entry
->orig_node
;