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 void hna_local_purge(struct work_struct *work);
36 static DECLARE_DELAYED_WORK(hna_local_purge_wq, hna_local_purge);
37 static void _hna_global_del_orig(struct bat_priv *bat_priv,
38 struct hna_global_entry *hna_global_entry,
41 static void hna_local_start_timer(void)
43 queue_delayed_work(bat_event_workqueue, &hna_local_purge_wq, 10 * HZ);
46 int hna_local_init(void)
51 hna_local_hash = hash_new(128, compare_orig, choose_orig);
56 atomic_set(&hna_local_changed, 0);
57 hna_local_start_timer();
62 void hna_local_add(struct net_device *soft_iface, uint8_t *addr)
64 struct bat_priv *bat_priv = netdev_priv(soft_iface);
65 struct hna_local_entry *hna_local_entry;
66 struct hna_global_entry *hna_global_entry;
67 struct hashtable_t *swaphash;
70 spin_lock_irqsave(&hna_local_hash_lock, flags);
72 ((struct hna_local_entry *)hash_find(hna_local_hash, addr));
73 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
75 if (hna_local_entry != NULL) {
76 hna_local_entry->last_seen = jiffies;
80 /* only announce as many hosts as possible in the batman-packet and
81 space in batman_packet->num_hna That also should give a limit to
83 if ((num_hna + 1 > (ETH_DATA_LEN - BAT_PACKET_LEN) / ETH_ALEN) ||
84 (num_hna + 1 > 255)) {
85 bat_dbg(DBG_ROUTES, bat_priv,
86 "Can't add new local hna entry (%pM): "
87 "number of local hna entries exceeds packet size\n",
92 bat_dbg(DBG_ROUTES, bat_priv,
93 "Creating new local hna entry: %pM\n", addr);
95 hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC);
99 memcpy(hna_local_entry->addr, addr, ETH_ALEN);
100 hna_local_entry->last_seen = jiffies;
102 /* the batman interface mac address should never be purged */
103 if (compare_orig(addr, soft_iface->dev_addr))
104 hna_local_entry->never_purge = 1;
106 hna_local_entry->never_purge = 0;
108 spin_lock_irqsave(&hna_local_hash_lock, flags);
110 hash_add(hna_local_hash, hna_local_entry);
112 atomic_set(&hna_local_changed, 1);
114 if (hna_local_hash->elements * 4 > hna_local_hash->size) {
115 swaphash = hash_resize(hna_local_hash,
116 hna_local_hash->size * 2);
118 if (swaphash == NULL)
119 pr_err("Couldn't resize local hna hash table\n");
121 hna_local_hash = swaphash;
124 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
126 /* remove address from global hash if present */
127 spin_lock_irqsave(&hna_global_hash_lock, flags);
130 ((struct hna_global_entry *)hash_find(hna_global_hash, addr));
132 if (hna_global_entry != NULL)
133 _hna_global_del_orig(bat_priv, hna_global_entry,
134 "local hna received");
136 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
139 int hna_local_fill_buffer(unsigned char *buff, int buff_len)
141 struct hna_local_entry *hna_local_entry;
146 spin_lock_irqsave(&hna_local_hash_lock, flags);
148 while (hash_iterate(hna_local_hash, &hashit)) {
150 if (buff_len < (i + 1) * ETH_ALEN)
153 hna_local_entry = hashit.bucket->data;
154 memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN);
159 /* if we did not get all new local hnas see you next time ;-) */
161 atomic_set(&hna_local_changed, 0);
163 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
168 int hna_local_seq_print_text(struct seq_file *seq, void *offset)
170 struct net_device *net_dev = (struct net_device *)seq->private;
171 struct bat_priv *bat_priv = netdev_priv(net_dev);
172 struct hna_local_entry *hna_local_entry;
174 HASHIT(hashit_count);
176 size_t buf_size, pos;
179 if (!bat_priv->primary_if) {
180 return seq_printf(seq, "BATMAN mesh %s disabled - "
181 "please specify interfaces to enable it\n",
185 seq_printf(seq, "Locally retrieved addresses (from %s) "
186 "announced via HNA:\n",
189 spin_lock_irqsave(&hna_local_hash_lock, flags);
192 /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
193 while (hash_iterate(hna_local_hash, &hashit_count))
196 buff = kmalloc(buf_size, GFP_ATOMIC);
198 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
204 while (hash_iterate(hna_local_hash, &hashit)) {
205 hna_local_entry = hashit.bucket->data;
207 pos += snprintf(buff + pos, 22, " * %pM\n",
208 hna_local_entry->addr);
211 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
213 seq_printf(seq, "%s", buff);
218 static void _hna_local_del(void *data, void *arg)
222 atomic_set(&hna_local_changed, 1);
225 static void hna_local_del(struct bat_priv *bat_priv,
226 struct hna_local_entry *hna_local_entry,
229 bat_dbg(DBG_ROUTES, bat_priv, "Deleting local hna entry (%pM): %s\n",
230 hna_local_entry->addr, message);
232 hash_remove(hna_local_hash, hna_local_entry->addr);
233 _hna_local_del(hna_local_entry, bat_priv);
236 void hna_local_remove(struct bat_priv *bat_priv,
237 uint8_t *addr, char *message)
239 struct hna_local_entry *hna_local_entry;
242 spin_lock_irqsave(&hna_local_hash_lock, flags);
244 hna_local_entry = (struct hna_local_entry *)
245 hash_find(hna_local_hash, addr);
247 hna_local_del(bat_priv, hna_local_entry, message);
249 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
252 static void hna_local_purge(struct work_struct *work)
254 struct hna_local_entry *hna_local_entry;
257 unsigned long timeout;
259 spin_lock_irqsave(&hna_local_hash_lock, flags);
261 while (hash_iterate(hna_local_hash, &hashit)) {
262 hna_local_entry = hashit.bucket->data;
264 timeout = hna_local_entry->last_seen + LOCAL_HNA_TIMEOUT * HZ;
265 /* if ((!hna_local_entry->never_purge) &&
266 time_after(jiffies, timeout))
267 hna_local_del(bat_priv, hna_local_entry,
268 "address timed out");*/
271 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
272 hna_local_start_timer();
275 void hna_local_free(void)
280 cancel_delayed_work_sync(&hna_local_purge_wq);
281 hash_delete(hna_local_hash, _hna_local_del, NULL);
282 hna_local_hash = NULL;
285 int hna_global_init(void)
290 hna_global_hash = hash_new(128, compare_orig, choose_orig);
292 if (!hna_global_hash)
298 void hna_global_add_orig(struct bat_priv *bat_priv,
299 struct orig_node *orig_node,
300 unsigned char *hna_buff, int hna_buff_len)
302 struct hna_global_entry *hna_global_entry;
303 struct hna_local_entry *hna_local_entry;
304 struct hashtable_t *swaphash;
305 int hna_buff_count = 0;
307 unsigned char *hna_ptr;
309 while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) {
310 spin_lock_irqsave(&hna_global_hash_lock, flags);
312 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
313 hna_global_entry = (struct hna_global_entry *)
314 hash_find(hna_global_hash, hna_ptr);
316 if (hna_global_entry == NULL) {
317 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
320 kmalloc(sizeof(struct hna_global_entry),
323 if (!hna_global_entry)
326 memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN);
328 bat_dbg(DBG_ROUTES, bat_priv,
329 "Creating new global hna entry: "
331 hna_global_entry->addr, orig_node->orig);
333 spin_lock_irqsave(&hna_global_hash_lock, flags);
334 hash_add(hna_global_hash, hna_global_entry);
338 hna_global_entry->orig_node = orig_node;
339 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
341 /* remove address from local hash if present */
342 spin_lock_irqsave(&hna_local_hash_lock, flags);
344 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
345 hna_local_entry = (struct hna_local_entry *)
346 hash_find(hna_local_hash, hna_ptr);
348 if (hna_local_entry != NULL)
349 hna_local_del(bat_priv, hna_local_entry,
350 "global hna received");
352 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
357 /* initialize, and overwrite if malloc succeeds */
358 orig_node->hna_buff = NULL;
359 orig_node->hna_buff_len = 0;
361 if (hna_buff_len > 0) {
362 orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC);
363 if (orig_node->hna_buff) {
364 memcpy(orig_node->hna_buff, hna_buff, hna_buff_len);
365 orig_node->hna_buff_len = hna_buff_len;
369 spin_lock_irqsave(&hna_global_hash_lock, flags);
371 if (hna_global_hash->elements * 4 > hna_global_hash->size) {
372 swaphash = hash_resize(hna_global_hash,
373 hna_global_hash->size * 2);
375 if (swaphash == NULL)
376 pr_err("Couldn't resize global hna hash table\n");
378 hna_global_hash = swaphash;
381 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
384 int hna_global_seq_print_text(struct seq_file *seq, void *offset)
386 struct net_device *net_dev = (struct net_device *)seq->private;
387 struct bat_priv *bat_priv = netdev_priv(net_dev);
388 struct hna_global_entry *hna_global_entry;
390 HASHIT(hashit_count);
392 size_t buf_size, pos;
395 if (!bat_priv->primary_if) {
396 return seq_printf(seq, "BATMAN mesh %s disabled - "
397 "please specify interfaces to enable it\n",
401 seq_printf(seq, "Globally announced HNAs received via the mesh %s\n",
404 spin_lock_irqsave(&hna_global_hash_lock, flags);
407 /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/
408 while (hash_iterate(hna_global_hash, &hashit_count))
411 buff = kmalloc(buf_size, GFP_ATOMIC);
413 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
419 while (hash_iterate(hna_global_hash, &hashit)) {
420 hna_global_entry = hashit.bucket->data;
422 pos += snprintf(buff + pos, 44,
423 " * %pM via %pM\n", hna_global_entry->addr,
424 hna_global_entry->orig_node->orig);
427 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
429 seq_printf(seq, "%s", buff);
434 static void _hna_global_del_orig(struct bat_priv *bat_priv,
435 struct hna_global_entry *hna_global_entry,
438 bat_dbg(DBG_ROUTES, bat_priv,
439 "Deleting global hna entry %pM (via %pM): %s\n",
440 hna_global_entry->addr, hna_global_entry->orig_node->orig,
443 hash_remove(hna_global_hash, hna_global_entry->addr);
444 kfree(hna_global_entry);
447 void hna_global_del_orig(struct bat_priv *bat_priv,
448 struct orig_node *orig_node, char *message)
450 struct hna_global_entry *hna_global_entry;
451 int hna_buff_count = 0;
453 unsigned char *hna_ptr;
455 if (orig_node->hna_buff_len == 0)
458 spin_lock_irqsave(&hna_global_hash_lock, flags);
460 while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) {
461 hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN);
462 hna_global_entry = (struct hna_global_entry *)
463 hash_find(hna_global_hash, hna_ptr);
465 if ((hna_global_entry != NULL) &&
466 (hna_global_entry->orig_node == orig_node))
467 _hna_global_del_orig(bat_priv, hna_global_entry,
473 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
475 orig_node->hna_buff_len = 0;
476 kfree(orig_node->hna_buff);
477 orig_node->hna_buff = NULL;
480 static void hna_global_del(void *data, void *arg)
485 void hna_global_free(void)
487 if (!hna_global_hash)
490 hash_delete(hna_global_hash, hna_global_del, NULL);
491 hna_global_hash = NULL;
494 struct orig_node *transtable_search(uint8_t *addr)
496 struct hna_global_entry *hna_global_entry;
499 spin_lock_irqsave(&hna_global_hash_lock, flags);
500 hna_global_entry = (struct hna_global_entry *)
501 hash_find(hna_global_hash, addr);
502 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
504 if (hna_global_entry == NULL)
507 return hna_global_entry->orig_node;