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