]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/batman-adv/translation-table.c
Staging: batman-adv: Convert MAC_FMT to %pM
[net-next-2.6.git] / drivers / staging / batman-adv / translation-table.c
CommitLineData
5beef3c9 1/*
9b6d10b7 2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
5beef3c9
AL
3 *
4 * Marek Lindner, 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 "translation-table.h"
5beef3c9
AL
24#include "soft-interface.h"
25#include "types.h"
26#include "hash.h"
5beef3c9
AL
27
28struct hashtable_t *hna_local_hash;
29static struct hashtable_t *hna_global_hash;
30atomic_t hna_local_changed;
31
32DEFINE_SPINLOCK(hna_local_hash_lock);
33static DEFINE_SPINLOCK(hna_global_hash_lock);
34
35static DECLARE_DELAYED_WORK(hna_local_purge_wq, hna_local_purge);
36
37static void hna_local_start_timer(void)
38{
39 queue_delayed_work(bat_event_workqueue, &hna_local_purge_wq, 10 * HZ);
40}
41
42int hna_local_init(void)
43{
44 if (hna_local_hash)
45 return 1;
46
47 hna_local_hash = hash_new(128, compare_orig, choose_orig);
48
49 if (!hna_local_hash)
50 return 0;
51
52 atomic_set(&hna_local_changed, 0);
53 hna_local_start_timer();
54
55 return 1;
56}
57
58void hna_local_add(uint8_t *addr)
59{
60 struct hna_local_entry *hna_local_entry;
61 struct hna_global_entry *hna_global_entry;
62 struct hashtable_t *swaphash;
5beef3c9
AL
63 unsigned long flags;
64
65 spin_lock_irqsave(&hna_local_hash_lock, flags);
66 hna_local_entry =
67 ((struct hna_local_entry *)hash_find(hna_local_hash, addr));
68 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
69
70 if (hna_local_entry != NULL) {
71 hna_local_entry->last_seen = jiffies;
72 return;
73 }
74
5beef3c9
AL
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
77 MAC-flooding. */
78 if ((num_hna + 1 > (ETH_DATA_LEN - BAT_PACKET_LEN) / ETH_ALEN) ||
79 (num_hna + 1 > 255)) {
6d45d8df
SE
80 bat_dbg(DBG_ROUTES,
81 "Can't add new local hna entry (%pM): "
82 "number of local hna entries exceeds packet size\n",
83 addr);
5beef3c9
AL
84 return;
85 }
86
0887635b 87 bat_dbg(DBG_ROUTES, "Creating new local hna entry: %pM\n",
b9b27e4e 88 addr);
5beef3c9
AL
89
90 hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC);
91 if (!hna_local_entry)
92 return;
93
94 memcpy(hna_local_entry->addr, addr, ETH_ALEN);
95 hna_local_entry->last_seen = jiffies;
96
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;
100 else
101 hna_local_entry->never_purge = 0;
102
103 spin_lock_irqsave(&hna_local_hash_lock, flags);
104
105 hash_add(hna_local_hash, hna_local_entry);
106 num_hna++;
107 atomic_set(&hna_local_changed, 1);
108
109 if (hna_local_hash->elements * 4 > hna_local_hash->size) {
110 swaphash = hash_resize(hna_local_hash,
111 hna_local_hash->size * 2);
112
113 if (swaphash == NULL)
6d45d8df
SE
114 printk(KERN_ERR "batman-adv:"
115 "Couldn't resize local hna hash table\n");
5beef3c9
AL
116 else
117 hna_local_hash = swaphash;
118 }
119
120 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
121
122 /* remove address from global hash if present */
123 spin_lock_irqsave(&hna_global_hash_lock, flags);
124
125 hna_global_entry =
126 ((struct hna_global_entry *)hash_find(hna_global_hash, addr));
127
128 if (hna_global_entry != NULL)
129 _hna_global_del_orig(hna_global_entry, "local hna received");
130
131 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
132}
133
134int hna_local_fill_buffer(unsigned char *buff, int buff_len)
135{
136 struct hna_local_entry *hna_local_entry;
b6c35976 137 HASHIT(hashit);
5beef3c9
AL
138 int i = 0;
139 unsigned long flags;
140
141 spin_lock_irqsave(&hna_local_hash_lock, flags);
142
b6c35976 143 while (hash_iterate(hna_local_hash, &hashit)) {
5beef3c9
AL
144
145 if (buff_len < (i + 1) * ETH_ALEN)
146 break;
147
b6c35976 148 hna_local_entry = hashit.bucket->data;
5beef3c9
AL
149 memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN);
150
151 i++;
152 }
153
154 /* if we did not get all new local hnas see you next time ;-) */
155 if (i == num_hna)
156 atomic_set(&hna_local_changed, 0);
157
158 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
159
160 return i;
161}
162
4caecbc0 163int hna_local_seq_print_text(struct seq_file *seq, void *offset)
5beef3c9 164{
4caecbc0 165 struct net_device *net_dev = (struct net_device *)seq->private;
208e13e4 166 struct bat_priv *bat_priv = netdev_priv(net_dev);
5beef3c9 167 struct hna_local_entry *hna_local_entry;
b6c35976 168 HASHIT(hashit);
4caecbc0 169 HASHIT(hashit_count);
5beef3c9 170 unsigned long flags;
4caecbc0
SE
171 size_t buf_size, pos;
172 char *buff;
47fdf097 173
208e13e4 174 if (!bat_priv->primary_if) {
4caecbc0
SE
175 return seq_printf(seq, "BATMAN mesh %s disabled - "
176 "please specify interfaces to enable it\n",
177 net_dev->name);
14741240 178 }
14741240 179
4caecbc0
SE
180 seq_printf(seq, "Locally retrieved addresses (from %s) "
181 "announced via HNA:\n",
182 net_dev->name);
5beef3c9
AL
183
184 spin_lock_irqsave(&hna_local_hash_lock, flags);
185
4caecbc0
SE
186 buf_size = 1;
187 /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
188 while (hash_iterate(hna_local_hash, &hashit_count))
189 buf_size += 21;
5beef3c9 190
4caecbc0
SE
191 buff = kmalloc(buf_size, GFP_ATOMIC);
192 if (!buff) {
193 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
194 return -ENOMEM;
195 }
196 buff[0] = '\0';
197 pos = 0;
47fdf097 198
4caecbc0 199 while (hash_iterate(hna_local_hash, &hashit)) {
b6c35976 200 hna_local_entry = hashit.bucket->data;
5beef3c9 201
516c9a77
JP
202 pos += snprintf(buff + pos, 22, " * %pM\n",
203 hna_local_entry->addr);
5beef3c9
AL
204 }
205
206 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
4caecbc0
SE
207
208 seq_printf(seq, "%s", buff);
209 kfree(buff);
210 return 0;
5beef3c9
AL
211}
212
213static void _hna_local_del(void *data)
214{
215 kfree(data);
216 num_hna--;
217 atomic_set(&hna_local_changed, 1);
218}
219
220static void hna_local_del(struct hna_local_entry *hna_local_entry,
221 char *message)
222{
0887635b 223 bat_dbg(DBG_ROUTES, "Deleting local hna entry (%pM): %s\n",
b9b27e4e 224 hna_local_entry->addr, message);
5beef3c9
AL
225
226 hash_remove(hna_local_hash, hna_local_entry->addr);
227 _hna_local_del(hna_local_entry);
228}
229
a9c2910a
AL
230void hna_local_remove(uint8_t *addr, char *message)
231{
232 struct hna_local_entry *hna_local_entry;
233 unsigned long flags;
234
235 spin_lock_irqsave(&hna_local_hash_lock, flags);
236
237 hna_local_entry = (struct hna_local_entry *)
238 hash_find(hna_local_hash, addr);
239 if (hna_local_entry)
240 hna_local_del(hna_local_entry, message);
241
242 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
243}
244
5beef3c9
AL
245void hna_local_purge(struct work_struct *work)
246{
247 struct hna_local_entry *hna_local_entry;
b6c35976 248 HASHIT(hashit);
5beef3c9
AL
249 unsigned long flags;
250 unsigned long timeout;
251
252 spin_lock_irqsave(&hna_local_hash_lock, flags);
253
b6c35976
SW
254 while (hash_iterate(hna_local_hash, &hashit)) {
255 hna_local_entry = hashit.bucket->data;
5beef3c9
AL
256
257 timeout = hna_local_entry->last_seen +
258 ((LOCAL_HNA_TIMEOUT / 1000) * HZ);
259 if ((!hna_local_entry->never_purge) &&
260 time_after(jiffies, timeout))
261 hna_local_del(hna_local_entry, "address timed out");
262 }
263
264 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
265 hna_local_start_timer();
266}
267
268void hna_local_free(void)
269{
270 if (!hna_local_hash)
271 return;
272
273 cancel_delayed_work_sync(&hna_local_purge_wq);
274 hash_delete(hna_local_hash, _hna_local_del);
275 hna_local_hash = NULL;
276}
277
278int hna_global_init(void)
279{
280 if (hna_global_hash)
281 return 1;
282
283 hna_global_hash = hash_new(128, compare_orig, choose_orig);
284
285 if (!hna_global_hash)
286 return 0;
287
288 return 1;
289}
290
291void hna_global_add_orig(struct orig_node *orig_node,
292 unsigned char *hna_buff, int hna_buff_len)
293{
294 struct hna_global_entry *hna_global_entry;
295 struct hna_local_entry *hna_local_entry;
296 struct hashtable_t *swaphash;
5beef3c9
AL
297 int hna_buff_count = 0;
298 unsigned long flags;
299 unsigned char *hna_ptr;
300
5beef3c9
AL
301 while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) {
302 spin_lock_irqsave(&hna_global_hash_lock, flags);
303
304 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
305 hna_global_entry = (struct hna_global_entry *)
306 hash_find(hna_global_hash, hna_ptr);
307
308 if (hna_global_entry == NULL) {
309 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
310
311 hna_global_entry =
312 kmalloc(sizeof(struct hna_global_entry),
313 GFP_ATOMIC);
314
315 if (!hna_global_entry)
316 break;
317
318 memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN);
319
bad2239e 320 bat_dbg(DBG_ROUTES,
6d45d8df
SE
321 "Creating new global hna entry: "
322 "%pM (via %pM)\n",
b9b27e4e 323 hna_global_entry->addr, orig_node->orig);
5beef3c9
AL
324
325 spin_lock_irqsave(&hna_global_hash_lock, flags);
326 hash_add(hna_global_hash, hna_global_entry);
327
328 }
329
330 hna_global_entry->orig_node = orig_node;
331 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
332
333 /* remove address from local hash if present */
334 spin_lock_irqsave(&hna_local_hash_lock, flags);
335
336 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
337 hna_local_entry = (struct hna_local_entry *)
338 hash_find(hna_local_hash, hna_ptr);
339
340 if (hna_local_entry != NULL)
341 hna_local_del(hna_local_entry, "global hna received");
342
343 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
344
345 hna_buff_count++;
346 }
347
c4bf05d3
SW
348 /* initialize, and overwrite if malloc succeeds */
349 orig_node->hna_buff = NULL;
350 orig_node->hna_buff_len = 0;
351
352 if (hna_buff_len > 0) {
353 orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC);
354 if (orig_node->hna_buff) {
355 memcpy(orig_node->hna_buff, hna_buff, hna_buff_len);
356 orig_node->hna_buff_len = hna_buff_len;
357 }
5beef3c9
AL
358 }
359
360 spin_lock_irqsave(&hna_global_hash_lock, flags);
361
362 if (hna_global_hash->elements * 4 > hna_global_hash->size) {
363 swaphash = hash_resize(hna_global_hash,
364 hna_global_hash->size * 2);
365
366 if (swaphash == NULL)
6d45d8df
SE
367 printk(KERN_ERR "batman-adv:"
368 "Couldn't resize global hna hash table\n");
5beef3c9
AL
369 else
370 hna_global_hash = swaphash;
371 }
372
373 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
374}
375
4caecbc0 376int hna_global_seq_print_text(struct seq_file *seq, void *offset)
5beef3c9 377{
4caecbc0 378 struct net_device *net_dev = (struct net_device *)seq->private;
208e13e4 379 struct bat_priv *bat_priv = netdev_priv(net_dev);
5beef3c9 380 struct hna_global_entry *hna_global_entry;
b6c35976 381 HASHIT(hashit);
4caecbc0 382 HASHIT(hashit_count);
5beef3c9 383 unsigned long flags;
4caecbc0
SE
384 size_t buf_size, pos;
385 char *buff;
47fdf097 386
208e13e4 387 if (!bat_priv->primary_if) {
4caecbc0
SE
388 return seq_printf(seq, "BATMAN mesh %s disabled - "
389 "please specify interfaces to enable it\n",
390 net_dev->name);
14741240 391 }
14741240 392
1bcb164e 393 seq_printf(seq, "Globally announced HNAs received via the mesh %s\n",
4caecbc0 394 net_dev->name);
5beef3c9
AL
395
396 spin_lock_irqsave(&hna_global_hash_lock, flags);
397
4caecbc0
SE
398 buf_size = 1;
399 /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/
400 while (hash_iterate(hna_global_hash, &hashit_count))
401 buf_size += 43;
5beef3c9 402
4caecbc0
SE
403 buff = kmalloc(buf_size, GFP_ATOMIC);
404 if (!buff) {
405 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
406 return -ENOMEM;
407 }
408 buff[0] = '\0';
409 pos = 0;
47fdf097 410
4caecbc0 411 while (hash_iterate(hna_global_hash, &hashit)) {
b6c35976 412 hna_global_entry = hashit.bucket->data;
5beef3c9 413
4caecbc0 414 pos += snprintf(buff + pos, 44,
516c9a77
JP
415 " * %pM via %pM\n", hna_global_entry->addr,
416 hna_global_entry->orig_node->orig);
5beef3c9
AL
417 }
418
419 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
4caecbc0
SE
420
421 seq_printf(seq, "%s", buff);
422 kfree(buff);
423 return 0;
5beef3c9
AL
424}
425
426void _hna_global_del_orig(struct hna_global_entry *hna_global_entry,
427 char *message)
428{
0887635b 429 bat_dbg(DBG_ROUTES, "Deleting global hna entry %pM (via %pM): %s\n",
b9b27e4e
AL
430 hna_global_entry->addr, hna_global_entry->orig_node->orig,
431 message);
5beef3c9
AL
432
433 hash_remove(hna_global_hash, hna_global_entry->addr);
434 kfree(hna_global_entry);
435}
436
437void hna_global_del_orig(struct orig_node *orig_node, char *message)
438{
439 struct hna_global_entry *hna_global_entry;
440 int hna_buff_count = 0;
441 unsigned long flags;
442 unsigned char *hna_ptr;
443
444 if (orig_node->hna_buff_len == 0)
445 return;
446
447 spin_lock_irqsave(&hna_global_hash_lock, flags);
448
449 while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) {
450 hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN);
451 hna_global_entry = (struct hna_global_entry *)
452 hash_find(hna_global_hash, hna_ptr);
453
454 if ((hna_global_entry != NULL) &&
455 (hna_global_entry->orig_node == orig_node))
456 _hna_global_del_orig(hna_global_entry, message);
457
458 hna_buff_count++;
459 }
460
461 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
462
463 orig_node->hna_buff_len = 0;
464 kfree(orig_node->hna_buff);
465 orig_node->hna_buff = NULL;
466}
467
468static void hna_global_del(void *data)
469{
470 kfree(data);
471}
472
473void hna_global_free(void)
474{
475 if (!hna_global_hash)
476 return;
477
478 hash_delete(hna_global_hash, hna_global_del);
479 hna_global_hash = NULL;
480}
481
482struct orig_node *transtable_search(uint8_t *addr)
483{
484 struct hna_global_entry *hna_global_entry;
485 unsigned long flags;
486
487 spin_lock_irqsave(&hna_global_hash_lock, flags);
488 hna_global_entry = (struct hna_global_entry *)
489 hash_find(hna_global_hash, addr);
490 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
491
492 if (hna_global_entry == NULL)
493 return NULL;
494
495 return hna_global_entry->orig_node;
496}