Staging: batman-adv: convert multiple /proc files to use sysfs
[GitHub/mt8127/android_kernel_alcatel_ttab.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)) {
0887635b 80 bat_dbg(DBG_ROUTES, "Can't add new local hna entry (%pM): number of local hna entries exceeds packet size\n", addr);
5beef3c9
AL
81 return;
82 }
83
0887635b 84 bat_dbg(DBG_ROUTES, "Creating new local hna entry: %pM\n",
b9b27e4e 85 addr);
5beef3c9
AL
86
87 hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC);
88 if (!hna_local_entry)
89 return;
90
91 memcpy(hna_local_entry->addr, addr, ETH_ALEN);
92 hna_local_entry->last_seen = jiffies;
93
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;
97 else
98 hna_local_entry->never_purge = 0;
99
100 spin_lock_irqsave(&hna_local_hash_lock, flags);
101
102 hash_add(hna_local_hash, hna_local_entry);
103 num_hna++;
104 atomic_set(&hna_local_changed, 1);
105
106 if (hna_local_hash->elements * 4 > hna_local_hash->size) {
107 swaphash = hash_resize(hna_local_hash,
108 hna_local_hash->size * 2);
109
110 if (swaphash == NULL)
0887635b 111 printk(KERN_ERR "batman-adv:Couldn't resize local hna hash table\n");
5beef3c9
AL
112 else
113 hna_local_hash = swaphash;
114 }
115
116 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
117
118 /* remove address from global hash if present */
119 spin_lock_irqsave(&hna_global_hash_lock, flags);
120
121 hna_global_entry =
122 ((struct hna_global_entry *)hash_find(hna_global_hash, addr));
123
124 if (hna_global_entry != NULL)
125 _hna_global_del_orig(hna_global_entry, "local hna received");
126
127 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
128}
129
130int hna_local_fill_buffer(unsigned char *buff, int buff_len)
131{
132 struct hna_local_entry *hna_local_entry;
b6c35976 133 HASHIT(hashit);
5beef3c9
AL
134 int i = 0;
135 unsigned long flags;
136
137 spin_lock_irqsave(&hna_local_hash_lock, flags);
138
b6c35976 139 while (hash_iterate(hna_local_hash, &hashit)) {
5beef3c9
AL
140
141 if (buff_len < (i + 1) * ETH_ALEN)
142 break;
143
b6c35976 144 hna_local_entry = hashit.bucket->data;
5beef3c9
AL
145 memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN);
146
147 i++;
148 }
149
150 /* if we did not get all new local hnas see you next time ;-) */
151 if (i == num_hna)
152 atomic_set(&hna_local_changed, 0);
153
154 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
155
156 return i;
157}
158
47fdf097
ML
159int hna_local_fill_buffer_text(struct net_device *net_dev, char *buff,
160 size_t count, loff_t off)
5beef3c9
AL
161{
162 struct hna_local_entry *hna_local_entry;
b6c35976 163 HASHIT(hashit);
5beef3c9
AL
164 int bytes_written = 0;
165 unsigned long flags;
47fdf097
ML
166 size_t hdr_len;
167
168 hdr_len = sprintf(buff,
169 "Locally retrieved addresses (from %s) announced via HNA:\n",
170 net_dev->name);
171
172 if (off < hdr_len)
173 bytes_written = hdr_len;
5beef3c9
AL
174
175 spin_lock_irqsave(&hna_local_hash_lock, flags);
176
b6c35976 177 while (hash_iterate(hna_local_hash, &hashit)) {
47fdf097 178 hdr_len += 21;
5beef3c9 179
47fdf097 180 if (count < bytes_written + 22)
5beef3c9
AL
181 break;
182
47fdf097
ML
183 if (off >= hdr_len)
184 continue;
185
b6c35976 186 hna_local_entry = hashit.bucket->data;
5beef3c9 187
47fdf097 188 bytes_written += snprintf(buff + bytes_written, 22,
5beef3c9
AL
189 " * %02x:%02x:%02x:%02x:%02x:%02x\n",
190 hna_local_entry->addr[0],
191 hna_local_entry->addr[1],
192 hna_local_entry->addr[2],
193 hna_local_entry->addr[3],
194 hna_local_entry->addr[4],
195 hna_local_entry->addr[5]);
196 }
197
198 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
5beef3c9
AL
199 return bytes_written;
200}
201
202static void _hna_local_del(void *data)
203{
204 kfree(data);
205 num_hna--;
206 atomic_set(&hna_local_changed, 1);
207}
208
209static void hna_local_del(struct hna_local_entry *hna_local_entry,
210 char *message)
211{
0887635b 212 bat_dbg(DBG_ROUTES, "Deleting local hna entry (%pM): %s\n",
b9b27e4e 213 hna_local_entry->addr, message);
5beef3c9
AL
214
215 hash_remove(hna_local_hash, hna_local_entry->addr);
216 _hna_local_del(hna_local_entry);
217}
218
a9c2910a
AL
219void hna_local_remove(uint8_t *addr, char *message)
220{
221 struct hna_local_entry *hna_local_entry;
222 unsigned long flags;
223
224 spin_lock_irqsave(&hna_local_hash_lock, flags);
225
226 hna_local_entry = (struct hna_local_entry *)
227 hash_find(hna_local_hash, addr);
228 if (hna_local_entry)
229 hna_local_del(hna_local_entry, message);
230
231 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
232}
233
5beef3c9
AL
234void hna_local_purge(struct work_struct *work)
235{
236 struct hna_local_entry *hna_local_entry;
b6c35976 237 HASHIT(hashit);
5beef3c9
AL
238 unsigned long flags;
239 unsigned long timeout;
240
241 spin_lock_irqsave(&hna_local_hash_lock, flags);
242
b6c35976
SW
243 while (hash_iterate(hna_local_hash, &hashit)) {
244 hna_local_entry = hashit.bucket->data;
5beef3c9
AL
245
246 timeout = hna_local_entry->last_seen +
247 ((LOCAL_HNA_TIMEOUT / 1000) * HZ);
248 if ((!hna_local_entry->never_purge) &&
249 time_after(jiffies, timeout))
250 hna_local_del(hna_local_entry, "address timed out");
251 }
252
253 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
254 hna_local_start_timer();
255}
256
257void hna_local_free(void)
258{
259 if (!hna_local_hash)
260 return;
261
262 cancel_delayed_work_sync(&hna_local_purge_wq);
263 hash_delete(hna_local_hash, _hna_local_del);
264 hna_local_hash = NULL;
265}
266
267int hna_global_init(void)
268{
269 if (hna_global_hash)
270 return 1;
271
272 hna_global_hash = hash_new(128, compare_orig, choose_orig);
273
274 if (!hna_global_hash)
275 return 0;
276
277 return 1;
278}
279
280void hna_global_add_orig(struct orig_node *orig_node,
281 unsigned char *hna_buff, int hna_buff_len)
282{
283 struct hna_global_entry *hna_global_entry;
284 struct hna_local_entry *hna_local_entry;
285 struct hashtable_t *swaphash;
5beef3c9
AL
286 int hna_buff_count = 0;
287 unsigned long flags;
288 unsigned char *hna_ptr;
289
5beef3c9
AL
290 while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) {
291 spin_lock_irqsave(&hna_global_hash_lock, flags);
292
293 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
294 hna_global_entry = (struct hna_global_entry *)
295 hash_find(hna_global_hash, hna_ptr);
296
297 if (hna_global_entry == NULL) {
298 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
299
300 hna_global_entry =
301 kmalloc(sizeof(struct hna_global_entry),
302 GFP_ATOMIC);
303
304 if (!hna_global_entry)
305 break;
306
307 memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN);
308
bad2239e 309 bat_dbg(DBG_ROUTES,
b9b27e4e
AL
310 "Creating new global hna entry: %pM (via %pM)\n",
311 hna_global_entry->addr, orig_node->orig);
5beef3c9
AL
312
313 spin_lock_irqsave(&hna_global_hash_lock, flags);
314 hash_add(hna_global_hash, hna_global_entry);
315
316 }
317
318 hna_global_entry->orig_node = orig_node;
319 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
320
321 /* remove address from local hash if present */
322 spin_lock_irqsave(&hna_local_hash_lock, flags);
323
324 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
325 hna_local_entry = (struct hna_local_entry *)
326 hash_find(hna_local_hash, hna_ptr);
327
328 if (hna_local_entry != NULL)
329 hna_local_del(hna_local_entry, "global hna received");
330
331 spin_unlock_irqrestore(&hna_local_hash_lock, flags);
332
333 hna_buff_count++;
334 }
335
c4bf05d3
SW
336 /* initialize, and overwrite if malloc succeeds */
337 orig_node->hna_buff = NULL;
338 orig_node->hna_buff_len = 0;
339
340 if (hna_buff_len > 0) {
341 orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC);
342 if (orig_node->hna_buff) {
343 memcpy(orig_node->hna_buff, hna_buff, hna_buff_len);
344 orig_node->hna_buff_len = hna_buff_len;
345 }
5beef3c9
AL
346 }
347
348 spin_lock_irqsave(&hna_global_hash_lock, flags);
349
350 if (hna_global_hash->elements * 4 > hna_global_hash->size) {
351 swaphash = hash_resize(hna_global_hash,
352 hna_global_hash->size * 2);
353
354 if (swaphash == NULL)
0887635b 355 printk(KERN_ERR "batman-adv:Couldn't resize global hna hash table\n");
5beef3c9
AL
356 else
357 hna_global_hash = swaphash;
358 }
359
360 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
361}
362
47fdf097
ML
363int hna_global_fill_buffer_text(struct net_device *net_dev, char *buff,
364 size_t count, loff_t off)
5beef3c9
AL
365{
366 struct hna_global_entry *hna_global_entry;
b6c35976 367 HASHIT(hashit);
5beef3c9
AL
368 int bytes_written = 0;
369 unsigned long flags;
47fdf097
ML
370 size_t hdr_len;
371
372 hdr_len = sprintf(buff,
373 "Globally announced HNAs received via the mesh %s (translation table):\n",
374 net_dev->name);
375
376 if (off < hdr_len)
377 bytes_written = hdr_len;
5beef3c9
AL
378
379 spin_lock_irqsave(&hna_global_hash_lock, flags);
380
b6c35976 381 while (hash_iterate(hna_global_hash, &hashit)) {
47fdf097
ML
382 hdr_len += 43;
383
384 if (count < bytes_written + 44)
5beef3c9
AL
385 break;
386
47fdf097
ML
387 if (off >= hdr_len)
388 continue;
389
b6c35976 390 hna_global_entry = hashit.bucket->data;
5beef3c9 391
47fdf097 392 bytes_written += snprintf(buff + bytes_written, 44,
0887635b 393 " * %02x:%02x:%02x:%02x:%02x:%02x via %02x:%02x:%02x:%02x:%02x:%02x\n",
5beef3c9
AL
394 hna_global_entry->addr[0],
395 hna_global_entry->addr[1],
396 hna_global_entry->addr[2],
397 hna_global_entry->addr[3],
398 hna_global_entry->addr[4],
399 hna_global_entry->addr[5],
400 hna_global_entry->orig_node->orig[0],
401 hna_global_entry->orig_node->orig[1],
402 hna_global_entry->orig_node->orig[2],
403 hna_global_entry->orig_node->orig[3],
404 hna_global_entry->orig_node->orig[4],
405 hna_global_entry->orig_node->orig[5]);
406 }
407
408 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
5beef3c9
AL
409 return bytes_written;
410}
411
412void _hna_global_del_orig(struct hna_global_entry *hna_global_entry,
413 char *message)
414{
0887635b 415 bat_dbg(DBG_ROUTES, "Deleting global hna entry %pM (via %pM): %s\n",
b9b27e4e
AL
416 hna_global_entry->addr, hna_global_entry->orig_node->orig,
417 message);
5beef3c9
AL
418
419 hash_remove(hna_global_hash, hna_global_entry->addr);
420 kfree(hna_global_entry);
421}
422
423void hna_global_del_orig(struct orig_node *orig_node, char *message)
424{
425 struct hna_global_entry *hna_global_entry;
426 int hna_buff_count = 0;
427 unsigned long flags;
428 unsigned char *hna_ptr;
429
430 if (orig_node->hna_buff_len == 0)
431 return;
432
433 spin_lock_irqsave(&hna_global_hash_lock, flags);
434
435 while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) {
436 hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN);
437 hna_global_entry = (struct hna_global_entry *)
438 hash_find(hna_global_hash, hna_ptr);
439
440 if ((hna_global_entry != NULL) &&
441 (hna_global_entry->orig_node == orig_node))
442 _hna_global_del_orig(hna_global_entry, message);
443
444 hna_buff_count++;
445 }
446
447 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
448
449 orig_node->hna_buff_len = 0;
450 kfree(orig_node->hna_buff);
451 orig_node->hna_buff = NULL;
452}
453
454static void hna_global_del(void *data)
455{
456 kfree(data);
457}
458
459void hna_global_free(void)
460{
461 if (!hna_global_hash)
462 return;
463
464 hash_delete(hna_global_hash, hna_global_del);
465 hna_global_hash = NULL;
466}
467
468struct orig_node *transtable_search(uint8_t *addr)
469{
470 struct hna_global_entry *hna_global_entry;
471 unsigned long flags;
472
473 spin_lock_irqsave(&hna_global_hash_lock, flags);
474 hna_global_entry = (struct hna_global_entry *)
475 hash_find(hna_global_hash, addr);
476 spin_unlock_irqrestore(&hna_global_hash_lock, flags);
477
478 if (hna_global_entry == NULL)
479 return NULL;
480
481 return hna_global_entry->orig_node;
482}