]>
git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/staging/batman-adv/translation-table.c
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 static void hna_local_purge(struct work_struct
*work
);
29 static void _hna_global_del_orig(struct bat_priv
*bat_priv
,
30 struct hna_global_entry
*hna_global_entry
,
33 static void hna_local_start_timer(struct bat_priv
*bat_priv
)
35 INIT_DELAYED_WORK(&bat_priv
->hna_work
, hna_local_purge
);
36 queue_delayed_work(bat_event_workqueue
, &bat_priv
->hna_work
, 10 * HZ
);
39 int hna_local_init(struct bat_priv
*bat_priv
)
41 if (bat_priv
->hna_local_hash
)
44 bat_priv
->hna_local_hash
= hash_new(128, compare_orig
, choose_orig
);
46 if (!bat_priv
->hna_local_hash
)
49 atomic_set(&bat_priv
->hna_local_changed
, 0);
50 hna_local_start_timer(bat_priv
);
55 void hna_local_add(struct net_device
*soft_iface
, uint8_t *addr
)
57 struct bat_priv
*bat_priv
= netdev_priv(soft_iface
);
58 struct hna_local_entry
*hna_local_entry
;
59 struct hna_global_entry
*hna_global_entry
;
60 struct hashtable_t
*swaphash
;
64 spin_lock_irqsave(&bat_priv
->hna_lhash_lock
, flags
);
66 ((struct hna_local_entry
*)hash_find(bat_priv
->hna_local_hash
,
68 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
70 if (hna_local_entry
) {
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 required_bytes
= (bat_priv
->num_local_hna
+ 1) * ETH_ALEN
;
79 required_bytes
+= BAT_PACKET_LEN
;
81 if ((required_bytes
> ETH_DATA_LEN
) ||
82 (atomic_read(&bat_priv
->aggregation_enabled
) &&
83 required_bytes
> MAX_AGGREGATION_BYTES
) ||
84 (bat_priv
->num_local_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(&bat_priv
->hna_lhash_lock
, flags
);
110 hash_add(bat_priv
->hna_local_hash
, hna_local_entry
);
111 bat_priv
->num_local_hna
++;
112 atomic_set(&bat_priv
->hna_local_changed
, 1);
114 if (bat_priv
->hna_local_hash
->elements
* 4 >
115 bat_priv
->hna_local_hash
->size
) {
116 swaphash
= hash_resize(bat_priv
->hna_local_hash
,
117 bat_priv
->hna_local_hash
->size
* 2);
120 pr_err("Couldn't resize local hna hash table\n");
122 bat_priv
->hna_local_hash
= swaphash
;
125 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
127 /* remove address from global hash if present */
128 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
130 hna_global_entry
= ((struct hna_global_entry
*)
131 hash_find(bat_priv
->hna_global_hash
, addr
));
133 if (hna_global_entry
)
134 _hna_global_del_orig(bat_priv
, hna_global_entry
,
135 "local hna received");
137 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
140 int hna_local_fill_buffer(struct bat_priv
*bat_priv
,
141 unsigned char *buff
, int buff_len
)
143 struct hna_local_entry
*hna_local_entry
;
148 spin_lock_irqsave(&bat_priv
->hna_lhash_lock
, flags
);
150 while (hash_iterate(bat_priv
->hna_local_hash
, &hashit
)) {
152 if (buff_len
< (i
+ 1) * ETH_ALEN
)
155 hna_local_entry
= hashit
.bucket
->data
;
156 memcpy(buff
+ (i
* ETH_ALEN
), hna_local_entry
->addr
, ETH_ALEN
);
161 /* if we did not get all new local hnas see you next time ;-) */
162 if (i
== bat_priv
->num_local_hna
)
163 atomic_set(&bat_priv
->hna_local_changed
, 0);
165 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
169 int hna_local_seq_print_text(struct seq_file
*seq
, void *offset
)
171 struct net_device
*net_dev
= (struct net_device
*)seq
->private;
172 struct bat_priv
*bat_priv
= netdev_priv(net_dev
);
173 struct hna_local_entry
*hna_local_entry
;
175 HASHIT(hashit_count
);
177 size_t buf_size
, pos
;
180 if (!bat_priv
->primary_if
) {
181 return seq_printf(seq
, "BATMAN mesh %s disabled - "
182 "please specify interfaces to enable it\n",
186 seq_printf(seq
, "Locally retrieved addresses (from %s) "
187 "announced via HNA:\n",
190 spin_lock_irqsave(&bat_priv
->hna_lhash_lock
, flags
);
193 /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
194 while (hash_iterate(bat_priv
->hna_local_hash
, &hashit_count
))
197 buff
= kmalloc(buf_size
, GFP_ATOMIC
);
199 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
205 while (hash_iterate(bat_priv
->hna_local_hash
, &hashit
)) {
206 hna_local_entry
= hashit
.bucket
->data
;
208 pos
+= snprintf(buff
+ pos
, 22, " * %pM\n",
209 hna_local_entry
->addr
);
212 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
214 seq_printf(seq
, "%s", buff
);
219 static void _hna_local_del(void *data
, void *arg
)
221 struct bat_priv
*bat_priv
= (struct bat_priv
*)arg
;
224 bat_priv
->num_local_hna
--;
225 atomic_set(&bat_priv
->hna_local_changed
, 1);
228 static void hna_local_del(struct bat_priv
*bat_priv
,
229 struct hna_local_entry
*hna_local_entry
,
232 bat_dbg(DBG_ROUTES
, bat_priv
, "Deleting local hna entry (%pM): %s\n",
233 hna_local_entry
->addr
, message
);
235 hash_remove(bat_priv
->hna_local_hash
, hna_local_entry
->addr
);
236 _hna_local_del(hna_local_entry
, bat_priv
);
239 void hna_local_remove(struct bat_priv
*bat_priv
,
240 uint8_t *addr
, char *message
)
242 struct hna_local_entry
*hna_local_entry
;
245 spin_lock_irqsave(&bat_priv
->hna_lhash_lock
, flags
);
247 hna_local_entry
= (struct hna_local_entry
*)
248 hash_find(bat_priv
->hna_local_hash
, addr
);
250 hna_local_del(bat_priv
, hna_local_entry
, message
);
252 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
255 static void hna_local_purge(struct work_struct
*work
)
257 struct delayed_work
*delayed_work
=
258 container_of(work
, struct delayed_work
, work
);
259 struct bat_priv
*bat_priv
=
260 container_of(delayed_work
, struct bat_priv
, hna_work
);
261 struct hna_local_entry
*hna_local_entry
;
264 unsigned long timeout
;
266 spin_lock_irqsave(&bat_priv
->hna_lhash_lock
, flags
);
268 while (hash_iterate(bat_priv
->hna_local_hash
, &hashit
)) {
269 hna_local_entry
= hashit
.bucket
->data
;
271 timeout
= hna_local_entry
->last_seen
+ LOCAL_HNA_TIMEOUT
* HZ
;
273 if ((!hna_local_entry
->never_purge
) &&
274 time_after(jiffies
, timeout
))
275 hna_local_del(bat_priv
, hna_local_entry
,
276 "address timed out");
279 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
280 hna_local_start_timer(bat_priv
);
283 void hna_local_free(struct bat_priv
*bat_priv
)
285 if (!bat_priv
->hna_local_hash
)
288 cancel_delayed_work_sync(&bat_priv
->hna_work
);
289 hash_delete(bat_priv
->hna_local_hash
, _hna_local_del
, bat_priv
);
290 bat_priv
->hna_local_hash
= NULL
;
293 int hna_global_init(struct bat_priv
*bat_priv
)
295 if (bat_priv
->hna_global_hash
)
298 bat_priv
->hna_global_hash
= hash_new(128, compare_orig
, choose_orig
);
300 if (!bat_priv
->hna_global_hash
)
306 void hna_global_add_orig(struct bat_priv
*bat_priv
,
307 struct orig_node
*orig_node
,
308 unsigned char *hna_buff
, int hna_buff_len
)
310 struct hna_global_entry
*hna_global_entry
;
311 struct hna_local_entry
*hna_local_entry
;
312 struct hashtable_t
*swaphash
;
313 int hna_buff_count
= 0;
315 unsigned char *hna_ptr
;
317 while ((hna_buff_count
+ 1) * ETH_ALEN
<= hna_buff_len
) {
318 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
320 hna_ptr
= hna_buff
+ (hna_buff_count
* ETH_ALEN
);
321 hna_global_entry
= (struct hna_global_entry
*)
322 hash_find(bat_priv
->hna_global_hash
, hna_ptr
);
324 if (!hna_global_entry
) {
325 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
,
329 kmalloc(sizeof(struct hna_global_entry
),
332 if (!hna_global_entry
)
335 memcpy(hna_global_entry
->addr
, hna_ptr
, ETH_ALEN
);
337 bat_dbg(DBG_ROUTES
, bat_priv
,
338 "Creating new global hna entry: "
340 hna_global_entry
->addr
, orig_node
->orig
);
342 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
343 hash_add(bat_priv
->hna_global_hash
, hna_global_entry
);
347 hna_global_entry
->orig_node
= orig_node
;
348 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
350 /* remove address from local hash if present */
351 spin_lock_irqsave(&bat_priv
->hna_lhash_lock
, flags
);
353 hna_ptr
= hna_buff
+ (hna_buff_count
* ETH_ALEN
);
354 hna_local_entry
= (struct hna_local_entry
*)
355 hash_find(bat_priv
->hna_local_hash
, hna_ptr
);
358 hna_local_del(bat_priv
, hna_local_entry
,
359 "global hna received");
361 spin_unlock_irqrestore(&bat_priv
->hna_lhash_lock
, flags
);
366 /* initialize, and overwrite if malloc succeeds */
367 orig_node
->hna_buff
= NULL
;
368 orig_node
->hna_buff_len
= 0;
370 if (hna_buff_len
> 0) {
371 orig_node
->hna_buff
= kmalloc(hna_buff_len
, GFP_ATOMIC
);
372 if (orig_node
->hna_buff
) {
373 memcpy(orig_node
->hna_buff
, hna_buff
, hna_buff_len
);
374 orig_node
->hna_buff_len
= hna_buff_len
;
378 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
380 if (bat_priv
->hna_global_hash
->elements
* 4 >
381 bat_priv
->hna_global_hash
->size
) {
382 swaphash
= hash_resize(bat_priv
->hna_global_hash
,
383 bat_priv
->hna_global_hash
->size
* 2);
386 pr_err("Couldn't resize global hna hash table\n");
388 bat_priv
->hna_global_hash
= swaphash
;
391 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
394 int hna_global_seq_print_text(struct seq_file
*seq
, void *offset
)
396 struct net_device
*net_dev
= (struct net_device
*)seq
->private;
397 struct bat_priv
*bat_priv
= netdev_priv(net_dev
);
398 struct hna_global_entry
*hna_global_entry
;
400 HASHIT(hashit_count
);
402 size_t buf_size
, pos
;
405 if (!bat_priv
->primary_if
) {
406 return seq_printf(seq
, "BATMAN mesh %s disabled - "
407 "please specify interfaces to enable it\n",
411 seq_printf(seq
, "Globally announced HNAs received via the mesh %s\n",
414 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
417 /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/
418 while (hash_iterate(bat_priv
->hna_global_hash
, &hashit_count
))
421 buff
= kmalloc(buf_size
, GFP_ATOMIC
);
423 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
429 while (hash_iterate(bat_priv
->hna_global_hash
, &hashit
)) {
430 hna_global_entry
= hashit
.bucket
->data
;
432 pos
+= snprintf(buff
+ pos
, 44,
433 " * %pM via %pM\n", hna_global_entry
->addr
,
434 hna_global_entry
->orig_node
->orig
);
437 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
439 seq_printf(seq
, "%s", buff
);
444 static void _hna_global_del_orig(struct bat_priv
*bat_priv
,
445 struct hna_global_entry
*hna_global_entry
,
448 bat_dbg(DBG_ROUTES
, bat_priv
,
449 "Deleting global hna entry %pM (via %pM): %s\n",
450 hna_global_entry
->addr
, hna_global_entry
->orig_node
->orig
,
453 hash_remove(bat_priv
->hna_global_hash
, hna_global_entry
->addr
);
454 kfree(hna_global_entry
);
457 void hna_global_del_orig(struct bat_priv
*bat_priv
,
458 struct orig_node
*orig_node
, char *message
)
460 struct hna_global_entry
*hna_global_entry
;
461 int hna_buff_count
= 0;
463 unsigned char *hna_ptr
;
465 if (orig_node
->hna_buff_len
== 0)
468 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
470 while ((hna_buff_count
+ 1) * ETH_ALEN
<= orig_node
->hna_buff_len
) {
471 hna_ptr
= orig_node
->hna_buff
+ (hna_buff_count
* ETH_ALEN
);
472 hna_global_entry
= (struct hna_global_entry
*)
473 hash_find(bat_priv
->hna_global_hash
, hna_ptr
);
475 if ((hna_global_entry
) &&
476 (hna_global_entry
->orig_node
== orig_node
))
477 _hna_global_del_orig(bat_priv
, hna_global_entry
,
483 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
485 orig_node
->hna_buff_len
= 0;
486 kfree(orig_node
->hna_buff
);
487 orig_node
->hna_buff
= NULL
;
490 static void hna_global_del(void *data
, void *arg
)
495 void hna_global_free(struct bat_priv
*bat_priv
)
497 if (!bat_priv
->hna_global_hash
)
500 hash_delete(bat_priv
->hna_global_hash
, hna_global_del
, NULL
);
501 bat_priv
->hna_global_hash
= NULL
;
504 struct orig_node
*transtable_search(struct bat_priv
*bat_priv
, uint8_t *addr
)
506 struct hna_global_entry
*hna_global_entry
;
509 spin_lock_irqsave(&bat_priv
->hna_ghash_lock
, flags
);
510 hna_global_entry
= (struct hna_global_entry
*)
511 hash_find(bat_priv
->hna_global_hash
, addr
);
512 spin_unlock_irqrestore(&bat_priv
->hna_ghash_lock
, flags
);
514 if (!hna_global_entry
)
517 return hna_global_entry
->orig_node
;