blob: 7b729660cbfdd6ecea373822995621fa0daff3ba [file] [log] [blame]
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001/*
Sven Eckelmann64afe352011-01-27 10:38:15 +01002 * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00003 *
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"
Marek Lindner32ae9b22011-04-20 15:40:58 +020025#include "hard-interface.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000026#include "hash.h"
27#include "originator.h"
28
Antonio Quartulli2dafb492011-05-05 08:42:45 +020029static void tt_local_purge(struct work_struct *work);
30static void _tt_global_del_orig(struct bat_priv *bat_priv,
31 struct tt_global_entry *tt_global_entry,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000032 char *message);
33
Marek Lindner7aadf882011-02-18 12:28:09 +000034/* returns 1 if they are the same mac addr */
Antonio Quartulli2dafb492011-05-05 08:42:45 +020035static int compare_ltt(struct hlist_node *node, void *data2)
Marek Lindner7aadf882011-02-18 12:28:09 +000036{
Antonio Quartulli2dafb492011-05-05 08:42:45 +020037 void *data1 = container_of(node, struct tt_local_entry, hash_entry);
Marek Lindner7aadf882011-02-18 12:28:09 +000038
39 return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
40}
41
42/* returns 1 if they are the same mac addr */
Antonio Quartulli2dafb492011-05-05 08:42:45 +020043static int compare_gtt(struct hlist_node *node, void *data2)
Marek Lindner7aadf882011-02-18 12:28:09 +000044{
Antonio Quartulli2dafb492011-05-05 08:42:45 +020045 void *data1 = container_of(node, struct tt_global_entry, hash_entry);
Marek Lindner7aadf882011-02-18 12:28:09 +000046
47 return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
48}
49
Antonio Quartulli2dafb492011-05-05 08:42:45 +020050static void tt_local_start_timer(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000051{
Antonio Quartulli2dafb492011-05-05 08:42:45 +020052 INIT_DELAYED_WORK(&bat_priv->tt_work, tt_local_purge);
53 queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work, 10 * HZ);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000054}
55
Antonio Quartulli2dafb492011-05-05 08:42:45 +020056static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
Marek Lindner7aadf882011-02-18 12:28:09 +000057 void *data)
58{
Antonio Quartulli2dafb492011-05-05 08:42:45 +020059 struct hashtable_t *hash = bat_priv->tt_local_hash;
Marek Lindner7aadf882011-02-18 12:28:09 +000060 struct hlist_head *head;
61 struct hlist_node *node;
Antonio Quartulli2dafb492011-05-05 08:42:45 +020062 struct tt_local_entry *tt_local_entry, *tt_local_entry_tmp = NULL;
Marek Lindner7aadf882011-02-18 12:28:09 +000063 int index;
64
65 if (!hash)
66 return NULL;
67
68 index = choose_orig(data, hash->size);
69 head = &hash->table[index];
70
71 rcu_read_lock();
Antonio Quartulli2dafb492011-05-05 08:42:45 +020072 hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) {
73 if (!compare_eth(tt_local_entry, data))
Marek Lindner7aadf882011-02-18 12:28:09 +000074 continue;
75
Antonio Quartulli2dafb492011-05-05 08:42:45 +020076 tt_local_entry_tmp = tt_local_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +000077 break;
78 }
79 rcu_read_unlock();
80
Antonio Quartulli2dafb492011-05-05 08:42:45 +020081 return tt_local_entry_tmp;
Marek Lindner7aadf882011-02-18 12:28:09 +000082}
83
Antonio Quartulli2dafb492011-05-05 08:42:45 +020084static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
Marek Lindner7aadf882011-02-18 12:28:09 +000085 void *data)
86{
Antonio Quartulli2dafb492011-05-05 08:42:45 +020087 struct hashtable_t *hash = bat_priv->tt_global_hash;
Marek Lindner7aadf882011-02-18 12:28:09 +000088 struct hlist_head *head;
89 struct hlist_node *node;
Antonio Quartulli2dafb492011-05-05 08:42:45 +020090 struct tt_global_entry *tt_global_entry;
91 struct tt_global_entry *tt_global_entry_tmp = NULL;
Marek Lindner7aadf882011-02-18 12:28:09 +000092 int index;
93
94 if (!hash)
95 return NULL;
96
97 index = choose_orig(data, hash->size);
98 head = &hash->table[index];
99
100 rcu_read_lock();
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200101 hlist_for_each_entry_rcu(tt_global_entry, node, head, hash_entry) {
102 if (!compare_eth(tt_global_entry, data))
Marek Lindner7aadf882011-02-18 12:28:09 +0000103 continue;
104
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200105 tt_global_entry_tmp = tt_global_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +0000106 break;
107 }
108 rcu_read_unlock();
109
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200110 return tt_global_entry_tmp;
Marek Lindner7aadf882011-02-18 12:28:09 +0000111}
112
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200113int tt_local_init(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000114{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200115 if (bat_priv->tt_local_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000116 return 1;
117
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200118 bat_priv->tt_local_hash = hash_new(1024);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000119
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200120 if (!bat_priv->tt_local_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000121 return 0;
122
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200123 atomic_set(&bat_priv->tt_local_changed, 0);
124 tt_local_start_timer(bat_priv);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000125
126 return 1;
127}
128
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200129void tt_local_add(struct net_device *soft_iface, uint8_t *addr)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000130{
131 struct bat_priv *bat_priv = netdev_priv(soft_iface);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200132 struct tt_local_entry *tt_local_entry;
133 struct tt_global_entry *tt_global_entry;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000134 int required_bytes;
135
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200136 spin_lock_bh(&bat_priv->tt_lhash_lock);
137 tt_local_entry = tt_local_hash_find(bat_priv, addr);
138 spin_unlock_bh(&bat_priv->tt_lhash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000139
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200140 if (tt_local_entry) {
141 tt_local_entry->last_seen = jiffies;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000142 return;
143 }
144
145 /* only announce as many hosts as possible in the batman-packet and
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200146 space in batman_packet->num_tt That also should give a limit to
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000147 MAC-flooding. */
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200148 required_bytes = (bat_priv->num_local_tt + 1) * ETH_ALEN;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000149 required_bytes += BAT_PACKET_LEN;
150
151 if ((required_bytes > ETH_DATA_LEN) ||
152 (atomic_read(&bat_priv->aggregated_ogms) &&
153 required_bytes > MAX_AGGREGATION_BYTES) ||
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200154 (bat_priv->num_local_tt + 1 > 255)) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000155 bat_dbg(DBG_ROUTES, bat_priv,
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200156 "Can't add new local tt entry (%pM): "
157 "number of local tt entries exceeds packet size\n",
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000158 addr);
159 return;
160 }
161
162 bat_dbg(DBG_ROUTES, bat_priv,
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200163 "Creating new local tt entry: %pM\n", addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000164
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200165 tt_local_entry = kmalloc(sizeof(struct tt_local_entry), GFP_ATOMIC);
166 if (!tt_local_entry)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000167 return;
168
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200169 memcpy(tt_local_entry->addr, addr, ETH_ALEN);
170 tt_local_entry->last_seen = jiffies;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000171
172 /* the batman interface mac address should never be purged */
Marek Lindner39901e72011-02-18 12:28:08 +0000173 if (compare_eth(addr, soft_iface->dev_addr))
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200174 tt_local_entry->never_purge = 1;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000175 else
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200176 tt_local_entry->never_purge = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000177
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200178 spin_lock_bh(&bat_priv->tt_lhash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000179
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200180 hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
181 tt_local_entry, &tt_local_entry->hash_entry);
182 bat_priv->num_local_tt++;
183 atomic_set(&bat_priv->tt_local_changed, 1);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000184
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200185 spin_unlock_bh(&bat_priv->tt_lhash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000186
187 /* remove address from global hash if present */
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200188 spin_lock_bh(&bat_priv->tt_ghash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000189
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200190 tt_global_entry = tt_global_hash_find(bat_priv, addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000191
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200192 if (tt_global_entry)
193 _tt_global_del_orig(bat_priv, tt_global_entry,
194 "local tt received");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000195
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200196 spin_unlock_bh(&bat_priv->tt_ghash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000197}
198
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200199int tt_local_fill_buffer(struct bat_priv *bat_priv,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000200 unsigned char *buff, int buff_len)
201{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200202 struct hashtable_t *hash = bat_priv->tt_local_hash;
203 struct tt_local_entry *tt_local_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +0000204 struct hlist_node *node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000205 struct hlist_head *head;
Marek Lindner7aadf882011-02-18 12:28:09 +0000206 int i, count = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000207
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200208 spin_lock_bh(&bat_priv->tt_lhash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000209
210 for (i = 0; i < hash->size; i++) {
211 head = &hash->table[i];
212
Marek Lindner7aadf882011-02-18 12:28:09 +0000213 rcu_read_lock();
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200214 hlist_for_each_entry_rcu(tt_local_entry, node,
Marek Lindner7aadf882011-02-18 12:28:09 +0000215 head, hash_entry) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000216 if (buff_len < (count + 1) * ETH_ALEN)
217 break;
218
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200219 memcpy(buff + (count * ETH_ALEN), tt_local_entry->addr,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000220 ETH_ALEN);
221
222 count++;
223 }
Marek Lindner7aadf882011-02-18 12:28:09 +0000224 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000225 }
226
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200227 /* if we did not get all new local tts see you next time ;-) */
228 if (count == bat_priv->num_local_tt)
229 atomic_set(&bat_priv->tt_local_changed, 0);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000230
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200231 spin_unlock_bh(&bat_priv->tt_lhash_lock);
Sven Eckelmann53320fe2010-12-20 10:32:03 -0800232 return count;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000233}
234
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200235int tt_local_seq_print_text(struct seq_file *seq, void *offset)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000236{
237 struct net_device *net_dev = (struct net_device *)seq->private;
238 struct bat_priv *bat_priv = netdev_priv(net_dev);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200239 struct hashtable_t *hash = bat_priv->tt_local_hash;
240 struct tt_local_entry *tt_local_entry;
Marek Lindner32ae9b22011-04-20 15:40:58 +0200241 struct hard_iface *primary_if;
Marek Lindner7aadf882011-02-18 12:28:09 +0000242 struct hlist_node *node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000243 struct hlist_head *head;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000244 size_t buf_size, pos;
245 char *buff;
Marek Lindner32ae9b22011-04-20 15:40:58 +0200246 int i, ret = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000247
Marek Lindner32ae9b22011-04-20 15:40:58 +0200248 primary_if = primary_if_get_selected(bat_priv);
249 if (!primary_if) {
250 ret = seq_printf(seq, "BATMAN mesh %s disabled - "
251 "please specify interfaces to enable it\n",
252 net_dev->name);
253 goto out;
254 }
255
256 if (primary_if->if_status != IF_ACTIVE) {
257 ret = seq_printf(seq, "BATMAN mesh %s disabled - "
258 "primary interface not active\n",
259 net_dev->name);
260 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000261 }
262
263 seq_printf(seq, "Locally retrieved addresses (from %s) "
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200264 "announced via TT:\n",
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000265 net_dev->name);
266
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200267 spin_lock_bh(&bat_priv->tt_lhash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000268
269 buf_size = 1;
270 /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
271 for (i = 0; i < hash->size; i++) {
272 head = &hash->table[i];
273
Marek Lindner7aadf882011-02-18 12:28:09 +0000274 rcu_read_lock();
275 __hlist_for_each_rcu(node, head)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000276 buf_size += 21;
Marek Lindner7aadf882011-02-18 12:28:09 +0000277 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000278 }
279
280 buff = kmalloc(buf_size, GFP_ATOMIC);
281 if (!buff) {
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200282 spin_unlock_bh(&bat_priv->tt_lhash_lock);
Marek Lindner32ae9b22011-04-20 15:40:58 +0200283 ret = -ENOMEM;
284 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000285 }
Marek Lindner7aadf882011-02-18 12:28:09 +0000286
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000287 buff[0] = '\0';
288 pos = 0;
289
290 for (i = 0; i < hash->size; i++) {
291 head = &hash->table[i];
292
Marek Lindner7aadf882011-02-18 12:28:09 +0000293 rcu_read_lock();
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200294 hlist_for_each_entry_rcu(tt_local_entry, node,
Marek Lindner7aadf882011-02-18 12:28:09 +0000295 head, hash_entry) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000296 pos += snprintf(buff + pos, 22, " * %pM\n",
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200297 tt_local_entry->addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000298 }
Marek Lindner7aadf882011-02-18 12:28:09 +0000299 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000300 }
301
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200302 spin_unlock_bh(&bat_priv->tt_lhash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000303
304 seq_printf(seq, "%s", buff);
305 kfree(buff);
Marek Lindner32ae9b22011-04-20 15:40:58 +0200306out:
307 if (primary_if)
308 hardif_free_ref(primary_if);
309 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000310}
311
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200312static void _tt_local_del(struct hlist_node *node, void *arg)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000313{
314 struct bat_priv *bat_priv = (struct bat_priv *)arg;
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200315 void *data = container_of(node, struct tt_local_entry, hash_entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000316
317 kfree(data);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200318 bat_priv->num_local_tt--;
319 atomic_set(&bat_priv->tt_local_changed, 1);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000320}
321
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200322static void tt_local_del(struct bat_priv *bat_priv,
323 struct tt_local_entry *tt_local_entry,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000324 char *message)
325{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200326 bat_dbg(DBG_ROUTES, bat_priv, "Deleting local tt entry (%pM): %s\n",
327 tt_local_entry->addr, message);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000328
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200329 hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig,
330 tt_local_entry->addr);
331 _tt_local_del(&tt_local_entry->hash_entry, bat_priv);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000332}
333
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200334void tt_local_remove(struct bat_priv *bat_priv,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000335 uint8_t *addr, char *message)
336{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200337 struct tt_local_entry *tt_local_entry;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000338
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200339 spin_lock_bh(&bat_priv->tt_lhash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000340
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200341 tt_local_entry = tt_local_hash_find(bat_priv, addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000342
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200343 if (tt_local_entry)
344 tt_local_del(bat_priv, tt_local_entry, message);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000345
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200346 spin_unlock_bh(&bat_priv->tt_lhash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000347}
348
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200349static void tt_local_purge(struct work_struct *work)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000350{
351 struct delayed_work *delayed_work =
352 container_of(work, struct delayed_work, work);
353 struct bat_priv *bat_priv =
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200354 container_of(delayed_work, struct bat_priv, tt_work);
355 struct hashtable_t *hash = bat_priv->tt_local_hash;
356 struct tt_local_entry *tt_local_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +0000357 struct hlist_node *node, *node_tmp;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000358 struct hlist_head *head;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000359 unsigned long timeout;
Marek Lindner7aadf882011-02-18 12:28:09 +0000360 int i;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000361
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200362 spin_lock_bh(&bat_priv->tt_lhash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000363
364 for (i = 0; i < hash->size; i++) {
365 head = &hash->table[i];
366
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200367 hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
Marek Lindner7aadf882011-02-18 12:28:09 +0000368 head, hash_entry) {
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200369 if (tt_local_entry->never_purge)
Marek Lindner7aadf882011-02-18 12:28:09 +0000370 continue;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000371
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200372 timeout = tt_local_entry->last_seen;
373 timeout += TT_LOCAL_TIMEOUT * HZ;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000374
Marek Lindner7aadf882011-02-18 12:28:09 +0000375 if (time_before(jiffies, timeout))
376 continue;
377
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200378 tt_local_del(bat_priv, tt_local_entry,
Marek Lindner7aadf882011-02-18 12:28:09 +0000379 "address timed out");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000380 }
381 }
382
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200383 spin_unlock_bh(&bat_priv->tt_lhash_lock);
384 tt_local_start_timer(bat_priv);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000385}
386
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200387void tt_local_free(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000388{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200389 if (!bat_priv->tt_local_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000390 return;
391
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200392 cancel_delayed_work_sync(&bat_priv->tt_work);
393 hash_delete(bat_priv->tt_local_hash, _tt_local_del, bat_priv);
394 bat_priv->tt_local_hash = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000395}
396
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200397int tt_global_init(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000398{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200399 if (bat_priv->tt_global_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000400 return 1;
401
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200402 bat_priv->tt_global_hash = hash_new(1024);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000403
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200404 if (!bat_priv->tt_global_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000405 return 0;
406
407 return 1;
408}
409
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200410void tt_global_add_orig(struct bat_priv *bat_priv,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000411 struct orig_node *orig_node,
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200412 unsigned char *tt_buff, int tt_buff_len)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000413{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200414 struct tt_global_entry *tt_global_entry;
415 struct tt_local_entry *tt_local_entry;
416 int tt_buff_count = 0;
417 unsigned char *tt_ptr;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000418
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200419 while ((tt_buff_count + 1) * ETH_ALEN <= tt_buff_len) {
420 spin_lock_bh(&bat_priv->tt_ghash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000421
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200422 tt_ptr = tt_buff + (tt_buff_count * ETH_ALEN);
423 tt_global_entry = tt_global_hash_find(bat_priv, tt_ptr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000424
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200425 if (!tt_global_entry) {
426 spin_unlock_bh(&bat_priv->tt_ghash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000427
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200428 tt_global_entry =
429 kmalloc(sizeof(struct tt_global_entry),
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000430 GFP_ATOMIC);
431
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200432 if (!tt_global_entry)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000433 break;
434
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200435 memcpy(tt_global_entry->addr, tt_ptr, ETH_ALEN);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000436
437 bat_dbg(DBG_ROUTES, bat_priv,
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200438 "Creating new global tt entry: "
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000439 "%pM (via %pM)\n",
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200440 tt_global_entry->addr, orig_node->orig);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000441
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200442 spin_lock_bh(&bat_priv->tt_ghash_lock);
443 hash_add(bat_priv->tt_global_hash, compare_gtt,
444 choose_orig, tt_global_entry,
445 &tt_global_entry->hash_entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000446
447 }
448
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200449 tt_global_entry->orig_node = orig_node;
450 spin_unlock_bh(&bat_priv->tt_ghash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000451
452 /* remove address from local hash if present */
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200453 spin_lock_bh(&bat_priv->tt_lhash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000454
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200455 tt_ptr = tt_buff + (tt_buff_count * ETH_ALEN);
456 tt_local_entry = tt_local_hash_find(bat_priv, tt_ptr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000457
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200458 if (tt_local_entry)
459 tt_local_del(bat_priv, tt_local_entry,
460 "global tt received");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000461
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200462 spin_unlock_bh(&bat_priv->tt_lhash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000463
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200464 tt_buff_count++;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000465 }
466
467 /* initialize, and overwrite if malloc succeeds */
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200468 orig_node->tt_buff = NULL;
469 orig_node->tt_buff_len = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000470
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200471 if (tt_buff_len > 0) {
472 orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
473 if (orig_node->tt_buff) {
474 memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
475 orig_node->tt_buff_len = tt_buff_len;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000476 }
477 }
478}
479
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200480int tt_global_seq_print_text(struct seq_file *seq, void *offset)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000481{
482 struct net_device *net_dev = (struct net_device *)seq->private;
483 struct bat_priv *bat_priv = netdev_priv(net_dev);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200484 struct hashtable_t *hash = bat_priv->tt_global_hash;
485 struct tt_global_entry *tt_global_entry;
Marek Lindner32ae9b22011-04-20 15:40:58 +0200486 struct hard_iface *primary_if;
Marek Lindner7aadf882011-02-18 12:28:09 +0000487 struct hlist_node *node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000488 struct hlist_head *head;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000489 size_t buf_size, pos;
490 char *buff;
Marek Lindner32ae9b22011-04-20 15:40:58 +0200491 int i, ret = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000492
Marek Lindner32ae9b22011-04-20 15:40:58 +0200493 primary_if = primary_if_get_selected(bat_priv);
494 if (!primary_if) {
495 ret = seq_printf(seq, "BATMAN mesh %s disabled - please "
496 "specify interfaces to enable it\n",
497 net_dev->name);
498 goto out;
499 }
500
501 if (primary_if->if_status != IF_ACTIVE) {
502 ret = seq_printf(seq, "BATMAN mesh %s disabled - "
503 "primary interface not active\n",
504 net_dev->name);
505 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000506 }
507
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200508 seq_printf(seq,
509 "Globally announced TT entries received via the mesh %s\n",
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000510 net_dev->name);
511
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200512 spin_lock_bh(&bat_priv->tt_ghash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000513
514 buf_size = 1;
515 /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/
516 for (i = 0; i < hash->size; i++) {
517 head = &hash->table[i];
518
Marek Lindner7aadf882011-02-18 12:28:09 +0000519 rcu_read_lock();
520 __hlist_for_each_rcu(node, head)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000521 buf_size += 43;
Marek Lindner7aadf882011-02-18 12:28:09 +0000522 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000523 }
524
525 buff = kmalloc(buf_size, GFP_ATOMIC);
526 if (!buff) {
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200527 spin_unlock_bh(&bat_priv->tt_ghash_lock);
Marek Lindner32ae9b22011-04-20 15:40:58 +0200528 ret = -ENOMEM;
529 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000530 }
531 buff[0] = '\0';
532 pos = 0;
533
534 for (i = 0; i < hash->size; i++) {
535 head = &hash->table[i];
536
Marek Lindner7aadf882011-02-18 12:28:09 +0000537 rcu_read_lock();
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200538 hlist_for_each_entry_rcu(tt_global_entry, node,
Marek Lindner7aadf882011-02-18 12:28:09 +0000539 head, hash_entry) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000540 pos += snprintf(buff + pos, 44,
541 " * %pM via %pM\n",
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200542 tt_global_entry->addr,
543 tt_global_entry->orig_node->orig);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000544 }
Marek Lindner7aadf882011-02-18 12:28:09 +0000545 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000546 }
547
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200548 spin_unlock_bh(&bat_priv->tt_ghash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000549
550 seq_printf(seq, "%s", buff);
551 kfree(buff);
Marek Lindner32ae9b22011-04-20 15:40:58 +0200552out:
553 if (primary_if)
554 hardif_free_ref(primary_if);
555 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000556}
557
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200558static void _tt_global_del_orig(struct bat_priv *bat_priv,
559 struct tt_global_entry *tt_global_entry,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000560 char *message)
561{
562 bat_dbg(DBG_ROUTES, bat_priv,
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200563 "Deleting global tt entry %pM (via %pM): %s\n",
564 tt_global_entry->addr, tt_global_entry->orig_node->orig,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000565 message);
566
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200567 hash_remove(bat_priv->tt_global_hash, compare_gtt, choose_orig,
568 tt_global_entry->addr);
569 kfree(tt_global_entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000570}
571
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200572void tt_global_del_orig(struct bat_priv *bat_priv,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000573 struct orig_node *orig_node, char *message)
574{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200575 struct tt_global_entry *tt_global_entry;
576 int tt_buff_count = 0;
577 unsigned char *tt_ptr;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000578
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200579 if (orig_node->tt_buff_len == 0)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000580 return;
581
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200582 spin_lock_bh(&bat_priv->tt_ghash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000583
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200584 while ((tt_buff_count + 1) * ETH_ALEN <= orig_node->tt_buff_len) {
585 tt_ptr = orig_node->tt_buff + (tt_buff_count * ETH_ALEN);
586 tt_global_entry = tt_global_hash_find(bat_priv, tt_ptr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000587
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200588 if ((tt_global_entry) &&
589 (tt_global_entry->orig_node == orig_node))
590 _tt_global_del_orig(bat_priv, tt_global_entry,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000591 message);
592
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200593 tt_buff_count++;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000594 }
595
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200596 spin_unlock_bh(&bat_priv->tt_ghash_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000597
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200598 orig_node->tt_buff_len = 0;
599 kfree(orig_node->tt_buff);
600 orig_node->tt_buff = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000601}
602
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200603static void tt_global_del(struct hlist_node *node, void *arg)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000604{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200605 void *data = container_of(node, struct tt_global_entry, hash_entry);
Marek Lindner7aadf882011-02-18 12:28:09 +0000606
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000607 kfree(data);
608}
609
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200610void tt_global_free(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000611{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200612 if (!bat_priv->tt_global_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000613 return;
614
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200615 hash_delete(bat_priv->tt_global_hash, tt_global_del, NULL);
616 bat_priv->tt_global_hash = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000617}
618
619struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr)
620{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200621 struct tt_global_entry *tt_global_entry;
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000622 struct orig_node *orig_node = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000623
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200624 spin_lock_bh(&bat_priv->tt_ghash_lock);
625 tt_global_entry = tt_global_hash_find(bat_priv, addr);
Marek Lindner7aadf882011-02-18 12:28:09 +0000626
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200627 if (!tt_global_entry)
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000628 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000629
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200630 if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000631 goto out;
632
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200633 orig_node = tt_global_entry->orig_node;
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000634
635out:
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200636 spin_unlock_bh(&bat_priv->tt_ghash_lock);
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000637 return orig_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000638}