blob: 5f28a7f0b03e234f8e505191d6b487fc4154cd18 [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"
Antonio Quartullia73105b2011-04-27 14:27:44 +020026#include "send.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000027#include "hash.h"
28#include "originator.h"
Antonio Quartullia73105b2011-04-27 14:27:44 +020029#include "routing.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000030
Antonio Quartullia73105b2011-04-27 14:27:44 +020031#include <linux/crc16.h>
32
33static void _tt_global_del(struct bat_priv *bat_priv,
34 struct tt_global_entry *tt_global_entry,
35 const char *message);
36static void tt_purge(struct work_struct *work);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000037
Marek Lindner7aadf882011-02-18 12:28:09 +000038/* returns 1 if they are the same mac addr */
Sven Eckelmann747e4222011-05-14 23:14:50 +020039static int compare_ltt(const struct hlist_node *node, const void *data2)
Marek Lindner7aadf882011-02-18 12:28:09 +000040{
Sven Eckelmann747e4222011-05-14 23:14:50 +020041 const void *data1 = container_of(node, struct tt_local_entry,
42 hash_entry);
Marek Lindner7aadf882011-02-18 12:28:09 +000043
44 return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
45}
46
47/* returns 1 if they are the same mac addr */
Sven Eckelmann747e4222011-05-14 23:14:50 +020048static int compare_gtt(const struct hlist_node *node, const void *data2)
Marek Lindner7aadf882011-02-18 12:28:09 +000049{
Sven Eckelmann747e4222011-05-14 23:14:50 +020050 const void *data1 = container_of(node, struct tt_global_entry,
51 hash_entry);
Marek Lindner7aadf882011-02-18 12:28:09 +000052
53 return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
54}
55
Antonio Quartullia73105b2011-04-27 14:27:44 +020056static void tt_start_timer(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000057{
Antonio Quartullia73105b2011-04-27 14:27:44 +020058 INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge);
59 queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work,
60 msecs_to_jiffies(5000));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000061}
62
Antonio Quartulli2dafb492011-05-05 08:42:45 +020063static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
Sven Eckelmann747e4222011-05-14 23:14:50 +020064 const void *data)
Marek Lindner7aadf882011-02-18 12:28:09 +000065{
Antonio Quartulli2dafb492011-05-05 08:42:45 +020066 struct hashtable_t *hash = bat_priv->tt_local_hash;
Marek Lindner7aadf882011-02-18 12:28:09 +000067 struct hlist_head *head;
68 struct hlist_node *node;
Antonio Quartulli2dafb492011-05-05 08:42:45 +020069 struct tt_local_entry *tt_local_entry, *tt_local_entry_tmp = NULL;
Antonio Quartullic90681b2011-10-05 17:05:25 +020070 uint32_t index;
Marek Lindner7aadf882011-02-18 12:28:09 +000071
72 if (!hash)
73 return NULL;
74
75 index = choose_orig(data, hash->size);
76 head = &hash->table[index];
77
78 rcu_read_lock();
Antonio Quartulli2dafb492011-05-05 08:42:45 +020079 hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) {
80 if (!compare_eth(tt_local_entry, data))
Marek Lindner7aadf882011-02-18 12:28:09 +000081 continue;
82
Antonio Quartulli7683fdc2011-04-27 14:28:07 +020083 if (!atomic_inc_not_zero(&tt_local_entry->refcount))
84 continue;
85
Antonio Quartulli2dafb492011-05-05 08:42:45 +020086 tt_local_entry_tmp = tt_local_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +000087 break;
88 }
89 rcu_read_unlock();
90
Antonio Quartulli2dafb492011-05-05 08:42:45 +020091 return tt_local_entry_tmp;
Marek Lindner7aadf882011-02-18 12:28:09 +000092}
93
Antonio Quartulli2dafb492011-05-05 08:42:45 +020094static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
Sven Eckelmann747e4222011-05-14 23:14:50 +020095 const void *data)
Marek Lindner7aadf882011-02-18 12:28:09 +000096{
Antonio Quartulli2dafb492011-05-05 08:42:45 +020097 struct hashtable_t *hash = bat_priv->tt_global_hash;
Marek Lindner7aadf882011-02-18 12:28:09 +000098 struct hlist_head *head;
99 struct hlist_node *node;
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200100 struct tt_global_entry *tt_global_entry;
101 struct tt_global_entry *tt_global_entry_tmp = NULL;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200102 uint32_t index;
Marek Lindner7aadf882011-02-18 12:28:09 +0000103
104 if (!hash)
105 return NULL;
106
107 index = choose_orig(data, hash->size);
108 head = &hash->table[index];
109
110 rcu_read_lock();
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200111 hlist_for_each_entry_rcu(tt_global_entry, node, head, hash_entry) {
112 if (!compare_eth(tt_global_entry, data))
Marek Lindner7aadf882011-02-18 12:28:09 +0000113 continue;
114
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200115 if (!atomic_inc_not_zero(&tt_global_entry->refcount))
116 continue;
117
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200118 tt_global_entry_tmp = tt_global_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +0000119 break;
120 }
121 rcu_read_unlock();
122
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200123 return tt_global_entry_tmp;
Marek Lindner7aadf882011-02-18 12:28:09 +0000124}
125
Antonio Quartullia73105b2011-04-27 14:27:44 +0200126static bool is_out_of_time(unsigned long starting_time, unsigned long timeout)
127{
128 unsigned long deadline;
129 deadline = starting_time + msecs_to_jiffies(timeout);
130
131 return time_after(jiffies, deadline);
132}
133
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200134static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
135{
136 if (atomic_dec_and_test(&tt_local_entry->refcount))
137 kfree_rcu(tt_local_entry, rcu);
138}
139
Simon Wunderlich531027f2011-10-19 11:02:25 +0200140static void tt_global_entry_free_rcu(struct rcu_head *rcu)
141{
142 struct tt_global_entry *tt_global_entry;
143
144 tt_global_entry = container_of(rcu, struct tt_global_entry, rcu);
145
146 if (tt_global_entry->orig_node)
147 orig_node_free_ref(tt_global_entry->orig_node);
148
149 kfree(tt_global_entry);
150}
151
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200152static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
153{
154 if (atomic_dec_and_test(&tt_global_entry->refcount))
Simon Wunderlich531027f2011-10-19 11:02:25 +0200155 call_rcu(&tt_global_entry->rcu, tt_global_entry_free_rcu);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200156}
157
Antonio Quartulliff66c972011-06-30 01:14:00 +0200158static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
159 uint8_t flags)
Antonio Quartullia73105b2011-04-27 14:27:44 +0200160{
161 struct tt_change_node *tt_change_node;
162
163 tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
164
165 if (!tt_change_node)
166 return;
167
Antonio Quartulliff66c972011-06-30 01:14:00 +0200168 tt_change_node->change.flags = flags;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200169 memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
170
171 spin_lock_bh(&bat_priv->tt_changes_list_lock);
172 /* track the change in the OGMinterval list */
173 list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list);
174 atomic_inc(&bat_priv->tt_local_changes);
175 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
176
177 atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
178}
179
180int tt_len(int changes_num)
181{
182 return changes_num * sizeof(struct tt_change);
183}
184
185static int tt_local_init(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000186{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200187 if (bat_priv->tt_local_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000188 return 1;
189
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200190 bat_priv->tt_local_hash = hash_new(1024);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000191
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200192 if (!bat_priv->tt_local_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000193 return 0;
194
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000195 return 1;
196}
197
Antonio Quartullibc279082011-07-07 15:35:35 +0200198void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
199 int ifindex)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000200{
201 struct bat_priv *bat_priv = netdev_priv(soft_iface);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200202 struct tt_local_entry *tt_local_entry = NULL;
203 struct tt_global_entry *tt_global_entry = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000204
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200205 tt_local_entry = tt_local_hash_find(bat_priv, addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000206
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200207 if (tt_local_entry) {
208 tt_local_entry->last_seen = jiffies;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200209 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000210 }
211
Sven Eckelmann704509b2011-05-14 23:14:54 +0200212 tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200213 if (!tt_local_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200214 goto out;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200215
Antonio Quartullia73105b2011-04-27 14:27:44 +0200216 bat_dbg(DBG_TT, bat_priv,
217 "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
218 (uint8_t)atomic_read(&bat_priv->ttvn));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000219
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200220 memcpy(tt_local_entry->addr, addr, ETH_ALEN);
221 tt_local_entry->last_seen = jiffies;
Antonio Quartulli5fbc1592011-06-17 16:11:27 +0200222 tt_local_entry->flags = NO_FLAGS;
Antonio Quartullibc279082011-07-07 15:35:35 +0200223 if (is_wifi_iface(ifindex))
224 tt_local_entry->flags |= TT_CLIENT_WIFI;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200225 atomic_set(&tt_local_entry->refcount, 2);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000226
227 /* the batman interface mac address should never be purged */
Marek Lindner39901e72011-02-18 12:28:08 +0000228 if (compare_eth(addr, soft_iface->dev_addr))
Antonio Quartulli5fbc1592011-06-17 16:11:27 +0200229 tt_local_entry->flags |= TT_CLIENT_NOPURGE;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000230
Antonio Quartulliff66c972011-06-30 01:14:00 +0200231 tt_local_event(bat_priv, addr, tt_local_entry->flags);
232
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200233 /* The local entry has to be marked as NEW to avoid to send it in
234 * a full table response going out before the next ttvn increment
235 * (consistency check) */
236 tt_local_entry->flags |= TT_CLIENT_NEW;
237
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200238 hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
239 tt_local_entry, &tt_local_entry->hash_entry);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200240
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000241 /* remove address from global hash if present */
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200242 tt_global_entry = tt_global_hash_find(bat_priv, addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000243
Antonio Quartullicc47f662011-04-27 14:27:57 +0200244 /* Check whether it is a roaming! */
245 if (tt_global_entry) {
Antonio Quartullicc47f662011-04-27 14:27:57 +0200246 /* This node is probably going to update its tt table */
247 tt_global_entry->orig_node->tt_poss_change = true;
Antonio Quartulli980d55b2011-07-07 01:40:59 +0200248 /* The global entry has to be marked as PENDING and has to be
249 * kept for consistency purpose */
250 tt_global_entry->flags |= TT_CLIENT_PENDING;
Antonio Quartullicc47f662011-04-27 14:27:57 +0200251 send_roam_adv(bat_priv, tt_global_entry->addr,
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200252 tt_global_entry->orig_node);
253 }
254out:
255 if (tt_local_entry)
256 tt_local_entry_free_ref(tt_local_entry);
257 if (tt_global_entry)
258 tt_global_entry_free_ref(tt_global_entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000259}
260
Antonio Quartullia73105b2011-04-27 14:27:44 +0200261int tt_changes_fill_buffer(struct bat_priv *bat_priv,
262 unsigned char *buff, int buff_len)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000263{
Antonio Quartullia73105b2011-04-27 14:27:44 +0200264 int count = 0, tot_changes = 0;
265 struct tt_change_node *entry, *safe;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000266
Antonio Quartullia73105b2011-04-27 14:27:44 +0200267 if (buff_len > 0)
268 tot_changes = buff_len / tt_len(1);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000269
Antonio Quartullia73105b2011-04-27 14:27:44 +0200270 spin_lock_bh(&bat_priv->tt_changes_list_lock);
271 atomic_set(&bat_priv->tt_local_changes, 0);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000272
Antonio Quartullia73105b2011-04-27 14:27:44 +0200273 list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
274 list) {
275 if (count < tot_changes) {
276 memcpy(buff + tt_len(count),
277 &entry->change, sizeof(struct tt_change));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000278 count++;
279 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200280 list_del(&entry->list);
281 kfree(entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000282 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200283 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000284
Antonio Quartullia73105b2011-04-27 14:27:44 +0200285 /* Keep the buffer for possible tt_request */
286 spin_lock_bh(&bat_priv->tt_buff_lock);
287 kfree(bat_priv->tt_buff);
288 bat_priv->tt_buff_len = 0;
289 bat_priv->tt_buff = NULL;
290 /* We check whether this new OGM has no changes due to size
291 * problems */
292 if (buff_len > 0) {
293 /**
294 * if kmalloc() fails we will reply with the full table
295 * instead of providing the diff
296 */
297 bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC);
298 if (bat_priv->tt_buff) {
299 memcpy(bat_priv->tt_buff, buff, buff_len);
300 bat_priv->tt_buff_len = buff_len;
301 }
302 }
303 spin_unlock_bh(&bat_priv->tt_buff_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000304
Antonio Quartullia73105b2011-04-27 14:27:44 +0200305 return tot_changes;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000306}
307
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200308int tt_local_seq_print_text(struct seq_file *seq, void *offset)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000309{
310 struct net_device *net_dev = (struct net_device *)seq->private;
311 struct bat_priv *bat_priv = netdev_priv(net_dev);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200312 struct hashtable_t *hash = bat_priv->tt_local_hash;
313 struct tt_local_entry *tt_local_entry;
Marek Lindner32ae9b22011-04-20 15:40:58 +0200314 struct hard_iface *primary_if;
Marek Lindner7aadf882011-02-18 12:28:09 +0000315 struct hlist_node *node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000316 struct hlist_head *head;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000317 size_t buf_size, pos;
318 char *buff;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200319 uint32_t i;
320 int ret = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000321
Marek Lindner32ae9b22011-04-20 15:40:58 +0200322 primary_if = primary_if_get_selected(bat_priv);
323 if (!primary_if) {
324 ret = seq_printf(seq, "BATMAN mesh %s disabled - "
325 "please specify interfaces to enable it\n",
326 net_dev->name);
327 goto out;
328 }
329
330 if (primary_if->if_status != IF_ACTIVE) {
331 ret = seq_printf(seq, "BATMAN mesh %s disabled - "
332 "primary interface not active\n",
333 net_dev->name);
334 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000335 }
336
337 seq_printf(seq, "Locally retrieved addresses (from %s) "
Antonio Quartullia73105b2011-04-27 14:27:44 +0200338 "announced via TT (TTVN: %u):\n",
339 net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000340
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000341 buf_size = 1;
342 /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
343 for (i = 0; i < hash->size; i++) {
344 head = &hash->table[i];
345
Marek Lindner7aadf882011-02-18 12:28:09 +0000346 rcu_read_lock();
347 __hlist_for_each_rcu(node, head)
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200348 buf_size += 29;
Marek Lindner7aadf882011-02-18 12:28:09 +0000349 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000350 }
351
352 buff = kmalloc(buf_size, GFP_ATOMIC);
353 if (!buff) {
Marek Lindner32ae9b22011-04-20 15:40:58 +0200354 ret = -ENOMEM;
355 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000356 }
Marek Lindner7aadf882011-02-18 12:28:09 +0000357
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000358 buff[0] = '\0';
359 pos = 0;
360
361 for (i = 0; i < hash->size; i++) {
362 head = &hash->table[i];
363
Marek Lindner7aadf882011-02-18 12:28:09 +0000364 rcu_read_lock();
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200365 hlist_for_each_entry_rcu(tt_local_entry, node,
Marek Lindner7aadf882011-02-18 12:28:09 +0000366 head, hash_entry) {
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200367 pos += snprintf(buff + pos, 30, " * %pM "
368 "[%c%c%c%c%c]\n",
369 tt_local_entry->addr,
370 (tt_local_entry->flags &
371 TT_CLIENT_ROAM ? 'R' : '.'),
372 (tt_local_entry->flags &
373 TT_CLIENT_NOPURGE ? 'P' : '.'),
374 (tt_local_entry->flags &
375 TT_CLIENT_NEW ? 'N' : '.'),
376 (tt_local_entry->flags &
377 TT_CLIENT_PENDING ? 'X' : '.'),
378 (tt_local_entry->flags &
379 TT_CLIENT_WIFI ? 'W' : '.'));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000380 }
Marek Lindner7aadf882011-02-18 12:28:09 +0000381 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000382 }
383
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000384 seq_printf(seq, "%s", buff);
385 kfree(buff);
Marek Lindner32ae9b22011-04-20 15:40:58 +0200386out:
387 if (primary_if)
388 hardif_free_ref(primary_if);
389 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000390}
391
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200392static void tt_local_set_pending(struct bat_priv *bat_priv,
393 struct tt_local_entry *tt_local_entry,
394 uint16_t flags)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000395{
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200396 tt_local_event(bat_priv, tt_local_entry->addr,
397 tt_local_entry->flags | flags);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000398
Antonio Quartulli015758d2011-07-09 17:52:13 +0200399 /* The local client has to be marked as "pending to be removed" but has
400 * to be kept in the table in order to send it in a full table
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200401 * response issued before the net ttvn increment (consistency check) */
402 tt_local_entry->flags |= TT_CLIENT_PENDING;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000403}
404
Antonio Quartullia73105b2011-04-27 14:27:44 +0200405void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
Antonio Quartullicc47f662011-04-27 14:27:57 +0200406 const char *message, bool roaming)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000407{
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200408 struct tt_local_entry *tt_local_entry = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000409
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200410 tt_local_entry = tt_local_hash_find(bat_priv, addr);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200411 if (!tt_local_entry)
412 goto out;
413
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200414 tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
415 (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
416
417 bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
418 "%s\n", tt_local_entry->addr, message);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200419out:
420 if (tt_local_entry)
421 tt_local_entry_free_ref(tt_local_entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000422}
423
Antonio Quartullia73105b2011-04-27 14:27:44 +0200424static void tt_local_purge(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000425{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200426 struct hashtable_t *hash = bat_priv->tt_local_hash;
427 struct tt_local_entry *tt_local_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +0000428 struct hlist_node *node, *node_tmp;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000429 struct hlist_head *head;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200430 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartullic90681b2011-10-05 17:05:25 +0200431 uint32_t i;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000432
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000433 for (i = 0; i < hash->size; i++) {
434 head = &hash->table[i];
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200435 list_lock = &hash->list_locks[i];
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000436
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200437 spin_lock_bh(list_lock);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200438 hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
Marek Lindner7aadf882011-02-18 12:28:09 +0000439 head, hash_entry) {
Antonio Quartulli5fbc1592011-06-17 16:11:27 +0200440 if (tt_local_entry->flags & TT_CLIENT_NOPURGE)
Marek Lindner7aadf882011-02-18 12:28:09 +0000441 continue;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000442
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200443 /* entry already marked for deletion */
444 if (tt_local_entry->flags & TT_CLIENT_PENDING)
445 continue;
446
Antonio Quartullia73105b2011-04-27 14:27:44 +0200447 if (!is_out_of_time(tt_local_entry->last_seen,
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200448 TT_LOCAL_TIMEOUT * 1000))
Marek Lindner7aadf882011-02-18 12:28:09 +0000449 continue;
450
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200451 tt_local_set_pending(bat_priv, tt_local_entry,
452 TT_CLIENT_DEL);
453 bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) "
454 "pending to be removed: timed out\n",
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200455 tt_local_entry->addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000456 }
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200457 spin_unlock_bh(list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000458 }
459
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000460}
461
Antonio Quartullia73105b2011-04-27 14:27:44 +0200462static void tt_local_table_free(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000463{
Antonio Quartullia73105b2011-04-27 14:27:44 +0200464 struct hashtable_t *hash;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200465 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartullia73105b2011-04-27 14:27:44 +0200466 struct tt_local_entry *tt_local_entry;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200467 struct hlist_node *node, *node_tmp;
468 struct hlist_head *head;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200469 uint32_t i;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200470
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200471 if (!bat_priv->tt_local_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000472 return;
473
Antonio Quartullia73105b2011-04-27 14:27:44 +0200474 hash = bat_priv->tt_local_hash;
475
476 for (i = 0; i < hash->size; i++) {
477 head = &hash->table[i];
478 list_lock = &hash->list_locks[i];
479
480 spin_lock_bh(list_lock);
481 hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
482 head, hash_entry) {
483 hlist_del_rcu(node);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200484 tt_local_entry_free_ref(tt_local_entry);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200485 }
486 spin_unlock_bh(list_lock);
487 }
488
489 hash_destroy(hash);
490
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200491 bat_priv->tt_local_hash = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000492}
493
Antonio Quartullia73105b2011-04-27 14:27:44 +0200494static int tt_global_init(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000495{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200496 if (bat_priv->tt_global_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000497 return 1;
498
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200499 bat_priv->tt_global_hash = hash_new(1024);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000500
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200501 if (!bat_priv->tt_global_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000502 return 0;
503
504 return 1;
505}
506
Antonio Quartullia73105b2011-04-27 14:27:44 +0200507static void tt_changes_list_free(struct bat_priv *bat_priv)
508{
509 struct tt_change_node *entry, *safe;
510
511 spin_lock_bh(&bat_priv->tt_changes_list_lock);
512
513 list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
514 list) {
515 list_del(&entry->list);
516 kfree(entry);
517 }
518
519 atomic_set(&bat_priv->tt_local_changes, 0);
520 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
521}
522
523/* caller must hold orig_node refcount */
524int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
Antonio Quartullibc279082011-07-07 15:35:35 +0200525 const unsigned char *tt_addr, uint8_t ttvn, bool roaming,
526 bool wifi)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000527{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200528 struct tt_global_entry *tt_global_entry;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200529 struct orig_node *orig_node_tmp;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200530 int ret = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000531
Antonio Quartullia73105b2011-04-27 14:27:44 +0200532 tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000533
Antonio Quartullia73105b2011-04-27 14:27:44 +0200534 if (!tt_global_entry) {
535 tt_global_entry =
536 kmalloc(sizeof(*tt_global_entry),
537 GFP_ATOMIC);
538 if (!tt_global_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200539 goto out;
540
Antonio Quartullia73105b2011-04-27 14:27:44 +0200541 memcpy(tt_global_entry->addr, tt_addr, ETH_ALEN);
542 /* Assign the new orig_node */
543 atomic_inc(&orig_node->refcount);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200544 tt_global_entry->orig_node = orig_node;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200545 tt_global_entry->ttvn = ttvn;
Antonio Quartullicc47f662011-04-27 14:27:57 +0200546 tt_global_entry->flags = NO_FLAGS;
547 tt_global_entry->roam_at = 0;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200548 atomic_set(&tt_global_entry->refcount, 2);
549
Antonio Quartullia73105b2011-04-27 14:27:44 +0200550 hash_add(bat_priv->tt_global_hash, compare_gtt,
551 choose_orig, tt_global_entry,
552 &tt_global_entry->hash_entry);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200553 atomic_inc(&orig_node->tt_size);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200554 } else {
555 if (tt_global_entry->orig_node != orig_node) {
556 atomic_dec(&tt_global_entry->orig_node->tt_size);
557 orig_node_tmp = tt_global_entry->orig_node;
558 atomic_inc(&orig_node->refcount);
559 tt_global_entry->orig_node = orig_node;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200560 orig_node_free_ref(orig_node_tmp);
561 atomic_inc(&orig_node->tt_size);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000562 }
Antonio Quartullicc47f662011-04-27 14:27:57 +0200563 tt_global_entry->ttvn = ttvn;
564 tt_global_entry->flags = NO_FLAGS;
565 tt_global_entry->roam_at = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000566 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200567
Antonio Quartullibc279082011-07-07 15:35:35 +0200568 if (wifi)
569 tt_global_entry->flags |= TT_CLIENT_WIFI;
570
Antonio Quartullia73105b2011-04-27 14:27:44 +0200571 bat_dbg(DBG_TT, bat_priv,
572 "Creating new global tt entry: %pM (via %pM)\n",
573 tt_global_entry->addr, orig_node->orig);
574
575 /* remove address from local hash if present */
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200576 tt_local_remove(bat_priv, tt_global_entry->addr,
577 "global tt received", roaming);
578 ret = 1;
579out:
580 if (tt_global_entry)
581 tt_global_entry_free_ref(tt_global_entry);
582 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000583}
584
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200585int tt_global_seq_print_text(struct seq_file *seq, void *offset)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000586{
587 struct net_device *net_dev = (struct net_device *)seq->private;
588 struct bat_priv *bat_priv = netdev_priv(net_dev);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200589 struct hashtable_t *hash = bat_priv->tt_global_hash;
590 struct tt_global_entry *tt_global_entry;
Marek Lindner32ae9b22011-04-20 15:40:58 +0200591 struct hard_iface *primary_if;
Marek Lindner7aadf882011-02-18 12:28:09 +0000592 struct hlist_node *node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000593 struct hlist_head *head;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000594 size_t buf_size, pos;
595 char *buff;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200596 uint32_t i;
597 int ret = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000598
Marek Lindner32ae9b22011-04-20 15:40:58 +0200599 primary_if = primary_if_get_selected(bat_priv);
600 if (!primary_if) {
601 ret = seq_printf(seq, "BATMAN mesh %s disabled - please "
602 "specify interfaces to enable it\n",
603 net_dev->name);
604 goto out;
605 }
606
607 if (primary_if->if_status != IF_ACTIVE) {
608 ret = seq_printf(seq, "BATMAN mesh %s disabled - "
609 "primary interface not active\n",
610 net_dev->name);
611 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000612 }
613
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200614 seq_printf(seq,
615 "Globally announced TT entries received via the mesh %s\n",
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000616 net_dev->name);
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200617 seq_printf(seq, " %-13s %s %-15s %s %s\n",
618 "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000619
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000620 buf_size = 1;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200621 /* Estimate length for: " * xx:xx:xx:xx:xx:xx (ttvn) via
622 * xx:xx:xx:xx:xx:xx (cur_ttvn)\n"*/
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000623 for (i = 0; i < hash->size; i++) {
624 head = &hash->table[i];
625
Marek Lindner7aadf882011-02-18 12:28:09 +0000626 rcu_read_lock();
627 __hlist_for_each_rcu(node, head)
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200628 buf_size += 67;
Marek Lindner7aadf882011-02-18 12:28:09 +0000629 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000630 }
631
632 buff = kmalloc(buf_size, GFP_ATOMIC);
633 if (!buff) {
Marek Lindner32ae9b22011-04-20 15:40:58 +0200634 ret = -ENOMEM;
635 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000636 }
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200637
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000638 buff[0] = '\0';
639 pos = 0;
640
641 for (i = 0; i < hash->size; i++) {
642 head = &hash->table[i];
643
Marek Lindner7aadf882011-02-18 12:28:09 +0000644 rcu_read_lock();
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200645 hlist_for_each_entry_rcu(tt_global_entry, node,
Marek Lindner7aadf882011-02-18 12:28:09 +0000646 head, hash_entry) {
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200647 pos += snprintf(buff + pos, 69,
648 " * %pM (%3u) via %pM (%3u) "
649 "[%c%c%c]\n", tt_global_entry->addr,
Antonio Quartullia73105b2011-04-27 14:27:44 +0200650 tt_global_entry->ttvn,
651 tt_global_entry->orig_node->orig,
652 (uint8_t) atomic_read(
653 &tt_global_entry->orig_node->
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200654 last_ttvn),
655 (tt_global_entry->flags &
656 TT_CLIENT_ROAM ? 'R' : '.'),
657 (tt_global_entry->flags &
658 TT_CLIENT_PENDING ? 'X' : '.'),
659 (tt_global_entry->flags &
660 TT_CLIENT_WIFI ? 'W' : '.'));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000661 }
Marek Lindner7aadf882011-02-18 12:28:09 +0000662 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000663 }
664
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000665 seq_printf(seq, "%s", buff);
666 kfree(buff);
Marek Lindner32ae9b22011-04-20 15:40:58 +0200667out:
668 if (primary_if)
669 hardif_free_ref(primary_if);
670 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000671}
672
Antonio Quartullia73105b2011-04-27 14:27:44 +0200673static void _tt_global_del(struct bat_priv *bat_priv,
674 struct tt_global_entry *tt_global_entry,
675 const char *message)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000676{
Antonio Quartullia73105b2011-04-27 14:27:44 +0200677 if (!tt_global_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200678 goto out;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200679
680 bat_dbg(DBG_TT, bat_priv,
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200681 "Deleting global tt entry %pM (via %pM): %s\n",
682 tt_global_entry->addr, tt_global_entry->orig_node->orig,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000683 message);
684
Antonio Quartullia73105b2011-04-27 14:27:44 +0200685 atomic_dec(&tt_global_entry->orig_node->tt_size);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200686
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200687 hash_remove(bat_priv->tt_global_hash, compare_gtt, choose_orig,
688 tt_global_entry->addr);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200689out:
690 if (tt_global_entry)
691 tt_global_entry_free_ref(tt_global_entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000692}
693
Antonio Quartullia73105b2011-04-27 14:27:44 +0200694void tt_global_del(struct bat_priv *bat_priv,
695 struct orig_node *orig_node, const unsigned char *addr,
Antonio Quartullicc47f662011-04-27 14:27:57 +0200696 const char *message, bool roaming)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000697{
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200698 struct tt_global_entry *tt_global_entry = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000699
Antonio Quartullia73105b2011-04-27 14:27:44 +0200700 tt_global_entry = tt_global_hash_find(bat_priv, addr);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200701 if (!tt_global_entry)
702 goto out;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200703
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200704 if (tt_global_entry->orig_node == orig_node) {
Antonio Quartullicc47f662011-04-27 14:27:57 +0200705 if (roaming) {
706 tt_global_entry->flags |= TT_CLIENT_ROAM;
707 tt_global_entry->roam_at = jiffies;
708 goto out;
709 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200710 _tt_global_del(bat_priv, tt_global_entry, message);
711 }
Antonio Quartullicc47f662011-04-27 14:27:57 +0200712out:
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200713 if (tt_global_entry)
714 tt_global_entry_free_ref(tt_global_entry);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200715}
716
717void tt_global_del_orig(struct bat_priv *bat_priv,
718 struct orig_node *orig_node, const char *message)
719{
720 struct tt_global_entry *tt_global_entry;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200721 uint32_t i;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200722 struct hashtable_t *hash = bat_priv->tt_global_hash;
723 struct hlist_node *node, *safe;
724 struct hlist_head *head;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200725 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartullia73105b2011-04-27 14:27:44 +0200726
Simon Wunderlich6e801492011-10-19 10:28:26 +0200727 if (!hash)
728 return;
729
Antonio Quartullia73105b2011-04-27 14:27:44 +0200730 for (i = 0; i < hash->size; i++) {
731 head = &hash->table[i];
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200732 list_lock = &hash->list_locks[i];
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000733
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200734 spin_lock_bh(list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200735 hlist_for_each_entry_safe(tt_global_entry, node, safe,
736 head, hash_entry) {
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200737 if (tt_global_entry->orig_node == orig_node) {
738 bat_dbg(DBG_TT, bat_priv,
739 "Deleting global tt entry %pM "
Antonio Quartulli87944972011-09-19 12:29:19 +0200740 "(via %pM): %s\n",
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200741 tt_global_entry->addr,
Antonio Quartulli87944972011-09-19 12:29:19 +0200742 tt_global_entry->orig_node->orig,
743 message);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200744 hlist_del_rcu(node);
745 tt_global_entry_free_ref(tt_global_entry);
746 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200747 }
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200748 spin_unlock_bh(list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000749 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200750 atomic_set(&orig_node->tt_size, 0);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000751}
752
Antonio Quartullicc47f662011-04-27 14:27:57 +0200753static void tt_global_roam_purge(struct bat_priv *bat_priv)
754{
755 struct hashtable_t *hash = bat_priv->tt_global_hash;
756 struct tt_global_entry *tt_global_entry;
757 struct hlist_node *node, *node_tmp;
758 struct hlist_head *head;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200759 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartullic90681b2011-10-05 17:05:25 +0200760 uint32_t i;
Antonio Quartullicc47f662011-04-27 14:27:57 +0200761
Antonio Quartullicc47f662011-04-27 14:27:57 +0200762 for (i = 0; i < hash->size; i++) {
763 head = &hash->table[i];
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200764 list_lock = &hash->list_locks[i];
Antonio Quartullicc47f662011-04-27 14:27:57 +0200765
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200766 spin_lock_bh(list_lock);
Antonio Quartullicc47f662011-04-27 14:27:57 +0200767 hlist_for_each_entry_safe(tt_global_entry, node, node_tmp,
768 head, hash_entry) {
769 if (!(tt_global_entry->flags & TT_CLIENT_ROAM))
770 continue;
771 if (!is_out_of_time(tt_global_entry->roam_at,
772 TT_CLIENT_ROAM_TIMEOUT * 1000))
773 continue;
774
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200775 bat_dbg(DBG_TT, bat_priv, "Deleting global "
776 "tt entry (%pM): Roaming timeout\n",
777 tt_global_entry->addr);
778 atomic_dec(&tt_global_entry->orig_node->tt_size);
779 hlist_del_rcu(node);
780 tt_global_entry_free_ref(tt_global_entry);
Antonio Quartullicc47f662011-04-27 14:27:57 +0200781 }
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200782 spin_unlock_bh(list_lock);
Antonio Quartullicc47f662011-04-27 14:27:57 +0200783 }
784
Antonio Quartullicc47f662011-04-27 14:27:57 +0200785}
786
Antonio Quartullia73105b2011-04-27 14:27:44 +0200787static void tt_global_table_free(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000788{
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200789 struct hashtable_t *hash;
790 spinlock_t *list_lock; /* protects write access to the hash lists */
791 struct tt_global_entry *tt_global_entry;
792 struct hlist_node *node, *node_tmp;
793 struct hlist_head *head;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200794 uint32_t i;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200795
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200796 if (!bat_priv->tt_global_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000797 return;
798
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200799 hash = bat_priv->tt_global_hash;
800
801 for (i = 0; i < hash->size; i++) {
802 head = &hash->table[i];
803 list_lock = &hash->list_locks[i];
804
805 spin_lock_bh(list_lock);
806 hlist_for_each_entry_safe(tt_global_entry, node, node_tmp,
807 head, hash_entry) {
808 hlist_del_rcu(node);
809 tt_global_entry_free_ref(tt_global_entry);
810 }
811 spin_unlock_bh(list_lock);
812 }
813
814 hash_destroy(hash);
815
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200816 bat_priv->tt_global_hash = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000817}
818
Antonio Quartulli59b699c2011-07-07 15:35:36 +0200819static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
820 struct tt_global_entry *tt_global_entry)
821{
822 bool ret = false;
823
824 if (tt_local_entry->flags & TT_CLIENT_WIFI &&
825 tt_global_entry->flags & TT_CLIENT_WIFI)
826 ret = true;
827
828 return ret;
829}
830
Sven Eckelmann747e4222011-05-14 23:14:50 +0200831struct orig_node *transtable_search(struct bat_priv *bat_priv,
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200832 const uint8_t *src, const uint8_t *addr)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000833{
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200834 struct tt_local_entry *tt_local_entry = NULL;
835 struct tt_global_entry *tt_global_entry = NULL;
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000836 struct orig_node *orig_node = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000837
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200838 if (src && atomic_read(&bat_priv->ap_isolation)) {
839 tt_local_entry = tt_local_hash_find(bat_priv, src);
840 if (!tt_local_entry)
841 goto out;
842 }
Marek Lindner7aadf882011-02-18 12:28:09 +0000843
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200844 tt_global_entry = tt_global_hash_find(bat_priv, addr);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200845 if (!tt_global_entry)
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000846 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000847
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200848 /* check whether the clients should not communicate due to AP
849 * isolation */
850 if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry))
851 goto out;
852
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200853 if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200854 goto out;
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000855
Antonio Quartulli980d55b2011-07-07 01:40:59 +0200856 /* A global client marked as PENDING has already moved from that
857 * originator */
858 if (tt_global_entry->flags & TT_CLIENT_PENDING)
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200859 goto out;
Antonio Quartulli980d55b2011-07-07 01:40:59 +0200860
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200861 orig_node = tt_global_entry->orig_node;
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000862
863out:
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200864 if (tt_global_entry)
865 tt_global_entry_free_ref(tt_global_entry);
866 if (tt_local_entry)
867 tt_local_entry_free_ref(tt_local_entry);
868
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000869 return orig_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000870}
Antonio Quartullia73105b2011-04-27 14:27:44 +0200871
872/* Calculates the checksum of the local table of a given orig_node */
873uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
874{
875 uint16_t total = 0, total_one;
876 struct hashtable_t *hash = bat_priv->tt_global_hash;
877 struct tt_global_entry *tt_global_entry;
878 struct hlist_node *node;
879 struct hlist_head *head;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200880 uint32_t i;
881 int j;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200882
883 for (i = 0; i < hash->size; i++) {
884 head = &hash->table[i];
885
886 rcu_read_lock();
887 hlist_for_each_entry_rcu(tt_global_entry, node,
888 head, hash_entry) {
889 if (compare_eth(tt_global_entry->orig_node,
890 orig_node)) {
Antonio Quartullicc47f662011-04-27 14:27:57 +0200891 /* Roaming clients are in the global table for
892 * consistency only. They don't have to be
893 * taken into account while computing the
894 * global crc */
895 if (tt_global_entry->flags & TT_CLIENT_ROAM)
896 continue;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200897 total_one = 0;
898 for (j = 0; j < ETH_ALEN; j++)
899 total_one = crc16_byte(total_one,
900 tt_global_entry->addr[j]);
901 total ^= total_one;
902 }
903 }
904 rcu_read_unlock();
905 }
906
907 return total;
908}
909
910/* Calculates the checksum of the local table */
911uint16_t tt_local_crc(struct bat_priv *bat_priv)
912{
913 uint16_t total = 0, total_one;
914 struct hashtable_t *hash = bat_priv->tt_local_hash;
915 struct tt_local_entry *tt_local_entry;
916 struct hlist_node *node;
917 struct hlist_head *head;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200918 uint32_t i;
919 int j;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200920
921 for (i = 0; i < hash->size; i++) {
922 head = &hash->table[i];
923
924 rcu_read_lock();
925 hlist_for_each_entry_rcu(tt_local_entry, node,
926 head, hash_entry) {
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200927 /* not yet committed clients have not to be taken into
928 * account while computing the CRC */
929 if (tt_local_entry->flags & TT_CLIENT_NEW)
930 continue;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200931 total_one = 0;
932 for (j = 0; j < ETH_ALEN; j++)
933 total_one = crc16_byte(total_one,
934 tt_local_entry->addr[j]);
935 total ^= total_one;
936 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200937 rcu_read_unlock();
938 }
939
940 return total;
941}
942
943static void tt_req_list_free(struct bat_priv *bat_priv)
944{
945 struct tt_req_node *node, *safe;
946
947 spin_lock_bh(&bat_priv->tt_req_list_lock);
948
949 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
950 list_del(&node->list);
951 kfree(node);
952 }
953
954 spin_unlock_bh(&bat_priv->tt_req_list_lock);
955}
956
957void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
958 const unsigned char *tt_buff, uint8_t tt_num_changes)
959{
960 uint16_t tt_buff_len = tt_len(tt_num_changes);
961
962 /* Replace the old buffer only if I received something in the
963 * last OGM (the OGM could carry no changes) */
964 spin_lock_bh(&orig_node->tt_buff_lock);
965 if (tt_buff_len > 0) {
966 kfree(orig_node->tt_buff);
967 orig_node->tt_buff_len = 0;
968 orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
969 if (orig_node->tt_buff) {
970 memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
971 orig_node->tt_buff_len = tt_buff_len;
972 }
973 }
974 spin_unlock_bh(&orig_node->tt_buff_lock);
975}
976
977static void tt_req_purge(struct bat_priv *bat_priv)
978{
979 struct tt_req_node *node, *safe;
980
981 spin_lock_bh(&bat_priv->tt_req_list_lock);
982 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
983 if (is_out_of_time(node->issued_at,
984 TT_REQUEST_TIMEOUT * 1000)) {
985 list_del(&node->list);
986 kfree(node);
987 }
988 }
989 spin_unlock_bh(&bat_priv->tt_req_list_lock);
990}
991
992/* returns the pointer to the new tt_req_node struct if no request
993 * has already been issued for this orig_node, NULL otherwise */
994static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
995 struct orig_node *orig_node)
996{
997 struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
998
999 spin_lock_bh(&bat_priv->tt_req_list_lock);
1000 list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) {
1001 if (compare_eth(tt_req_node_tmp, orig_node) &&
1002 !is_out_of_time(tt_req_node_tmp->issued_at,
1003 TT_REQUEST_TIMEOUT * 1000))
1004 goto unlock;
1005 }
1006
1007 tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
1008 if (!tt_req_node)
1009 goto unlock;
1010
1011 memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
1012 tt_req_node->issued_at = jiffies;
1013
1014 list_add(&tt_req_node->list, &bat_priv->tt_req_list);
1015unlock:
1016 spin_unlock_bh(&bat_priv->tt_req_list_lock);
1017 return tt_req_node;
1018}
1019
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001020/* data_ptr is useless here, but has to be kept to respect the prototype */
1021static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
1022{
1023 const struct tt_local_entry *tt_local_entry = entry_ptr;
1024
1025 if (tt_local_entry->flags & TT_CLIENT_NEW)
1026 return 0;
1027 return 1;
1028}
1029
Antonio Quartullia73105b2011-04-27 14:27:44 +02001030static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
1031{
1032 const struct tt_global_entry *tt_global_entry = entry_ptr;
1033 const struct orig_node *orig_node = data_ptr;
1034
Antonio Quartullicc47f662011-04-27 14:27:57 +02001035 if (tt_global_entry->flags & TT_CLIENT_ROAM)
1036 return 0;
1037
Antonio Quartullia73105b2011-04-27 14:27:44 +02001038 return (tt_global_entry->orig_node == orig_node);
1039}
1040
1041static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
1042 struct hashtable_t *hash,
1043 struct hard_iface *primary_if,
1044 int (*valid_cb)(const void *,
1045 const void *),
1046 void *cb_data)
1047{
1048 struct tt_local_entry *tt_local_entry;
1049 struct tt_query_packet *tt_response;
1050 struct tt_change *tt_change;
1051 struct hlist_node *node;
1052 struct hlist_head *head;
1053 struct sk_buff *skb = NULL;
1054 uint16_t tt_tot, tt_count;
1055 ssize_t tt_query_size = sizeof(struct tt_query_packet);
Antonio Quartullic90681b2011-10-05 17:05:25 +02001056 uint32_t i;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001057
1058 if (tt_query_size + tt_len > primary_if->soft_iface->mtu) {
1059 tt_len = primary_if->soft_iface->mtu - tt_query_size;
1060 tt_len -= tt_len % sizeof(struct tt_change);
1061 }
1062 tt_tot = tt_len / sizeof(struct tt_change);
1063
1064 skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN);
1065 if (!skb)
1066 goto out;
1067
1068 skb_reserve(skb, ETH_HLEN);
1069 tt_response = (struct tt_query_packet *)skb_put(skb,
1070 tt_query_size + tt_len);
1071 tt_response->ttvn = ttvn;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001072
1073 tt_change = (struct tt_change *)(skb->data + tt_query_size);
1074 tt_count = 0;
1075
1076 rcu_read_lock();
1077 for (i = 0; i < hash->size; i++) {
1078 head = &hash->table[i];
1079
1080 hlist_for_each_entry_rcu(tt_local_entry, node,
1081 head, hash_entry) {
1082 if (tt_count == tt_tot)
1083 break;
1084
1085 if ((valid_cb) && (!valid_cb(tt_local_entry, cb_data)))
1086 continue;
1087
1088 memcpy(tt_change->addr, tt_local_entry->addr, ETH_ALEN);
1089 tt_change->flags = NO_FLAGS;
1090
1091 tt_count++;
1092 tt_change++;
1093 }
1094 }
1095 rcu_read_unlock();
1096
Antonio Quartulli9d852392011-10-17 14:25:13 +02001097 /* store in the message the number of entries we have successfully
1098 * copied */
1099 tt_response->tt_data = htons(tt_count);
1100
Antonio Quartullia73105b2011-04-27 14:27:44 +02001101out:
1102 return skb;
1103}
1104
Marek Lindnera943cac2011-07-30 13:10:18 +02001105static int send_tt_request(struct bat_priv *bat_priv,
1106 struct orig_node *dst_orig_node,
1107 uint8_t ttvn, uint16_t tt_crc, bool full_table)
Antonio Quartullia73105b2011-04-27 14:27:44 +02001108{
1109 struct sk_buff *skb = NULL;
1110 struct tt_query_packet *tt_request;
1111 struct neigh_node *neigh_node = NULL;
1112 struct hard_iface *primary_if;
1113 struct tt_req_node *tt_req_node = NULL;
1114 int ret = 1;
1115
1116 primary_if = primary_if_get_selected(bat_priv);
1117 if (!primary_if)
1118 goto out;
1119
1120 /* The new tt_req will be issued only if I'm not waiting for a
1121 * reply from the same orig_node yet */
1122 tt_req_node = new_tt_req_node(bat_priv, dst_orig_node);
1123 if (!tt_req_node)
1124 goto out;
1125
1126 skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN);
1127 if (!skb)
1128 goto out;
1129
1130 skb_reserve(skb, ETH_HLEN);
1131
1132 tt_request = (struct tt_query_packet *)skb_put(skb,
1133 sizeof(struct tt_query_packet));
1134
1135 tt_request->packet_type = BAT_TT_QUERY;
1136 tt_request->version = COMPAT_VERSION;
1137 memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1138 memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN);
1139 tt_request->ttl = TTL;
1140 tt_request->ttvn = ttvn;
1141 tt_request->tt_data = tt_crc;
1142 tt_request->flags = TT_REQUEST;
1143
1144 if (full_table)
1145 tt_request->flags |= TT_FULL_TABLE;
1146
1147 neigh_node = orig_node_get_router(dst_orig_node);
1148 if (!neigh_node)
1149 goto out;
1150
1151 bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM "
1152 "[%c]\n", dst_orig_node->orig, neigh_node->addr,
1153 (full_table ? 'F' : '.'));
1154
1155 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1156 ret = 0;
1157
1158out:
1159 if (neigh_node)
1160 neigh_node_free_ref(neigh_node);
1161 if (primary_if)
1162 hardif_free_ref(primary_if);
1163 if (ret)
1164 kfree_skb(skb);
1165 if (ret && tt_req_node) {
1166 spin_lock_bh(&bat_priv->tt_req_list_lock);
1167 list_del(&tt_req_node->list);
1168 spin_unlock_bh(&bat_priv->tt_req_list_lock);
1169 kfree(tt_req_node);
1170 }
1171 return ret;
1172}
1173
1174static bool send_other_tt_response(struct bat_priv *bat_priv,
1175 struct tt_query_packet *tt_request)
1176{
1177 struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL;
1178 struct neigh_node *neigh_node = NULL;
1179 struct hard_iface *primary_if = NULL;
1180 uint8_t orig_ttvn, req_ttvn, ttvn;
1181 int ret = false;
1182 unsigned char *tt_buff;
1183 bool full_table;
1184 uint16_t tt_len, tt_tot;
1185 struct sk_buff *skb = NULL;
1186 struct tt_query_packet *tt_response;
1187
1188 bat_dbg(DBG_TT, bat_priv,
1189 "Received TT_REQUEST from %pM for "
1190 "ttvn: %u (%pM) [%c]\n", tt_request->src,
1191 tt_request->ttvn, tt_request->dst,
1192 (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1193
1194 /* Let's get the orig node of the REAL destination */
Antonio Quartullieb7e2a12011-10-12 14:54:50 +02001195 req_dst_orig_node = orig_hash_find(bat_priv, tt_request->dst);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001196 if (!req_dst_orig_node)
1197 goto out;
1198
Antonio Quartullieb7e2a12011-10-12 14:54:50 +02001199 res_dst_orig_node = orig_hash_find(bat_priv, tt_request->src);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001200 if (!res_dst_orig_node)
1201 goto out;
1202
1203 neigh_node = orig_node_get_router(res_dst_orig_node);
1204 if (!neigh_node)
1205 goto out;
1206
1207 primary_if = primary_if_get_selected(bat_priv);
1208 if (!primary_if)
1209 goto out;
1210
1211 orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1212 req_ttvn = tt_request->ttvn;
1213
Antonio Quartulli015758d2011-07-09 17:52:13 +02001214 /* I don't have the requested data */
Antonio Quartullia73105b2011-04-27 14:27:44 +02001215 if (orig_ttvn != req_ttvn ||
1216 tt_request->tt_data != req_dst_orig_node->tt_crc)
1217 goto out;
1218
Antonio Quartulli015758d2011-07-09 17:52:13 +02001219 /* If the full table has been explicitly requested */
Antonio Quartullia73105b2011-04-27 14:27:44 +02001220 if (tt_request->flags & TT_FULL_TABLE ||
1221 !req_dst_orig_node->tt_buff)
1222 full_table = true;
1223 else
1224 full_table = false;
1225
1226 /* In this version, fragmentation is not implemented, then
1227 * I'll send only one packet with as much TT entries as I can */
1228 if (!full_table) {
1229 spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
1230 tt_len = req_dst_orig_node->tt_buff_len;
1231 tt_tot = tt_len / sizeof(struct tt_change);
1232
1233 skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1234 tt_len + ETH_HLEN);
1235 if (!skb)
1236 goto unlock;
1237
1238 skb_reserve(skb, ETH_HLEN);
1239 tt_response = (struct tt_query_packet *)skb_put(skb,
1240 sizeof(struct tt_query_packet) + tt_len);
1241 tt_response->ttvn = req_ttvn;
1242 tt_response->tt_data = htons(tt_tot);
1243
1244 tt_buff = skb->data + sizeof(struct tt_query_packet);
1245 /* Copy the last orig_node's OGM buffer */
1246 memcpy(tt_buff, req_dst_orig_node->tt_buff,
1247 req_dst_orig_node->tt_buff_len);
1248
1249 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1250 } else {
1251 tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) *
1252 sizeof(struct tt_change);
1253 ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1254
1255 skb = tt_response_fill_table(tt_len, ttvn,
1256 bat_priv->tt_global_hash,
1257 primary_if, tt_global_valid_entry,
1258 req_dst_orig_node);
1259 if (!skb)
1260 goto out;
1261
1262 tt_response = (struct tt_query_packet *)skb->data;
1263 }
1264
1265 tt_response->packet_type = BAT_TT_QUERY;
1266 tt_response->version = COMPAT_VERSION;
1267 tt_response->ttl = TTL;
1268 memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN);
1269 memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1270 tt_response->flags = TT_RESPONSE;
1271
1272 if (full_table)
1273 tt_response->flags |= TT_FULL_TABLE;
1274
1275 bat_dbg(DBG_TT, bat_priv,
1276 "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n",
1277 res_dst_orig_node->orig, neigh_node->addr,
1278 req_dst_orig_node->orig, req_ttvn);
1279
1280 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1281 ret = true;
1282 goto out;
1283
1284unlock:
1285 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1286
1287out:
1288 if (res_dst_orig_node)
1289 orig_node_free_ref(res_dst_orig_node);
1290 if (req_dst_orig_node)
1291 orig_node_free_ref(req_dst_orig_node);
1292 if (neigh_node)
1293 neigh_node_free_ref(neigh_node);
1294 if (primary_if)
1295 hardif_free_ref(primary_if);
1296 if (!ret)
1297 kfree_skb(skb);
1298 return ret;
1299
1300}
1301static bool send_my_tt_response(struct bat_priv *bat_priv,
1302 struct tt_query_packet *tt_request)
1303{
1304 struct orig_node *orig_node = NULL;
1305 struct neigh_node *neigh_node = NULL;
1306 struct hard_iface *primary_if = NULL;
1307 uint8_t my_ttvn, req_ttvn, ttvn;
1308 int ret = false;
1309 unsigned char *tt_buff;
1310 bool full_table;
1311 uint16_t tt_len, tt_tot;
1312 struct sk_buff *skb = NULL;
1313 struct tt_query_packet *tt_response;
1314
1315 bat_dbg(DBG_TT, bat_priv,
1316 "Received TT_REQUEST from %pM for "
1317 "ttvn: %u (me) [%c]\n", tt_request->src,
1318 tt_request->ttvn,
1319 (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1320
1321
1322 my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1323 req_ttvn = tt_request->ttvn;
1324
Antonio Quartullieb7e2a12011-10-12 14:54:50 +02001325 orig_node = orig_hash_find(bat_priv, tt_request->src);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001326 if (!orig_node)
1327 goto out;
1328
1329 neigh_node = orig_node_get_router(orig_node);
1330 if (!neigh_node)
1331 goto out;
1332
1333 primary_if = primary_if_get_selected(bat_priv);
1334 if (!primary_if)
1335 goto out;
1336
1337 /* If the full table has been explicitly requested or the gap
1338 * is too big send the whole local translation table */
1339 if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn ||
1340 !bat_priv->tt_buff)
1341 full_table = true;
1342 else
1343 full_table = false;
1344
1345 /* In this version, fragmentation is not implemented, then
1346 * I'll send only one packet with as much TT entries as I can */
1347 if (!full_table) {
1348 spin_lock_bh(&bat_priv->tt_buff_lock);
1349 tt_len = bat_priv->tt_buff_len;
1350 tt_tot = tt_len / sizeof(struct tt_change);
1351
1352 skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1353 tt_len + ETH_HLEN);
1354 if (!skb)
1355 goto unlock;
1356
1357 skb_reserve(skb, ETH_HLEN);
1358 tt_response = (struct tt_query_packet *)skb_put(skb,
1359 sizeof(struct tt_query_packet) + tt_len);
1360 tt_response->ttvn = req_ttvn;
1361 tt_response->tt_data = htons(tt_tot);
1362
1363 tt_buff = skb->data + sizeof(struct tt_query_packet);
1364 memcpy(tt_buff, bat_priv->tt_buff,
1365 bat_priv->tt_buff_len);
1366 spin_unlock_bh(&bat_priv->tt_buff_lock);
1367 } else {
1368 tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) *
1369 sizeof(struct tt_change);
1370 ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1371
1372 skb = tt_response_fill_table(tt_len, ttvn,
1373 bat_priv->tt_local_hash,
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001374 primary_if, tt_local_valid_entry,
1375 NULL);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001376 if (!skb)
1377 goto out;
1378
1379 tt_response = (struct tt_query_packet *)skb->data;
1380 }
1381
1382 tt_response->packet_type = BAT_TT_QUERY;
1383 tt_response->version = COMPAT_VERSION;
1384 tt_response->ttl = TTL;
1385 memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1386 memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1387 tt_response->flags = TT_RESPONSE;
1388
1389 if (full_table)
1390 tt_response->flags |= TT_FULL_TABLE;
1391
1392 bat_dbg(DBG_TT, bat_priv,
1393 "Sending TT_RESPONSE to %pM via %pM [%c]\n",
1394 orig_node->orig, neigh_node->addr,
1395 (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1396
1397 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1398 ret = true;
1399 goto out;
1400
1401unlock:
1402 spin_unlock_bh(&bat_priv->tt_buff_lock);
1403out:
1404 if (orig_node)
1405 orig_node_free_ref(orig_node);
1406 if (neigh_node)
1407 neigh_node_free_ref(neigh_node);
1408 if (primary_if)
1409 hardif_free_ref(primary_if);
1410 if (!ret)
1411 kfree_skb(skb);
1412 /* This packet was for me, so it doesn't need to be re-routed */
1413 return true;
1414}
1415
1416bool send_tt_response(struct bat_priv *bat_priv,
1417 struct tt_query_packet *tt_request)
1418{
1419 if (is_my_mac(tt_request->dst))
1420 return send_my_tt_response(bat_priv, tt_request);
1421 else
1422 return send_other_tt_response(bat_priv, tt_request);
1423}
1424
1425static void _tt_update_changes(struct bat_priv *bat_priv,
1426 struct orig_node *orig_node,
1427 struct tt_change *tt_change,
1428 uint16_t tt_num_changes, uint8_t ttvn)
1429{
1430 int i;
1431
1432 for (i = 0; i < tt_num_changes; i++) {
Antonio Quartulli5fbc1592011-06-17 16:11:27 +02001433 if ((tt_change + i)->flags & TT_CLIENT_DEL)
Antonio Quartullia73105b2011-04-27 14:27:44 +02001434 tt_global_del(bat_priv, orig_node,
1435 (tt_change + i)->addr,
Antonio Quartullicc47f662011-04-27 14:27:57 +02001436 "tt removed by changes",
1437 (tt_change + i)->flags & TT_CLIENT_ROAM);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001438 else
1439 if (!tt_global_add(bat_priv, orig_node,
Antonio Quartullibc279082011-07-07 15:35:35 +02001440 (tt_change + i)->addr, ttvn, false,
1441 (tt_change + i)->flags &
1442 TT_CLIENT_WIFI))
Antonio Quartullia73105b2011-04-27 14:27:44 +02001443 /* In case of problem while storing a
1444 * global_entry, we stop the updating
1445 * procedure without committing the
1446 * ttvn change. This will avoid to send
1447 * corrupted data on tt_request
1448 */
1449 return;
1450 }
1451}
1452
1453static void tt_fill_gtable(struct bat_priv *bat_priv,
1454 struct tt_query_packet *tt_response)
1455{
1456 struct orig_node *orig_node = NULL;
1457
1458 orig_node = orig_hash_find(bat_priv, tt_response->src);
1459 if (!orig_node)
1460 goto out;
1461
1462 /* Purge the old table first.. */
1463 tt_global_del_orig(bat_priv, orig_node, "Received full table");
1464
1465 _tt_update_changes(bat_priv, orig_node,
1466 (struct tt_change *)(tt_response + 1),
1467 tt_response->tt_data, tt_response->ttvn);
1468
1469 spin_lock_bh(&orig_node->tt_buff_lock);
1470 kfree(orig_node->tt_buff);
1471 orig_node->tt_buff_len = 0;
1472 orig_node->tt_buff = NULL;
1473 spin_unlock_bh(&orig_node->tt_buff_lock);
1474
1475 atomic_set(&orig_node->last_ttvn, tt_response->ttvn);
1476
1477out:
1478 if (orig_node)
1479 orig_node_free_ref(orig_node);
1480}
1481
Marek Lindnera943cac2011-07-30 13:10:18 +02001482static void tt_update_changes(struct bat_priv *bat_priv,
1483 struct orig_node *orig_node,
1484 uint16_t tt_num_changes, uint8_t ttvn,
1485 struct tt_change *tt_change)
Antonio Quartullia73105b2011-04-27 14:27:44 +02001486{
1487 _tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes,
1488 ttvn);
1489
1490 tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change,
1491 tt_num_changes);
1492 atomic_set(&orig_node->last_ttvn, ttvn);
1493}
1494
1495bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
1496{
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001497 struct tt_local_entry *tt_local_entry = NULL;
1498 bool ret = false;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001499
Antonio Quartullia73105b2011-04-27 14:27:44 +02001500 tt_local_entry = tt_local_hash_find(bat_priv, addr);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001501 if (!tt_local_entry)
1502 goto out;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001503 /* Check if the client has been logically deleted (but is kept for
1504 * consistency purpose) */
1505 if (tt_local_entry->flags & TT_CLIENT_PENDING)
1506 goto out;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001507 ret = true;
1508out:
Antonio Quartullia73105b2011-04-27 14:27:44 +02001509 if (tt_local_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001510 tt_local_entry_free_ref(tt_local_entry);
1511 return ret;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001512}
1513
1514void handle_tt_response(struct bat_priv *bat_priv,
1515 struct tt_query_packet *tt_response)
1516{
1517 struct tt_req_node *node, *safe;
1518 struct orig_node *orig_node = NULL;
1519
1520 bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for "
1521 "ttvn %d t_size: %d [%c]\n",
1522 tt_response->src, tt_response->ttvn,
1523 tt_response->tt_data,
1524 (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1525
1526 orig_node = orig_hash_find(bat_priv, tt_response->src);
1527 if (!orig_node)
1528 goto out;
1529
1530 if (tt_response->flags & TT_FULL_TABLE)
1531 tt_fill_gtable(bat_priv, tt_response);
1532 else
1533 tt_update_changes(bat_priv, orig_node, tt_response->tt_data,
1534 tt_response->ttvn,
1535 (struct tt_change *)(tt_response + 1));
1536
1537 /* Delete the tt_req_node from pending tt_requests list */
1538 spin_lock_bh(&bat_priv->tt_req_list_lock);
1539 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
1540 if (!compare_eth(node->addr, tt_response->src))
1541 continue;
1542 list_del(&node->list);
1543 kfree(node);
1544 }
1545 spin_unlock_bh(&bat_priv->tt_req_list_lock);
1546
1547 /* Recalculate the CRC for this orig_node and store it */
Antonio Quartullia73105b2011-04-27 14:27:44 +02001548 orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
Antonio Quartullicc47f662011-04-27 14:27:57 +02001549 /* Roaming phase is over: tables are in sync again. I can
1550 * unset the flag */
1551 orig_node->tt_poss_change = false;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001552out:
1553 if (orig_node)
1554 orig_node_free_ref(orig_node);
1555}
1556
1557int tt_init(struct bat_priv *bat_priv)
1558{
1559 if (!tt_local_init(bat_priv))
1560 return 0;
1561
1562 if (!tt_global_init(bat_priv))
1563 return 0;
1564
1565 tt_start_timer(bat_priv);
1566
1567 return 1;
1568}
1569
Antonio Quartullicc47f662011-04-27 14:27:57 +02001570static void tt_roam_list_free(struct bat_priv *bat_priv)
Antonio Quartullia73105b2011-04-27 14:27:44 +02001571{
Antonio Quartullicc47f662011-04-27 14:27:57 +02001572 struct tt_roam_node *node, *safe;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001573
Antonio Quartullicc47f662011-04-27 14:27:57 +02001574 spin_lock_bh(&bat_priv->tt_roam_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001575
Antonio Quartullicc47f662011-04-27 14:27:57 +02001576 list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1577 list_del(&node->list);
1578 kfree(node);
1579 }
1580
1581 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1582}
1583
1584static void tt_roam_purge(struct bat_priv *bat_priv)
1585{
1586 struct tt_roam_node *node, *safe;
1587
1588 spin_lock_bh(&bat_priv->tt_roam_list_lock);
1589 list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1590 if (!is_out_of_time(node->first_time,
1591 ROAMING_MAX_TIME * 1000))
1592 continue;
1593
1594 list_del(&node->list);
1595 kfree(node);
1596 }
1597 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1598}
1599
1600/* This function checks whether the client already reached the
1601 * maximum number of possible roaming phases. In this case the ROAMING_ADV
1602 * will not be sent.
1603 *
1604 * returns true if the ROAMING_ADV can be sent, false otherwise */
1605static bool tt_check_roam_count(struct bat_priv *bat_priv,
1606 uint8_t *client)
1607{
1608 struct tt_roam_node *tt_roam_node;
1609 bool ret = false;
1610
1611 spin_lock_bh(&bat_priv->tt_roam_list_lock);
1612 /* The new tt_req will be issued only if I'm not waiting for a
1613 * reply from the same orig_node yet */
1614 list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) {
1615 if (!compare_eth(tt_roam_node->addr, client))
1616 continue;
1617
1618 if (is_out_of_time(tt_roam_node->first_time,
1619 ROAMING_MAX_TIME * 1000))
1620 continue;
1621
1622 if (!atomic_dec_not_zero(&tt_roam_node->counter))
1623 /* Sorry, you roamed too many times! */
1624 goto unlock;
1625 ret = true;
1626 break;
1627 }
1628
1629 if (!ret) {
1630 tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
1631 if (!tt_roam_node)
1632 goto unlock;
1633
1634 tt_roam_node->first_time = jiffies;
1635 atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1);
1636 memcpy(tt_roam_node->addr, client, ETH_ALEN);
1637
1638 list_add(&tt_roam_node->list, &bat_priv->tt_roam_list);
1639 ret = true;
1640 }
1641
1642unlock:
1643 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1644 return ret;
1645}
1646
1647void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
1648 struct orig_node *orig_node)
1649{
1650 struct neigh_node *neigh_node = NULL;
1651 struct sk_buff *skb = NULL;
1652 struct roam_adv_packet *roam_adv_packet;
1653 int ret = 1;
1654 struct hard_iface *primary_if;
1655
1656 /* before going on we have to check whether the client has
1657 * already roamed to us too many times */
1658 if (!tt_check_roam_count(bat_priv, client))
1659 goto out;
1660
1661 skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
1662 if (!skb)
1663 goto out;
1664
1665 skb_reserve(skb, ETH_HLEN);
1666
1667 roam_adv_packet = (struct roam_adv_packet *)skb_put(skb,
1668 sizeof(struct roam_adv_packet));
1669
1670 roam_adv_packet->packet_type = BAT_ROAM_ADV;
1671 roam_adv_packet->version = COMPAT_VERSION;
1672 roam_adv_packet->ttl = TTL;
1673 primary_if = primary_if_get_selected(bat_priv);
1674 if (!primary_if)
1675 goto out;
1676 memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1677 hardif_free_ref(primary_if);
1678 memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN);
1679 memcpy(roam_adv_packet->client, client, ETH_ALEN);
1680
1681 neigh_node = orig_node_get_router(orig_node);
1682 if (!neigh_node)
1683 goto out;
1684
1685 bat_dbg(DBG_TT, bat_priv,
1686 "Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
1687 orig_node->orig, client, neigh_node->addr);
1688
1689 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1690 ret = 0;
1691
1692out:
1693 if (neigh_node)
1694 neigh_node_free_ref(neigh_node);
1695 if (ret)
1696 kfree_skb(skb);
1697 return;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001698}
1699
1700static void tt_purge(struct work_struct *work)
1701{
1702 struct delayed_work *delayed_work =
1703 container_of(work, struct delayed_work, work);
1704 struct bat_priv *bat_priv =
1705 container_of(delayed_work, struct bat_priv, tt_work);
1706
1707 tt_local_purge(bat_priv);
Antonio Quartullicc47f662011-04-27 14:27:57 +02001708 tt_global_roam_purge(bat_priv);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001709 tt_req_purge(bat_priv);
Antonio Quartullicc47f662011-04-27 14:27:57 +02001710 tt_roam_purge(bat_priv);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001711
1712 tt_start_timer(bat_priv);
1713}
Antonio Quartullicc47f662011-04-27 14:27:57 +02001714
1715void tt_free(struct bat_priv *bat_priv)
1716{
1717 cancel_delayed_work_sync(&bat_priv->tt_work);
1718
1719 tt_local_table_free(bat_priv);
1720 tt_global_table_free(bat_priv);
1721 tt_req_list_free(bat_priv);
1722 tt_changes_list_free(bat_priv);
1723 tt_roam_list_free(bat_priv);
1724
1725 kfree(bat_priv->tt_buff);
1726}
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001727
1728/* This function will reset the specified flags from all the entries in
1729 * the given hash table and will increment num_local_tt for each involved
1730 * entry */
1731static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags)
1732{
Antonio Quartullic90681b2011-10-05 17:05:25 +02001733 uint32_t i;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001734 struct hashtable_t *hash = bat_priv->tt_local_hash;
1735 struct hlist_head *head;
1736 struct hlist_node *node;
1737 struct tt_local_entry *tt_local_entry;
1738
1739 if (!hash)
1740 return;
1741
1742 for (i = 0; i < hash->size; i++) {
1743 head = &hash->table[i];
1744
1745 rcu_read_lock();
1746 hlist_for_each_entry_rcu(tt_local_entry, node,
1747 head, hash_entry) {
Antonio Quartulli31901262011-10-16 18:53:37 +02001748 if (!(tt_local_entry->flags & flags))
1749 continue;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001750 tt_local_entry->flags &= ~flags;
1751 atomic_inc(&bat_priv->num_local_tt);
1752 }
1753 rcu_read_unlock();
1754 }
1755
1756}
1757
1758/* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
1759static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
1760{
1761 struct hashtable_t *hash = bat_priv->tt_local_hash;
1762 struct tt_local_entry *tt_local_entry;
1763 struct hlist_node *node, *node_tmp;
1764 struct hlist_head *head;
1765 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartullic90681b2011-10-05 17:05:25 +02001766 uint32_t i;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001767
1768 if (!hash)
1769 return;
1770
1771 for (i = 0; i < hash->size; i++) {
1772 head = &hash->table[i];
1773 list_lock = &hash->list_locks[i];
1774
1775 spin_lock_bh(list_lock);
1776 hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
1777 head, hash_entry) {
1778 if (!(tt_local_entry->flags & TT_CLIENT_PENDING))
1779 continue;
1780
1781 bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry "
1782 "(%pM): pending\n", tt_local_entry->addr);
1783
1784 atomic_dec(&bat_priv->num_local_tt);
1785 hlist_del_rcu(node);
1786 tt_local_entry_free_ref(tt_local_entry);
1787 }
1788 spin_unlock_bh(list_lock);
1789 }
1790
1791}
1792
1793void tt_commit_changes(struct bat_priv *bat_priv)
1794{
1795 tt_local_reset_flags(bat_priv, TT_CLIENT_NEW);
1796 tt_local_purge_pending_clients(bat_priv);
1797
1798 /* Increment the TTVN only once per OGM interval */
1799 atomic_inc(&bat_priv->ttvn);
1800 bat_priv->tt_poss_change = false;
1801}
Antonio Quartulli59b699c2011-07-07 15:35:36 +02001802
1803bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst)
1804{
1805 struct tt_local_entry *tt_local_entry = NULL;
1806 struct tt_global_entry *tt_global_entry = NULL;
1807 bool ret = true;
1808
1809 if (!atomic_read(&bat_priv->ap_isolation))
1810 return false;
1811
1812 tt_local_entry = tt_local_hash_find(bat_priv, dst);
1813 if (!tt_local_entry)
1814 goto out;
1815
1816 tt_global_entry = tt_global_hash_find(bat_priv, src);
1817 if (!tt_global_entry)
1818 goto out;
1819
1820 if (_is_ap_isolated(tt_local_entry, tt_global_entry))
1821 goto out;
1822
1823 ret = false;
1824
1825out:
1826 if (tt_global_entry)
1827 tt_global_entry_free_ref(tt_global_entry);
1828 if (tt_local_entry)
1829 tt_local_entry_free_ref(tt_local_entry);
1830 return ret;
1831}
Marek Lindnera943cac2011-07-30 13:10:18 +02001832
1833void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
1834 const unsigned char *tt_buff, uint8_t tt_num_changes,
1835 uint8_t ttvn, uint16_t tt_crc)
1836{
1837 uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
1838 bool full_table = true;
1839
1840 /* the ttvn increased by one -> we can apply the attached changes */
1841 if (ttvn - orig_ttvn == 1) {
1842 /* the OGM could not contain the changes due to their size or
1843 * because they have already been sent TT_OGM_APPEND_MAX times.
1844 * In this case send a tt request */
1845 if (!tt_num_changes) {
1846 full_table = false;
1847 goto request_table;
1848 }
1849
1850 tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
1851 (struct tt_change *)tt_buff);
1852
1853 /* Even if we received the precomputed crc with the OGM, we
1854 * prefer to recompute it to spot any possible inconsistency
1855 * in the global table */
1856 orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
1857
1858 /* The ttvn alone is not enough to guarantee consistency
1859 * because a single value could represent different states
1860 * (due to the wrap around). Thus a node has to check whether
1861 * the resulting table (after applying the changes) is still
1862 * consistent or not. E.g. a node could disconnect while its
1863 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
1864 * checking the CRC value is mandatory to detect the
1865 * inconsistency */
1866 if (orig_node->tt_crc != tt_crc)
1867 goto request_table;
1868
1869 /* Roaming phase is over: tables are in sync again. I can
1870 * unset the flag */
1871 orig_node->tt_poss_change = false;
1872 } else {
1873 /* if we missed more than one change or our tables are not
1874 * in sync anymore -> request fresh tt data */
1875 if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) {
1876request_table:
1877 bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. "
1878 "Need to retrieve the correct information "
1879 "(ttvn: %u last_ttvn: %u crc: %u last_crc: "
1880 "%u num_changes: %u)\n", orig_node->orig, ttvn,
1881 orig_ttvn, tt_crc, orig_node->tt_crc,
1882 tt_num_changes);
1883 send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
1884 full_table);
1885 return;
1886 }
1887 }
1888}