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"
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)) {
81 "Can't add new local hna entry (%pM): "
82 "number of local hna entries exceeds packet size\n",
87 bat_dbg(DBG_ROUTES, "Creating new local hna entry: %pM\n",
90 hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC);
94 memcpy(hna_local_entry->addr, addr, ETH_ALEN);
95 hna_local_entry->last_seen = jiffies;
97 /* the batman interface mac address should never be purged */
98 if (compare_orig(addr, soft_device->dev_addr))
99 hna_local_entry->never_purge = 1;
101 hna_local_entry->never_purge = 0;
103 spin_lock_irqsave(&hna_local_hash_lock, flags);
105 hash_add(hna_local_hash, hna_local_entry);
107 atomic_set(&hna_local_changed, 1);
109 if (hna_local_hash->elements * 4 > hna_local_hash->size) {
110 swaphash = hash_resize(hna_local_hash,
111 hna_local_hash->size * 2);
113 if (swaphash == NULL)
114 printk(KERN_ERR "batman-adv:"
115 "Couldn't resize local hna hash table\n");
117 hna_local_hash = swaphash;
120 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
122 /* remove address from global hash if present */
123 spin_lock_irqsave(&hna_global_hash_lock, flags);
126 ((struct hna_global_entry *)hash_find(hna_global_hash, addr));
128 if (hna_global_entry != NULL)
129 _hna_global_del_orig(hna_global_entry, "local hna received");
131 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
134 int hna_local_fill_buffer(unsigned char *buff, int buff_len)
136 struct hna_local_entry *hna_local_entry;
141 spin_lock_irqsave(&hna_local_hash_lock, flags);
143 while (hash_iterate(hna_local_hash, &hashit)) {
145 if (buff_len < (i + 1) * ETH_ALEN)
148 hna_local_entry = hashit.bucket->data;
149 memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN);
154 /* if we did not get all new local hnas see you next time ;-) */
156 atomic_set(&hna_local_changed, 0);
158 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
163 int hna_local_fill_buffer_text(struct net_device *net_dev, char *buff,
164 size_t count, loff_t off)
166 struct bat_priv *bat_priv = netdev_priv(net_dev);
167 struct hna_local_entry *hna_local_entry;
169 int bytes_written = 0;
173 if (!bat_priv->primary_if) {
176 "BATMAN mesh %s disabled - "
177 "please specify interfaces to enable it\n",
183 hdr_len = sprintf(buff,
184 "Locally retrieved addresses (from %s) "
185 "announced via HNA:\n",
189 bytes_written = hdr_len;
191 spin_lock_irqsave(&hna_local_hash_lock, flags);
193 while (hash_iterate(hna_local_hash, &hashit)) {
196 if (count < bytes_written + 22)
202 hna_local_entry = hashit.bucket->data;
204 bytes_written += snprintf(buff + bytes_written, 22,
206 hna_local_entry->addr[0],
207 hna_local_entry->addr[1],
208 hna_local_entry->addr[2],
209 hna_local_entry->addr[3],
210 hna_local_entry->addr[4],
211 hna_local_entry->addr[5]);
214 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
215 return bytes_written;
218 static void _hna_local_del(void *data)
222 atomic_set(&hna_local_changed, 1);
225 static void hna_local_del(struct hna_local_entry *hna_local_entry,
228 bat_dbg(DBG_ROUTES, "Deleting local hna entry (%pM): %s\n",
229 hna_local_entry->addr, message);
231 hash_remove(hna_local_hash, hna_local_entry->addr);
232 _hna_local_del(hna_local_entry);
235 void hna_local_remove(uint8_t *addr, char *message)
237 struct hna_local_entry *hna_local_entry;
240 spin_lock_irqsave(&hna_local_hash_lock, flags);
242 hna_local_entry = (struct hna_local_entry *)
243 hash_find(hna_local_hash, addr);
245 hna_local_del(hna_local_entry, message);
247 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
250 void hna_local_purge(struct work_struct *work)
252 struct hna_local_entry *hna_local_entry;
255 unsigned long timeout;
257 spin_lock_irqsave(&hna_local_hash_lock, flags);
259 while (hash_iterate(hna_local_hash, &hashit)) {
260 hna_local_entry = hashit.bucket->data;
262 timeout = hna_local_entry->last_seen +
263 ((LOCAL_HNA_TIMEOUT / 1000) * HZ);
264 if ((!hna_local_entry->never_purge) &&
265 time_after(jiffies, timeout))
266 hna_local_del(hna_local_entry, "address timed out");
269 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
270 hna_local_start_timer();
273 void hna_local_free(void)
278 cancel_delayed_work_sync(&hna_local_purge_wq);
279 hash_delete(hna_local_hash, _hna_local_del);
280 hna_local_hash = NULL;
283 int hna_global_init(void)
288 hna_global_hash = hash_new(128, compare_orig, choose_orig);
290 if (!hna_global_hash)
296 void hna_global_add_orig(struct orig_node *orig_node,
297 unsigned char *hna_buff, int hna_buff_len)
299 struct hna_global_entry *hna_global_entry;
300 struct hna_local_entry *hna_local_entry;
301 struct hashtable_t *swaphash;
302 int hna_buff_count = 0;
304 unsigned char *hna_ptr;
306 while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) {
307 spin_lock_irqsave(&hna_global_hash_lock, flags);
309 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
310 hna_global_entry = (struct hna_global_entry *)
311 hash_find(hna_global_hash, hna_ptr);
313 if (hna_global_entry == NULL) {
314 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
317 kmalloc(sizeof(struct hna_global_entry),
320 if (!hna_global_entry)
323 memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN);
326 "Creating new global hna entry: "
328 hna_global_entry->addr, orig_node->orig);
330 spin_lock_irqsave(&hna_global_hash_lock, flags);
331 hash_add(hna_global_hash, hna_global_entry);
335 hna_global_entry->orig_node = orig_node;
336 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
338 /* remove address from local hash if present */
339 spin_lock_irqsave(&hna_local_hash_lock, flags);
341 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
342 hna_local_entry = (struct hna_local_entry *)
343 hash_find(hna_local_hash, hna_ptr);
345 if (hna_local_entry != NULL)
346 hna_local_del(hna_local_entry, "global hna received");
348 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
353 /* initialize, and overwrite if malloc succeeds */
354 orig_node->hna_buff = NULL;
355 orig_node->hna_buff_len = 0;
357 if (hna_buff_len > 0) {
358 orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC);
359 if (orig_node->hna_buff) {
360 memcpy(orig_node->hna_buff, hna_buff, hna_buff_len);
361 orig_node->hna_buff_len = hna_buff_len;
365 spin_lock_irqsave(&hna_global_hash_lock, flags);
367 if (hna_global_hash->elements * 4 > hna_global_hash->size) {
368 swaphash = hash_resize(hna_global_hash,
369 hna_global_hash->size * 2);
371 if (swaphash == NULL)
372 printk(KERN_ERR "batman-adv:"
373 "Couldn't resize global hna hash table\n");
375 hna_global_hash = swaphash;
378 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
381 int hna_global_fill_buffer_text(struct net_device *net_dev, char *buff,
382 size_t count, loff_t off)
384 struct bat_priv *bat_priv = netdev_priv(net_dev);
385 struct hna_global_entry *hna_global_entry;
387 int bytes_written = 0;
391 if (!bat_priv->primary_if) {
394 "BATMAN mesh %s disabled - "
395 "please specify interfaces to enable it\n",
401 hdr_len = sprintf(buff,
402 "Globally announced HNAs received via the mesh %s "
403 "(translation table):\n",
407 bytes_written = hdr_len;
409 spin_lock_irqsave(&hna_global_hash_lock, flags);
411 while (hash_iterate(hna_global_hash, &hashit)) {
414 if (count < bytes_written + 44)
420 hna_global_entry = hashit.bucket->data;
422 bytes_written += snprintf(buff + bytes_written, 44,
423 " * " MAC_FMT " via " MAC_FMT "\n",
424 hna_global_entry->addr[0],
425 hna_global_entry->addr[1],
426 hna_global_entry->addr[2],
427 hna_global_entry->addr[3],
428 hna_global_entry->addr[4],
429 hna_global_entry->addr[5],
430 hna_global_entry->orig_node->orig[0],
431 hna_global_entry->orig_node->orig[1],
432 hna_global_entry->orig_node->orig[2],
433 hna_global_entry->orig_node->orig[3],
434 hna_global_entry->orig_node->orig[4],
435 hna_global_entry->orig_node->orig[5]);
438 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
439 return bytes_written;
442 void _hna_global_del_orig(struct hna_global_entry *hna_global_entry,
445 bat_dbg(DBG_ROUTES, "Deleting global hna entry %pM (via %pM): %s\n",
446 hna_global_entry->addr, hna_global_entry->orig_node->orig,
449 hash_remove(hna_global_hash, hna_global_entry->addr);
450 kfree(hna_global_entry);
453 void hna_global_del_orig(struct orig_node *orig_node, char *message)
455 struct hna_global_entry *hna_global_entry;
456 int hna_buff_count = 0;
458 unsigned char *hna_ptr;
460 if (orig_node->hna_buff_len == 0)
463 spin_lock_irqsave(&hna_global_hash_lock, flags);
465 while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) {
466 hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN);
467 hna_global_entry = (struct hna_global_entry *)
468 hash_find(hna_global_hash, hna_ptr);
470 if ((hna_global_entry != NULL) &&
471 (hna_global_entry->orig_node == orig_node))
472 _hna_global_del_orig(hna_global_entry, message);
477 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
479 orig_node->hna_buff_len = 0;
480 kfree(orig_node->hna_buff);
481 orig_node->hna_buff = NULL;
484 static void hna_global_del(void *data)
489 void hna_global_free(void)
491 if (!hna_global_hash)
494 hash_delete(hna_global_hash, hna_global_del);
495 hna_global_hash = NULL;
498 struct orig_node *transtable_search(uint8_t *addr)
500 struct hna_global_entry *hna_global_entry;
503 spin_lock_irqsave(&hna_global_hash_lock, flags);
504 hna_global_entry = (struct hna_global_entry *)
505 hash_find(hna_global_hash, addr);
506 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
508 if (hna_global_entry == NULL)
511 return hna_global_entry->orig_node;