]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/batman-adv/translation-table.c
Staging: batman-adv: Reduce max characters on a line to 80
[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
47fdf097
ML
163int hna_local_fill_buffer_text(struct net_device *net_dev, char *buff,
164 size_t count, loff_t off)
5beef3c9 165{
208e13e4 166 struct bat_priv *bat_priv = netdev_priv(net_dev);
5beef3c9 167 struct hna_local_entry *hna_local_entry;
b6c35976 168 HASHIT(hashit);
5beef3c9
AL
169 int bytes_written = 0;
170 unsigned long flags;
47fdf097
ML
171 size_t hdr_len;
172
208e13e4 173 if (!bat_priv->primary_if) {
14741240
ML
174 if (off == 0)
175 return sprintf(buff,
6d45d8df
SE
176 "BATMAN mesh %s disabled - "
177 "please specify interfaces to enable it\n",
178 net_dev->name);
14741240
ML
179
180 return 0;
181 }
14741240 182
47fdf097 183 hdr_len = sprintf(buff,
6d45d8df
SE
184 "Locally retrieved addresses (from %s) "
185 "announced via HNA:\n",
47fdf097
ML
186 net_dev->name);
187
188 if (off < hdr_len)
189 bytes_written = hdr_len;
5beef3c9
AL
190
191 spin_lock_irqsave(&hna_local_hash_lock, flags);
192
b6c35976 193 while (hash_iterate(hna_local_hash, &hashit)) {
47fdf097 194 hdr_len += 21;
5beef3c9 195
47fdf097 196 if (count < bytes_written + 22)
5beef3c9
AL
197 break;
198
47fdf097
ML
199 if (off >= hdr_len)
200 continue;
201
b6c35976 202 hna_local_entry = hashit.bucket->data;
5beef3c9 203
47fdf097 204 bytes_written += snprintf(buff + bytes_written, 22,
6d45d8df 205 " * " MAC_FMT "\n",
5beef3c9
AL
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]);
212 }
213
214 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
5beef3c9
AL
215 return bytes_written;
216}
217
218static void _hna_local_del(void *data)
219{
220 kfree(data);
221 num_hna--;
222 atomic_set(&hna_local_changed, 1);
223}
224
225static void hna_local_del(struct hna_local_entry *hna_local_entry,
226 char *message)
227{
0887635b 228 bat_dbg(DBG_ROUTES, "Deleting local hna entry (%pM): %s\n",
b9b27e4e 229 hna_local_entry->addr, message);
5beef3c9
AL
230
231 hash_remove(hna_local_hash, hna_local_entry->addr);
232 _hna_local_del(hna_local_entry);
233}
234
a9c2910a
AL
235void hna_local_remove(uint8_t *addr, char *message)
236{
237 struct hna_local_entry *hna_local_entry;
238 unsigned long flags;
239
240 spin_lock_irqsave(&hna_local_hash_lock, flags);
241
242 hna_local_entry = (struct hna_local_entry *)
243 hash_find(hna_local_hash, addr);
244 if (hna_local_entry)
245 hna_local_del(hna_local_entry, message);
246
247 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
248}
249
5beef3c9
AL
250void hna_local_purge(struct work_struct *work)
251{
252 struct hna_local_entry *hna_local_entry;
b6c35976 253 HASHIT(hashit);
5beef3c9
AL
254 unsigned long flags;
255 unsigned long timeout;
256
257 spin_lock_irqsave(&hna_local_hash_lock, flags);
258
b6c35976
SW
259 while (hash_iterate(hna_local_hash, &hashit)) {
260 hna_local_entry = hashit.bucket->data;
5beef3c9
AL
261
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");
267 }
268
269 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
270 hna_local_start_timer();
271}
272
273void hna_local_free(void)
274{
275 if (!hna_local_hash)
276 return;
277
278 cancel_delayed_work_sync(&hna_local_purge_wq);
279 hash_delete(hna_local_hash, _hna_local_del);
280 hna_local_hash = NULL;
281}
282
283int hna_global_init(void)
284{
285 if (hna_global_hash)
286 return 1;
287
288 hna_global_hash = hash_new(128, compare_orig, choose_orig);
289
290 if (!hna_global_hash)
291 return 0;
292
293 return 1;
294}
295
296void hna_global_add_orig(struct orig_node *orig_node,
297 unsigned char *hna_buff, int hna_buff_len)
298{
299 struct hna_global_entry *hna_global_entry;
300 struct hna_local_entry *hna_local_entry;
301 struct hashtable_t *swaphash;
5beef3c9
AL
302 int hna_buff_count = 0;
303 unsigned long flags;
304 unsigned char *hna_ptr;
305
5beef3c9
AL
306 while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) {
307 spin_lock_irqsave(&hna_global_hash_lock, flags);
308
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);
312
313 if (hna_global_entry == NULL) {
314 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
315
316 hna_global_entry =
317 kmalloc(sizeof(struct hna_global_entry),
318 GFP_ATOMIC);
319
320 if (!hna_global_entry)
321 break;
322
323 memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN);
324
bad2239e 325 bat_dbg(DBG_ROUTES,
6d45d8df
SE
326 "Creating new global hna entry: "
327 "%pM (via %pM)\n",
b9b27e4e 328 hna_global_entry->addr, orig_node->orig);
5beef3c9
AL
329
330 spin_lock_irqsave(&hna_global_hash_lock, flags);
331 hash_add(hna_global_hash, hna_global_entry);
332
333 }
334
335 hna_global_entry->orig_node = orig_node;
336 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
337
338 /* remove address from local hash if present */
339 spin_lock_irqsave(&hna_local_hash_lock, flags);
340
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);
344
345 if (hna_local_entry != NULL)
346 hna_local_del(hna_local_entry, "global hna received");
347
348 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
349
350 hna_buff_count++;
351 }
352
c4bf05d3
SW
353 /* initialize, and overwrite if malloc succeeds */
354 orig_node->hna_buff = NULL;
355 orig_node->hna_buff_len = 0;
356
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;
362 }
5beef3c9
AL
363 }
364
365 spin_lock_irqsave(&hna_global_hash_lock, flags);
366
367 if (hna_global_hash->elements * 4 > hna_global_hash->size) {
368 swaphash = hash_resize(hna_global_hash,
369 hna_global_hash->size * 2);
370
371 if (swaphash == NULL)
6d45d8df
SE
372 printk(KERN_ERR "batman-adv:"
373 "Couldn't resize global hna hash table\n");
5beef3c9
AL
374 else
375 hna_global_hash = swaphash;
376 }
377
378 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
379}
380
47fdf097
ML
381int hna_global_fill_buffer_text(struct net_device *net_dev, char *buff,
382 size_t count, loff_t off)
5beef3c9 383{
208e13e4 384 struct bat_priv *bat_priv = netdev_priv(net_dev);
5beef3c9 385 struct hna_global_entry *hna_global_entry;
b6c35976 386 HASHIT(hashit);
5beef3c9
AL
387 int bytes_written = 0;
388 unsigned long flags;
47fdf097
ML
389 size_t hdr_len;
390
208e13e4 391 if (!bat_priv->primary_if) {
14741240
ML
392 if (off == 0)
393 return sprintf(buff,
6d45d8df
SE
394 "BATMAN mesh %s disabled - "
395 "please specify interfaces to enable it\n",
396 net_dev->name);
14741240
ML
397
398 return 0;
399 }
14741240 400
47fdf097 401 hdr_len = sprintf(buff,
6d45d8df
SE
402 "Globally announced HNAs received via the mesh %s "
403 "(translation table):\n",
47fdf097
ML
404 net_dev->name);
405
406 if (off < hdr_len)
407 bytes_written = hdr_len;
5beef3c9
AL
408
409 spin_lock_irqsave(&hna_global_hash_lock, flags);
410
b6c35976 411 while (hash_iterate(hna_global_hash, &hashit)) {
47fdf097
ML
412 hdr_len += 43;
413
414 if (count < bytes_written + 44)
5beef3c9
AL
415 break;
416
47fdf097
ML
417 if (off >= hdr_len)
418 continue;
419
b6c35976 420 hna_global_entry = hashit.bucket->data;
5beef3c9 421
47fdf097 422 bytes_written += snprintf(buff + bytes_written, 44,
6d45d8df 423 " * " MAC_FMT " via " MAC_FMT "\n",
5beef3c9
AL
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]);
436 }
437
438 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
5beef3c9
AL
439 return bytes_written;
440}
441
442void _hna_global_del_orig(struct hna_global_entry *hna_global_entry,
443 char *message)
444{
0887635b 445 bat_dbg(DBG_ROUTES, "Deleting global hna entry %pM (via %pM): %s\n",
b9b27e4e
AL
446 hna_global_entry->addr, hna_global_entry->orig_node->orig,
447 message);
5beef3c9
AL
448
449 hash_remove(hna_global_hash, hna_global_entry->addr);
450 kfree(hna_global_entry);
451}
452
453void hna_global_del_orig(struct orig_node *orig_node, char *message)
454{
455 struct hna_global_entry *hna_global_entry;
456 int hna_buff_count = 0;
457 unsigned long flags;
458 unsigned char *hna_ptr;
459
460 if (orig_node->hna_buff_len == 0)
461 return;
462
463 spin_lock_irqsave(&hna_global_hash_lock, flags);
464
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);
469
470 if ((hna_global_entry != NULL) &&
471 (hna_global_entry->orig_node == orig_node))
472 _hna_global_del_orig(hna_global_entry, message);
473
474 hna_buff_count++;
475 }
476
477 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
478
479 orig_node->hna_buff_len = 0;
480 kfree(orig_node->hna_buff);
481 orig_node->hna_buff = NULL;
482}
483
484static void hna_global_del(void *data)
485{
486 kfree(data);
487}
488
489void hna_global_free(void)
490{
491 if (!hna_global_hash)
492 return;
493
494 hash_delete(hna_global_hash, hna_global_del);
495 hna_global_hash = NULL;
496}
497
498struct orig_node *transtable_search(uint8_t *addr)
499{
500 struct hna_global_entry *hna_global_entry;
501 unsigned long flags;
502
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);
507
508 if (hna_global_entry == NULL)
509 return NULL;
510
511 return hna_global_entry->orig_node;
512}