blob: f6bbd6423defccb2646082d9549e52a4bd7bfc22 [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 */
Antonio Quartulli48100ba2011-10-30 12:17:33 +010039static int compare_tt(const struct hlist_node *node, const void *data2)
Marek Lindner7aadf882011-02-18 12:28:09 +000040{
Antonio Quartulli48100ba2011-10-30 12:17:33 +010041 const void *data1 = container_of(node, struct tt_common_entry,
Sven Eckelmann747e4222011-05-14 23:14:50 +020042 hash_entry);
Marek Lindner7aadf882011-02-18 12:28:09 +000043
44 return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
45}
46
Antonio Quartullia73105b2011-04-27 14:27:44 +020047static void tt_start_timer(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000048{
Antonio Quartullia73105b2011-04-27 14:27:44 +020049 INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge);
50 queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work,
51 msecs_to_jiffies(5000));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000052}
53
Antonio Quartulli48100ba2011-10-30 12:17:33 +010054static struct tt_common_entry *tt_hash_find(struct hashtable_t *hash,
55 const void *data)
Marek Lindner7aadf882011-02-18 12:28:09 +000056{
Marek Lindner7aadf882011-02-18 12:28:09 +000057 struct hlist_head *head;
58 struct hlist_node *node;
Antonio Quartulli48100ba2011-10-30 12:17:33 +010059 struct tt_common_entry *tt_common_entry, *tt_common_entry_tmp = NULL;
Antonio Quartullic90681b2011-10-05 17:05:25 +020060 uint32_t index;
Marek Lindner7aadf882011-02-18 12:28:09 +000061
62 if (!hash)
63 return NULL;
64
65 index = choose_orig(data, hash->size);
66 head = &hash->table[index];
67
68 rcu_read_lock();
Antonio Quartulli48100ba2011-10-30 12:17:33 +010069 hlist_for_each_entry_rcu(tt_common_entry, node, head, hash_entry) {
70 if (!compare_eth(tt_common_entry, data))
Marek Lindner7aadf882011-02-18 12:28:09 +000071 continue;
72
Antonio Quartulli48100ba2011-10-30 12:17:33 +010073 if (!atomic_inc_not_zero(&tt_common_entry->refcount))
Antonio Quartulli7683fdc2011-04-27 14:28:07 +020074 continue;
75
Antonio Quartulli48100ba2011-10-30 12:17:33 +010076 tt_common_entry_tmp = tt_common_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +000077 break;
78 }
79 rcu_read_unlock();
80
Antonio Quartulli48100ba2011-10-30 12:17:33 +010081 return tt_common_entry_tmp;
82}
83
84static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
85 const void *data)
86{
87 struct tt_common_entry *tt_common_entry;
88 struct tt_local_entry *tt_local_entry = NULL;
89
90 tt_common_entry = tt_hash_find(bat_priv->tt_local_hash, data);
91 if (tt_common_entry)
92 tt_local_entry = container_of(tt_common_entry,
93 struct tt_local_entry, common);
94 return tt_local_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +000095}
96
Antonio Quartulli2dafb492011-05-05 08:42:45 +020097static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
Sven Eckelmann747e4222011-05-14 23:14:50 +020098 const void *data)
Marek Lindner7aadf882011-02-18 12:28:09 +000099{
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100100 struct tt_common_entry *tt_common_entry;
101 struct tt_global_entry *tt_global_entry = NULL;
Marek Lindner7aadf882011-02-18 12:28:09 +0000102
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100103 tt_common_entry = tt_hash_find(bat_priv->tt_global_hash, data);
104 if (tt_common_entry)
105 tt_global_entry = container_of(tt_common_entry,
106 struct tt_global_entry, common);
107 return tt_global_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +0000108
Marek Lindner7aadf882011-02-18 12:28:09 +0000109}
110
Antonio Quartullia73105b2011-04-27 14:27:44 +0200111static bool is_out_of_time(unsigned long starting_time, unsigned long timeout)
112{
113 unsigned long deadline;
114 deadline = starting_time + msecs_to_jiffies(timeout);
115
116 return time_after(jiffies, deadline);
117}
118
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200119static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
120{
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100121 if (atomic_dec_and_test(&tt_local_entry->common.refcount))
122 kfree_rcu(tt_local_entry, common.rcu);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200123}
124
Simon Wunderlich531027f2011-10-19 11:02:25 +0200125static void tt_global_entry_free_rcu(struct rcu_head *rcu)
126{
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100127 struct tt_common_entry *tt_common_entry;
Simon Wunderlich531027f2011-10-19 11:02:25 +0200128 struct tt_global_entry *tt_global_entry;
129
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100130 tt_common_entry = container_of(rcu, struct tt_common_entry, rcu);
131 tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
132 common);
Simon Wunderlich531027f2011-10-19 11:02:25 +0200133
134 if (tt_global_entry->orig_node)
135 orig_node_free_ref(tt_global_entry->orig_node);
136
137 kfree(tt_global_entry);
138}
139
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200140static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
141{
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100142 if (atomic_dec_and_test(&tt_global_entry->common.refcount))
143 call_rcu(&tt_global_entry->common.rcu,
144 tt_global_entry_free_rcu);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200145}
146
Antonio Quartulliff66c972011-06-30 01:14:00 +0200147static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
148 uint8_t flags)
Antonio Quartullia73105b2011-04-27 14:27:44 +0200149{
150 struct tt_change_node *tt_change_node;
151
152 tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
153
154 if (!tt_change_node)
155 return;
156
Antonio Quartulliff66c972011-06-30 01:14:00 +0200157 tt_change_node->change.flags = flags;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200158 memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
159
160 spin_lock_bh(&bat_priv->tt_changes_list_lock);
161 /* track the change in the OGMinterval list */
162 list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list);
163 atomic_inc(&bat_priv->tt_local_changes);
164 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
165
166 atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
167}
168
169int tt_len(int changes_num)
170{
171 return changes_num * sizeof(struct tt_change);
172}
173
174static int tt_local_init(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000175{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200176 if (bat_priv->tt_local_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000177 return 1;
178
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200179 bat_priv->tt_local_hash = hash_new(1024);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000180
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200181 if (!bat_priv->tt_local_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000182 return 0;
183
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000184 return 1;
185}
186
Antonio Quartullibc279082011-07-07 15:35:35 +0200187void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
188 int ifindex)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000189{
190 struct bat_priv *bat_priv = netdev_priv(soft_iface);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200191 struct tt_local_entry *tt_local_entry = NULL;
192 struct tt_global_entry *tt_global_entry = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000193
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200194 tt_local_entry = tt_local_hash_find(bat_priv, addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000195
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200196 if (tt_local_entry) {
197 tt_local_entry->last_seen = jiffies;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200198 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000199 }
200
Sven Eckelmann704509b2011-05-14 23:14:54 +0200201 tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200202 if (!tt_local_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200203 goto out;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200204
Antonio Quartullia73105b2011-04-27 14:27:44 +0200205 bat_dbg(DBG_TT, bat_priv,
206 "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
207 (uint8_t)atomic_read(&bat_priv->ttvn));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000208
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100209 memcpy(tt_local_entry->common.addr, addr, ETH_ALEN);
210 tt_local_entry->common.flags = NO_FLAGS;
Antonio Quartullibc279082011-07-07 15:35:35 +0200211 if (is_wifi_iface(ifindex))
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100212 tt_local_entry->common.flags |= TT_CLIENT_WIFI;
213 atomic_set(&tt_local_entry->common.refcount, 2);
214 tt_local_entry->last_seen = jiffies;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000215
216 /* the batman interface mac address should never be purged */
Marek Lindner39901e72011-02-18 12:28:08 +0000217 if (compare_eth(addr, soft_iface->dev_addr))
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100218 tt_local_entry->common.flags |= TT_CLIENT_NOPURGE;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000219
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100220 tt_local_event(bat_priv, addr, tt_local_entry->common.flags);
Antonio Quartulliff66c972011-06-30 01:14:00 +0200221
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200222 /* The local entry has to be marked as NEW to avoid to send it in
223 * a full table response going out before the next ttvn increment
224 * (consistency check) */
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100225 tt_local_entry->common.flags |= TT_CLIENT_NEW;
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200226
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100227 hash_add(bat_priv->tt_local_hash, compare_tt, choose_orig,
228 &tt_local_entry->common, &tt_local_entry->common.hash_entry);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200229
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000230 /* remove address from global hash if present */
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200231 tt_global_entry = tt_global_hash_find(bat_priv, addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000232
Antonio Quartullicc47f662011-04-27 14:27:57 +0200233 /* Check whether it is a roaming! */
234 if (tt_global_entry) {
Antonio Quartullicc47f662011-04-27 14:27:57 +0200235 /* This node is probably going to update its tt table */
236 tt_global_entry->orig_node->tt_poss_change = true;
Antonio Quartulli980d55b2011-07-07 01:40:59 +0200237 /* The global entry has to be marked as PENDING and has to be
238 * kept for consistency purpose */
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100239 tt_global_entry->common.flags |= TT_CLIENT_PENDING;
240 send_roam_adv(bat_priv, tt_global_entry->common.addr,
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200241 tt_global_entry->orig_node);
242 }
243out:
244 if (tt_local_entry)
245 tt_local_entry_free_ref(tt_local_entry);
246 if (tt_global_entry)
247 tt_global_entry_free_ref(tt_global_entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000248}
249
Antonio Quartullia73105b2011-04-27 14:27:44 +0200250int tt_changes_fill_buffer(struct bat_priv *bat_priv,
251 unsigned char *buff, int buff_len)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000252{
Antonio Quartullia73105b2011-04-27 14:27:44 +0200253 int count = 0, tot_changes = 0;
254 struct tt_change_node *entry, *safe;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000255
Antonio Quartullia73105b2011-04-27 14:27:44 +0200256 if (buff_len > 0)
257 tot_changes = buff_len / tt_len(1);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000258
Antonio Quartullia73105b2011-04-27 14:27:44 +0200259 spin_lock_bh(&bat_priv->tt_changes_list_lock);
260 atomic_set(&bat_priv->tt_local_changes, 0);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000261
Antonio Quartullia73105b2011-04-27 14:27:44 +0200262 list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
263 list) {
264 if (count < tot_changes) {
265 memcpy(buff + tt_len(count),
266 &entry->change, sizeof(struct tt_change));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000267 count++;
268 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200269 list_del(&entry->list);
270 kfree(entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000271 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200272 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000273
Antonio Quartullia73105b2011-04-27 14:27:44 +0200274 /* Keep the buffer for possible tt_request */
275 spin_lock_bh(&bat_priv->tt_buff_lock);
276 kfree(bat_priv->tt_buff);
277 bat_priv->tt_buff_len = 0;
278 bat_priv->tt_buff = NULL;
279 /* We check whether this new OGM has no changes due to size
280 * problems */
281 if (buff_len > 0) {
282 /**
283 * if kmalloc() fails we will reply with the full table
284 * instead of providing the diff
285 */
286 bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC);
287 if (bat_priv->tt_buff) {
288 memcpy(bat_priv->tt_buff, buff, buff_len);
289 bat_priv->tt_buff_len = buff_len;
290 }
291 }
292 spin_unlock_bh(&bat_priv->tt_buff_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000293
Antonio Quartullia73105b2011-04-27 14:27:44 +0200294 return tot_changes;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000295}
296
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200297int tt_local_seq_print_text(struct seq_file *seq, void *offset)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000298{
299 struct net_device *net_dev = (struct net_device *)seq->private;
300 struct bat_priv *bat_priv = netdev_priv(net_dev);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200301 struct hashtable_t *hash = bat_priv->tt_local_hash;
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100302 struct tt_common_entry *tt_common_entry;
Marek Lindner32ae9b22011-04-20 15:40:58 +0200303 struct hard_iface *primary_if;
Marek Lindner7aadf882011-02-18 12:28:09 +0000304 struct hlist_node *node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000305 struct hlist_head *head;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200306 uint32_t i;
307 int ret = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000308
Marek Lindner32ae9b22011-04-20 15:40:58 +0200309 primary_if = primary_if_get_selected(bat_priv);
310 if (!primary_if) {
311 ret = seq_printf(seq, "BATMAN mesh %s disabled - "
312 "please specify interfaces to enable it\n",
313 net_dev->name);
314 goto out;
315 }
316
317 if (primary_if->if_status != IF_ACTIVE) {
318 ret = seq_printf(seq, "BATMAN mesh %s disabled - "
319 "primary interface not active\n",
320 net_dev->name);
321 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000322 }
323
324 seq_printf(seq, "Locally retrieved addresses (from %s) "
Antonio Quartullia73105b2011-04-27 14:27:44 +0200325 "announced via TT (TTVN: %u):\n",
326 net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000327
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000328 for (i = 0; i < hash->size; i++) {
329 head = &hash->table[i];
330
Marek Lindner7aadf882011-02-18 12:28:09 +0000331 rcu_read_lock();
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100332 hlist_for_each_entry_rcu(tt_common_entry, node,
Marek Lindner7aadf882011-02-18 12:28:09 +0000333 head, hash_entry) {
Simon Wunderlichd099c2c2011-10-22 18:15:26 +0200334 seq_printf(seq, " * %pM [%c%c%c%c%c]\n",
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100335 tt_common_entry->addr,
336 (tt_common_entry->flags &
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200337 TT_CLIENT_ROAM ? 'R' : '.'),
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100338 (tt_common_entry->flags &
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200339 TT_CLIENT_NOPURGE ? 'P' : '.'),
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100340 (tt_common_entry->flags &
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200341 TT_CLIENT_NEW ? 'N' : '.'),
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100342 (tt_common_entry->flags &
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200343 TT_CLIENT_PENDING ? 'X' : '.'),
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100344 (tt_common_entry->flags &
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200345 TT_CLIENT_WIFI ? 'W' : '.'));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000346 }
Marek Lindner7aadf882011-02-18 12:28:09 +0000347 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000348 }
Marek Lindner32ae9b22011-04-20 15:40:58 +0200349out:
350 if (primary_if)
351 hardif_free_ref(primary_if);
352 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000353}
354
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200355static void tt_local_set_pending(struct bat_priv *bat_priv,
356 struct tt_local_entry *tt_local_entry,
357 uint16_t flags)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000358{
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100359 tt_local_event(bat_priv, tt_local_entry->common.addr,
360 tt_local_entry->common.flags | flags);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000361
Antonio Quartulli015758d2011-07-09 17:52:13 +0200362 /* The local client has to be marked as "pending to be removed" but has
363 * to be kept in the table in order to send it in a full table
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200364 * response issued before the net ttvn increment (consistency check) */
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100365 tt_local_entry->common.flags |= TT_CLIENT_PENDING;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000366}
367
Antonio Quartullia73105b2011-04-27 14:27:44 +0200368void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
Antonio Quartullicc47f662011-04-27 14:27:57 +0200369 const char *message, bool roaming)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000370{
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200371 struct tt_local_entry *tt_local_entry = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000372
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200373 tt_local_entry = tt_local_hash_find(bat_priv, addr);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200374 if (!tt_local_entry)
375 goto out;
376
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200377 tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
378 (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
379
380 bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100381 "%s\n", tt_local_entry->common.addr, message);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200382out:
383 if (tt_local_entry)
384 tt_local_entry_free_ref(tt_local_entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000385}
386
Antonio Quartullia73105b2011-04-27 14:27:44 +0200387static void tt_local_purge(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000388{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200389 struct hashtable_t *hash = bat_priv->tt_local_hash;
390 struct tt_local_entry *tt_local_entry;
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100391 struct tt_common_entry *tt_common_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +0000392 struct hlist_node *node, *node_tmp;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000393 struct hlist_head *head;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200394 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartullic90681b2011-10-05 17:05:25 +0200395 uint32_t i;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000396
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000397 for (i = 0; i < hash->size; i++) {
398 head = &hash->table[i];
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200399 list_lock = &hash->list_locks[i];
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000400
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200401 spin_lock_bh(list_lock);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100402 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
Marek Lindner7aadf882011-02-18 12:28:09 +0000403 head, hash_entry) {
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100404 tt_local_entry = container_of(tt_common_entry,
405 struct tt_local_entry,
406 common);
407 if (tt_local_entry->common.flags & TT_CLIENT_NOPURGE)
Marek Lindner7aadf882011-02-18 12:28:09 +0000408 continue;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000409
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200410 /* entry already marked for deletion */
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100411 if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200412 continue;
413
Antonio Quartullia73105b2011-04-27 14:27:44 +0200414 if (!is_out_of_time(tt_local_entry->last_seen,
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200415 TT_LOCAL_TIMEOUT * 1000))
Marek Lindner7aadf882011-02-18 12:28:09 +0000416 continue;
417
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200418 tt_local_set_pending(bat_priv, tt_local_entry,
419 TT_CLIENT_DEL);
420 bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) "
421 "pending to be removed: timed out\n",
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100422 tt_local_entry->common.addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000423 }
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200424 spin_unlock_bh(list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000425 }
426
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000427}
428
Antonio Quartullia73105b2011-04-27 14:27:44 +0200429static void tt_local_table_free(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000430{
Antonio Quartullia73105b2011-04-27 14:27:44 +0200431 struct hashtable_t *hash;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200432 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100433 struct tt_common_entry *tt_common_entry;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200434 struct tt_local_entry *tt_local_entry;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200435 struct hlist_node *node, *node_tmp;
436 struct hlist_head *head;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200437 uint32_t i;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200438
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200439 if (!bat_priv->tt_local_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000440 return;
441
Antonio Quartullia73105b2011-04-27 14:27:44 +0200442 hash = bat_priv->tt_local_hash;
443
444 for (i = 0; i < hash->size; i++) {
445 head = &hash->table[i];
446 list_lock = &hash->list_locks[i];
447
448 spin_lock_bh(list_lock);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100449 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
Antonio Quartullia73105b2011-04-27 14:27:44 +0200450 head, hash_entry) {
451 hlist_del_rcu(node);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100452 tt_local_entry = container_of(tt_common_entry,
453 struct tt_local_entry,
454 common);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200455 tt_local_entry_free_ref(tt_local_entry);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200456 }
457 spin_unlock_bh(list_lock);
458 }
459
460 hash_destroy(hash);
461
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200462 bat_priv->tt_local_hash = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000463}
464
Antonio Quartullia73105b2011-04-27 14:27:44 +0200465static int tt_global_init(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000466{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200467 if (bat_priv->tt_global_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000468 return 1;
469
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200470 bat_priv->tt_global_hash = hash_new(1024);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000471
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200472 if (!bat_priv->tt_global_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000473 return 0;
474
475 return 1;
476}
477
Antonio Quartullia73105b2011-04-27 14:27:44 +0200478static void tt_changes_list_free(struct bat_priv *bat_priv)
479{
480 struct tt_change_node *entry, *safe;
481
482 spin_lock_bh(&bat_priv->tt_changes_list_lock);
483
484 list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
485 list) {
486 list_del(&entry->list);
487 kfree(entry);
488 }
489
490 atomic_set(&bat_priv->tt_local_changes, 0);
491 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
492}
493
494/* caller must hold orig_node refcount */
495int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
Antonio Quartullibc279082011-07-07 15:35:35 +0200496 const unsigned char *tt_addr, uint8_t ttvn, bool roaming,
497 bool wifi)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000498{
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200499 struct tt_global_entry *tt_global_entry;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200500 struct orig_node *orig_node_tmp;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200501 int ret = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000502
Antonio Quartullia73105b2011-04-27 14:27:44 +0200503 tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000504
Antonio Quartullia73105b2011-04-27 14:27:44 +0200505 if (!tt_global_entry) {
506 tt_global_entry =
507 kmalloc(sizeof(*tt_global_entry),
508 GFP_ATOMIC);
509 if (!tt_global_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200510 goto out;
511
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100512 memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN);
513 tt_global_entry->common.flags = NO_FLAGS;
514 atomic_set(&tt_global_entry->common.refcount, 2);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200515 /* Assign the new orig_node */
516 atomic_inc(&orig_node->refcount);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200517 tt_global_entry->orig_node = orig_node;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200518 tt_global_entry->ttvn = ttvn;
Antonio Quartullicc47f662011-04-27 14:27:57 +0200519 tt_global_entry->roam_at = 0;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200520
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100521 hash_add(bat_priv->tt_global_hash, compare_tt,
522 choose_orig, &tt_global_entry->common,
523 &tt_global_entry->common.hash_entry);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200524 atomic_inc(&orig_node->tt_size);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200525 } else {
526 if (tt_global_entry->orig_node != orig_node) {
527 atomic_dec(&tt_global_entry->orig_node->tt_size);
528 orig_node_tmp = tt_global_entry->orig_node;
529 atomic_inc(&orig_node->refcount);
530 tt_global_entry->orig_node = orig_node;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200531 orig_node_free_ref(orig_node_tmp);
532 atomic_inc(&orig_node->tt_size);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000533 }
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100534 tt_global_entry->common.flags = NO_FLAGS;
Antonio Quartullicc47f662011-04-27 14:27:57 +0200535 tt_global_entry->ttvn = ttvn;
Antonio Quartullicc47f662011-04-27 14:27:57 +0200536 tt_global_entry->roam_at = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000537 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200538
Antonio Quartullibc279082011-07-07 15:35:35 +0200539 if (wifi)
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100540 tt_global_entry->common.flags |= TT_CLIENT_WIFI;
Antonio Quartullibc279082011-07-07 15:35:35 +0200541
Antonio Quartullia73105b2011-04-27 14:27:44 +0200542 bat_dbg(DBG_TT, bat_priv,
543 "Creating new global tt entry: %pM (via %pM)\n",
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100544 tt_global_entry->common.addr, orig_node->orig);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200545
546 /* remove address from local hash if present */
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100547 tt_local_remove(bat_priv, tt_global_entry->common.addr,
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200548 "global tt received", roaming);
549 ret = 1;
550out:
551 if (tt_global_entry)
552 tt_global_entry_free_ref(tt_global_entry);
553 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000554}
555
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200556int tt_global_seq_print_text(struct seq_file *seq, void *offset)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000557{
558 struct net_device *net_dev = (struct net_device *)seq->private;
559 struct bat_priv *bat_priv = netdev_priv(net_dev);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200560 struct hashtable_t *hash = bat_priv->tt_global_hash;
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100561 struct tt_common_entry *tt_common_entry;
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200562 struct tt_global_entry *tt_global_entry;
Marek Lindner32ae9b22011-04-20 15:40:58 +0200563 struct hard_iface *primary_if;
Marek Lindner7aadf882011-02-18 12:28:09 +0000564 struct hlist_node *node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000565 struct hlist_head *head;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200566 uint32_t i;
567 int ret = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000568
Marek Lindner32ae9b22011-04-20 15:40:58 +0200569 primary_if = primary_if_get_selected(bat_priv);
570 if (!primary_if) {
571 ret = seq_printf(seq, "BATMAN mesh %s disabled - please "
572 "specify interfaces to enable it\n",
573 net_dev->name);
574 goto out;
575 }
576
577 if (primary_if->if_status != IF_ACTIVE) {
578 ret = seq_printf(seq, "BATMAN mesh %s disabled - "
579 "primary interface not active\n",
580 net_dev->name);
581 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000582 }
583
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200584 seq_printf(seq,
585 "Globally announced TT entries received via the mesh %s\n",
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000586 net_dev->name);
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200587 seq_printf(seq, " %-13s %s %-15s %s %s\n",
588 "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000589
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000590 for (i = 0; i < hash->size; i++) {
591 head = &hash->table[i];
592
Marek Lindner7aadf882011-02-18 12:28:09 +0000593 rcu_read_lock();
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100594 hlist_for_each_entry_rcu(tt_common_entry, node,
Marek Lindner7aadf882011-02-18 12:28:09 +0000595 head, hash_entry) {
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100596 tt_global_entry = container_of(tt_common_entry,
597 struct tt_global_entry,
598 common);
Simon Wunderlichd099c2c2011-10-22 18:15:26 +0200599 seq_printf(seq, " * %pM (%3u) via %pM (%3u) "
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100600 "[%c%c%c]\n",
601 tt_global_entry->common.addr,
Antonio Quartullia73105b2011-04-27 14:27:44 +0200602 tt_global_entry->ttvn,
603 tt_global_entry->orig_node->orig,
604 (uint8_t) atomic_read(
605 &tt_global_entry->orig_node->
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200606 last_ttvn),
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100607 (tt_global_entry->common.flags &
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200608 TT_CLIENT_ROAM ? 'R' : '.'),
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100609 (tt_global_entry->common.flags &
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200610 TT_CLIENT_PENDING ? 'X' : '.'),
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100611 (tt_global_entry->common.flags &
Antonio Quartullidf6edb92011-07-07 15:35:38 +0200612 TT_CLIENT_WIFI ? 'W' : '.'));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000613 }
Marek Lindner7aadf882011-02-18 12:28:09 +0000614 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000615 }
Marek Lindner32ae9b22011-04-20 15:40:58 +0200616out:
617 if (primary_if)
618 hardif_free_ref(primary_if);
619 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000620}
621
Antonio Quartullia73105b2011-04-27 14:27:44 +0200622static void _tt_global_del(struct bat_priv *bat_priv,
623 struct tt_global_entry *tt_global_entry,
624 const char *message)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000625{
Antonio Quartullia73105b2011-04-27 14:27:44 +0200626 if (!tt_global_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200627 goto out;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200628
629 bat_dbg(DBG_TT, bat_priv,
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200630 "Deleting global tt entry %pM (via %pM): %s\n",
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100631 tt_global_entry->common.addr, tt_global_entry->orig_node->orig,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000632 message);
633
Antonio Quartullia73105b2011-04-27 14:27:44 +0200634 atomic_dec(&tt_global_entry->orig_node->tt_size);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200635
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100636 hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig,
637 tt_global_entry->common.addr);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200638out:
639 if (tt_global_entry)
640 tt_global_entry_free_ref(tt_global_entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000641}
642
Antonio Quartullia73105b2011-04-27 14:27:44 +0200643void tt_global_del(struct bat_priv *bat_priv,
644 struct orig_node *orig_node, const unsigned char *addr,
Antonio Quartullicc47f662011-04-27 14:27:57 +0200645 const char *message, bool roaming)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000646{
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200647 struct tt_global_entry *tt_global_entry = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000648
Antonio Quartullia73105b2011-04-27 14:27:44 +0200649 tt_global_entry = tt_global_hash_find(bat_priv, addr);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200650 if (!tt_global_entry)
651 goto out;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200652
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200653 if (tt_global_entry->orig_node == orig_node) {
Antonio Quartullicc47f662011-04-27 14:27:57 +0200654 if (roaming) {
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100655 tt_global_entry->common.flags |= TT_CLIENT_ROAM;
Antonio Quartullicc47f662011-04-27 14:27:57 +0200656 tt_global_entry->roam_at = jiffies;
657 goto out;
658 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200659 _tt_global_del(bat_priv, tt_global_entry, message);
660 }
Antonio Quartullicc47f662011-04-27 14:27:57 +0200661out:
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200662 if (tt_global_entry)
663 tt_global_entry_free_ref(tt_global_entry);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200664}
665
666void tt_global_del_orig(struct bat_priv *bat_priv,
667 struct orig_node *orig_node, const char *message)
668{
669 struct tt_global_entry *tt_global_entry;
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100670 struct tt_common_entry *tt_common_entry;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200671 uint32_t i;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200672 struct hashtable_t *hash = bat_priv->tt_global_hash;
673 struct hlist_node *node, *safe;
674 struct hlist_head *head;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200675 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartullia73105b2011-04-27 14:27:44 +0200676
Simon Wunderlich6e801492011-10-19 10:28:26 +0200677 if (!hash)
678 return;
679
Antonio Quartullia73105b2011-04-27 14:27:44 +0200680 for (i = 0; i < hash->size; i++) {
681 head = &hash->table[i];
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200682 list_lock = &hash->list_locks[i];
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000683
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200684 spin_lock_bh(list_lock);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100685 hlist_for_each_entry_safe(tt_common_entry, node, safe,
Antonio Quartullia73105b2011-04-27 14:27:44 +0200686 head, hash_entry) {
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100687 tt_global_entry = container_of(tt_common_entry,
688 struct tt_global_entry,
689 common);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200690 if (tt_global_entry->orig_node == orig_node) {
691 bat_dbg(DBG_TT, bat_priv,
692 "Deleting global tt entry %pM "
Antonio Quartulli87944972011-09-19 12:29:19 +0200693 "(via %pM): %s\n",
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100694 tt_global_entry->common.addr,
Antonio Quartulli87944972011-09-19 12:29:19 +0200695 tt_global_entry->orig_node->orig,
696 message);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200697 hlist_del_rcu(node);
698 tt_global_entry_free_ref(tt_global_entry);
699 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200700 }
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200701 spin_unlock_bh(list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000702 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200703 atomic_set(&orig_node->tt_size, 0);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000704}
705
Antonio Quartullicc47f662011-04-27 14:27:57 +0200706static void tt_global_roam_purge(struct bat_priv *bat_priv)
707{
708 struct hashtable_t *hash = bat_priv->tt_global_hash;
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100709 struct tt_common_entry *tt_common_entry;
Antonio Quartullicc47f662011-04-27 14:27:57 +0200710 struct tt_global_entry *tt_global_entry;
711 struct hlist_node *node, *node_tmp;
712 struct hlist_head *head;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200713 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartullic90681b2011-10-05 17:05:25 +0200714 uint32_t i;
Antonio Quartullicc47f662011-04-27 14:27:57 +0200715
Antonio Quartullicc47f662011-04-27 14:27:57 +0200716 for (i = 0; i < hash->size; i++) {
717 head = &hash->table[i];
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200718 list_lock = &hash->list_locks[i];
Antonio Quartullicc47f662011-04-27 14:27:57 +0200719
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200720 spin_lock_bh(list_lock);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100721 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
Antonio Quartullicc47f662011-04-27 14:27:57 +0200722 head, hash_entry) {
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100723 tt_global_entry = container_of(tt_common_entry,
724 struct tt_global_entry,
725 common);
726 if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM))
Antonio Quartullicc47f662011-04-27 14:27:57 +0200727 continue;
728 if (!is_out_of_time(tt_global_entry->roam_at,
729 TT_CLIENT_ROAM_TIMEOUT * 1000))
730 continue;
731
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200732 bat_dbg(DBG_TT, bat_priv, "Deleting global "
733 "tt entry (%pM): Roaming timeout\n",
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100734 tt_global_entry->common.addr);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200735 atomic_dec(&tt_global_entry->orig_node->tt_size);
736 hlist_del_rcu(node);
737 tt_global_entry_free_ref(tt_global_entry);
Antonio Quartullicc47f662011-04-27 14:27:57 +0200738 }
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200739 spin_unlock_bh(list_lock);
Antonio Quartullicc47f662011-04-27 14:27:57 +0200740 }
741
Antonio Quartullicc47f662011-04-27 14:27:57 +0200742}
743
Antonio Quartullia73105b2011-04-27 14:27:44 +0200744static void tt_global_table_free(struct bat_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000745{
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200746 struct hashtable_t *hash;
747 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100748 struct tt_common_entry *tt_common_entry;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200749 struct tt_global_entry *tt_global_entry;
750 struct hlist_node *node, *node_tmp;
751 struct hlist_head *head;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200752 uint32_t i;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200753
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200754 if (!bat_priv->tt_global_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000755 return;
756
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200757 hash = bat_priv->tt_global_hash;
758
759 for (i = 0; i < hash->size; i++) {
760 head = &hash->table[i];
761 list_lock = &hash->list_locks[i];
762
763 spin_lock_bh(list_lock);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100764 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200765 head, hash_entry) {
766 hlist_del_rcu(node);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100767 tt_global_entry = container_of(tt_common_entry,
768 struct tt_global_entry,
769 common);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200770 tt_global_entry_free_ref(tt_global_entry);
771 }
772 spin_unlock_bh(list_lock);
773 }
774
775 hash_destroy(hash);
776
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200777 bat_priv->tt_global_hash = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000778}
779
Antonio Quartulli59b699c2011-07-07 15:35:36 +0200780static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
781 struct tt_global_entry *tt_global_entry)
782{
783 bool ret = false;
784
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100785 if (tt_local_entry->common.flags & TT_CLIENT_WIFI &&
786 tt_global_entry->common.flags & TT_CLIENT_WIFI)
Antonio Quartulli59b699c2011-07-07 15:35:36 +0200787 ret = true;
788
789 return ret;
790}
791
Sven Eckelmann747e4222011-05-14 23:14:50 +0200792struct orig_node *transtable_search(struct bat_priv *bat_priv,
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200793 const uint8_t *src, const uint8_t *addr)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000794{
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200795 struct tt_local_entry *tt_local_entry = NULL;
796 struct tt_global_entry *tt_global_entry = NULL;
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000797 struct orig_node *orig_node = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000798
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200799 if (src && atomic_read(&bat_priv->ap_isolation)) {
800 tt_local_entry = tt_local_hash_find(bat_priv, src);
801 if (!tt_local_entry)
802 goto out;
803 }
Marek Lindner7aadf882011-02-18 12:28:09 +0000804
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200805 tt_global_entry = tt_global_hash_find(bat_priv, addr);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200806 if (!tt_global_entry)
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000807 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000808
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200809 /* check whether the clients should not communicate due to AP
810 * isolation */
811 if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry))
812 goto out;
813
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200814 if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200815 goto out;
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000816
Antonio Quartulli980d55b2011-07-07 01:40:59 +0200817 /* A global client marked as PENDING has already moved from that
818 * originator */
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100819 if (tt_global_entry->common.flags & TT_CLIENT_PENDING)
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200820 goto out;
Antonio Quartulli980d55b2011-07-07 01:40:59 +0200821
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200822 orig_node = tt_global_entry->orig_node;
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000823
824out:
Antonio Quartulli3d393e42011-07-07 15:35:37 +0200825 if (tt_global_entry)
826 tt_global_entry_free_ref(tt_global_entry);
827 if (tt_local_entry)
828 tt_local_entry_free_ref(tt_local_entry);
829
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000830 return orig_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000831}
Antonio Quartullia73105b2011-04-27 14:27:44 +0200832
833/* Calculates the checksum of the local table of a given orig_node */
834uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
835{
836 uint16_t total = 0, total_one;
837 struct hashtable_t *hash = bat_priv->tt_global_hash;
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100838 struct tt_common_entry *tt_common_entry;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200839 struct tt_global_entry *tt_global_entry;
840 struct hlist_node *node;
841 struct hlist_head *head;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200842 uint32_t i;
843 int j;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200844
845 for (i = 0; i < hash->size; i++) {
846 head = &hash->table[i];
847
848 rcu_read_lock();
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100849 hlist_for_each_entry_rcu(tt_common_entry, node,
Antonio Quartullia73105b2011-04-27 14:27:44 +0200850 head, hash_entry) {
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100851 tt_global_entry = container_of(tt_common_entry,
852 struct tt_global_entry,
853 common);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200854 if (compare_eth(tt_global_entry->orig_node,
855 orig_node)) {
Antonio Quartullicc47f662011-04-27 14:27:57 +0200856 /* Roaming clients are in the global table for
857 * consistency only. They don't have to be
858 * taken into account while computing the
859 * global crc */
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100860 if (tt_common_entry->flags & TT_CLIENT_ROAM)
Antonio Quartullicc47f662011-04-27 14:27:57 +0200861 continue;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200862 total_one = 0;
863 for (j = 0; j < ETH_ALEN; j++)
864 total_one = crc16_byte(total_one,
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100865 tt_common_entry->addr[j]);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200866 total ^= total_one;
867 }
868 }
869 rcu_read_unlock();
870 }
871
872 return total;
873}
874
875/* Calculates the checksum of the local table */
876uint16_t tt_local_crc(struct bat_priv *bat_priv)
877{
878 uint16_t total = 0, total_one;
879 struct hashtable_t *hash = bat_priv->tt_local_hash;
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100880 struct tt_common_entry *tt_common_entry;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200881 struct hlist_node *node;
882 struct hlist_head *head;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200883 uint32_t i;
884 int j;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200885
886 for (i = 0; i < hash->size; i++) {
887 head = &hash->table[i];
888
889 rcu_read_lock();
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100890 hlist_for_each_entry_rcu(tt_common_entry, node,
Antonio Quartullia73105b2011-04-27 14:27:44 +0200891 head, hash_entry) {
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200892 /* not yet committed clients have not to be taken into
893 * account while computing the CRC */
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100894 if (tt_common_entry->flags & TT_CLIENT_NEW)
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200895 continue;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200896 total_one = 0;
897 for (j = 0; j < ETH_ALEN; j++)
898 total_one = crc16_byte(total_one,
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100899 tt_common_entry->addr[j]);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200900 total ^= total_one;
901 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200902 rcu_read_unlock();
903 }
904
905 return total;
906}
907
908static void tt_req_list_free(struct bat_priv *bat_priv)
909{
910 struct tt_req_node *node, *safe;
911
912 spin_lock_bh(&bat_priv->tt_req_list_lock);
913
914 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
915 list_del(&node->list);
916 kfree(node);
917 }
918
919 spin_unlock_bh(&bat_priv->tt_req_list_lock);
920}
921
922void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
923 const unsigned char *tt_buff, uint8_t tt_num_changes)
924{
925 uint16_t tt_buff_len = tt_len(tt_num_changes);
926
927 /* Replace the old buffer only if I received something in the
928 * last OGM (the OGM could carry no changes) */
929 spin_lock_bh(&orig_node->tt_buff_lock);
930 if (tt_buff_len > 0) {
931 kfree(orig_node->tt_buff);
932 orig_node->tt_buff_len = 0;
933 orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
934 if (orig_node->tt_buff) {
935 memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
936 orig_node->tt_buff_len = tt_buff_len;
937 }
938 }
939 spin_unlock_bh(&orig_node->tt_buff_lock);
940}
941
942static void tt_req_purge(struct bat_priv *bat_priv)
943{
944 struct tt_req_node *node, *safe;
945
946 spin_lock_bh(&bat_priv->tt_req_list_lock);
947 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
948 if (is_out_of_time(node->issued_at,
949 TT_REQUEST_TIMEOUT * 1000)) {
950 list_del(&node->list);
951 kfree(node);
952 }
953 }
954 spin_unlock_bh(&bat_priv->tt_req_list_lock);
955}
956
957/* returns the pointer to the new tt_req_node struct if no request
958 * has already been issued for this orig_node, NULL otherwise */
959static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
960 struct orig_node *orig_node)
961{
962 struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
963
964 spin_lock_bh(&bat_priv->tt_req_list_lock);
965 list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) {
966 if (compare_eth(tt_req_node_tmp, orig_node) &&
967 !is_out_of_time(tt_req_node_tmp->issued_at,
968 TT_REQUEST_TIMEOUT * 1000))
969 goto unlock;
970 }
971
972 tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
973 if (!tt_req_node)
974 goto unlock;
975
976 memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
977 tt_req_node->issued_at = jiffies;
978
979 list_add(&tt_req_node->list, &bat_priv->tt_req_list);
980unlock:
981 spin_unlock_bh(&bat_priv->tt_req_list_lock);
982 return tt_req_node;
983}
984
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200985/* data_ptr is useless here, but has to be kept to respect the prototype */
986static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
987{
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100988 const struct tt_common_entry *tt_common_entry = entry_ptr;
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200989
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100990 if (tt_common_entry->flags & TT_CLIENT_NEW)
Antonio Quartulli058d0e22011-07-07 01:40:58 +0200991 return 0;
992 return 1;
993}
994
Antonio Quartullia73105b2011-04-27 14:27:44 +0200995static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
996{
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100997 const struct tt_common_entry *tt_common_entry = entry_ptr;
998 const struct tt_global_entry *tt_global_entry;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200999 const struct orig_node *orig_node = data_ptr;
1000
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001001 if (tt_common_entry->flags & TT_CLIENT_ROAM)
Antonio Quartullicc47f662011-04-27 14:27:57 +02001002 return 0;
1003
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001004 tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
1005 common);
1006
Antonio Quartullia73105b2011-04-27 14:27:44 +02001007 return (tt_global_entry->orig_node == orig_node);
1008}
1009
1010static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
1011 struct hashtable_t *hash,
1012 struct hard_iface *primary_if,
1013 int (*valid_cb)(const void *,
1014 const void *),
1015 void *cb_data)
1016{
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001017 struct tt_common_entry *tt_common_entry;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001018 struct tt_query_packet *tt_response;
1019 struct tt_change *tt_change;
1020 struct hlist_node *node;
1021 struct hlist_head *head;
1022 struct sk_buff *skb = NULL;
1023 uint16_t tt_tot, tt_count;
1024 ssize_t tt_query_size = sizeof(struct tt_query_packet);
Antonio Quartullic90681b2011-10-05 17:05:25 +02001025 uint32_t i;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001026
1027 if (tt_query_size + tt_len > primary_if->soft_iface->mtu) {
1028 tt_len = primary_if->soft_iface->mtu - tt_query_size;
1029 tt_len -= tt_len % sizeof(struct tt_change);
1030 }
1031 tt_tot = tt_len / sizeof(struct tt_change);
1032
1033 skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN);
1034 if (!skb)
1035 goto out;
1036
1037 skb_reserve(skb, ETH_HLEN);
1038 tt_response = (struct tt_query_packet *)skb_put(skb,
1039 tt_query_size + tt_len);
1040 tt_response->ttvn = ttvn;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001041
1042 tt_change = (struct tt_change *)(skb->data + tt_query_size);
1043 tt_count = 0;
1044
1045 rcu_read_lock();
1046 for (i = 0; i < hash->size; i++) {
1047 head = &hash->table[i];
1048
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001049 hlist_for_each_entry_rcu(tt_common_entry, node,
Antonio Quartullia73105b2011-04-27 14:27:44 +02001050 head, hash_entry) {
1051 if (tt_count == tt_tot)
1052 break;
1053
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001054 if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
Antonio Quartullia73105b2011-04-27 14:27:44 +02001055 continue;
1056
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001057 memcpy(tt_change->addr, tt_common_entry->addr,
1058 ETH_ALEN);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001059 tt_change->flags = NO_FLAGS;
1060
1061 tt_count++;
1062 tt_change++;
1063 }
1064 }
1065 rcu_read_unlock();
1066
Antonio Quartulli9d852392011-10-17 14:25:13 +02001067 /* store in the message the number of entries we have successfully
1068 * copied */
1069 tt_response->tt_data = htons(tt_count);
1070
Antonio Quartullia73105b2011-04-27 14:27:44 +02001071out:
1072 return skb;
1073}
1074
Marek Lindnera943cac2011-07-30 13:10:18 +02001075static int send_tt_request(struct bat_priv *bat_priv,
1076 struct orig_node *dst_orig_node,
1077 uint8_t ttvn, uint16_t tt_crc, bool full_table)
Antonio Quartullia73105b2011-04-27 14:27:44 +02001078{
1079 struct sk_buff *skb = NULL;
1080 struct tt_query_packet *tt_request;
1081 struct neigh_node *neigh_node = NULL;
1082 struct hard_iface *primary_if;
1083 struct tt_req_node *tt_req_node = NULL;
1084 int ret = 1;
1085
1086 primary_if = primary_if_get_selected(bat_priv);
1087 if (!primary_if)
1088 goto out;
1089
1090 /* The new tt_req will be issued only if I'm not waiting for a
1091 * reply from the same orig_node yet */
1092 tt_req_node = new_tt_req_node(bat_priv, dst_orig_node);
1093 if (!tt_req_node)
1094 goto out;
1095
1096 skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN);
1097 if (!skb)
1098 goto out;
1099
1100 skb_reserve(skb, ETH_HLEN);
1101
1102 tt_request = (struct tt_query_packet *)skb_put(skb,
1103 sizeof(struct tt_query_packet));
1104
1105 tt_request->packet_type = BAT_TT_QUERY;
1106 tt_request->version = COMPAT_VERSION;
1107 memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1108 memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN);
1109 tt_request->ttl = TTL;
1110 tt_request->ttvn = ttvn;
1111 tt_request->tt_data = tt_crc;
1112 tt_request->flags = TT_REQUEST;
1113
1114 if (full_table)
1115 tt_request->flags |= TT_FULL_TABLE;
1116
1117 neigh_node = orig_node_get_router(dst_orig_node);
1118 if (!neigh_node)
1119 goto out;
1120
1121 bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM "
1122 "[%c]\n", dst_orig_node->orig, neigh_node->addr,
1123 (full_table ? 'F' : '.'));
1124
1125 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1126 ret = 0;
1127
1128out:
1129 if (neigh_node)
1130 neigh_node_free_ref(neigh_node);
1131 if (primary_if)
1132 hardif_free_ref(primary_if);
1133 if (ret)
1134 kfree_skb(skb);
1135 if (ret && tt_req_node) {
1136 spin_lock_bh(&bat_priv->tt_req_list_lock);
1137 list_del(&tt_req_node->list);
1138 spin_unlock_bh(&bat_priv->tt_req_list_lock);
1139 kfree(tt_req_node);
1140 }
1141 return ret;
1142}
1143
1144static bool send_other_tt_response(struct bat_priv *bat_priv,
1145 struct tt_query_packet *tt_request)
1146{
1147 struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL;
1148 struct neigh_node *neigh_node = NULL;
1149 struct hard_iface *primary_if = NULL;
1150 uint8_t orig_ttvn, req_ttvn, ttvn;
1151 int ret = false;
1152 unsigned char *tt_buff;
1153 bool full_table;
1154 uint16_t tt_len, tt_tot;
1155 struct sk_buff *skb = NULL;
1156 struct tt_query_packet *tt_response;
1157
1158 bat_dbg(DBG_TT, bat_priv,
1159 "Received TT_REQUEST from %pM for "
1160 "ttvn: %u (%pM) [%c]\n", tt_request->src,
1161 tt_request->ttvn, tt_request->dst,
1162 (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1163
1164 /* Let's get the orig node of the REAL destination */
Antonio Quartullieb7e2a12011-10-12 14:54:50 +02001165 req_dst_orig_node = orig_hash_find(bat_priv, tt_request->dst);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001166 if (!req_dst_orig_node)
1167 goto out;
1168
Antonio Quartullieb7e2a12011-10-12 14:54:50 +02001169 res_dst_orig_node = orig_hash_find(bat_priv, tt_request->src);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001170 if (!res_dst_orig_node)
1171 goto out;
1172
1173 neigh_node = orig_node_get_router(res_dst_orig_node);
1174 if (!neigh_node)
1175 goto out;
1176
1177 primary_if = primary_if_get_selected(bat_priv);
1178 if (!primary_if)
1179 goto out;
1180
1181 orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1182 req_ttvn = tt_request->ttvn;
1183
Antonio Quartulli015758d2011-07-09 17:52:13 +02001184 /* I don't have the requested data */
Antonio Quartullia73105b2011-04-27 14:27:44 +02001185 if (orig_ttvn != req_ttvn ||
1186 tt_request->tt_data != req_dst_orig_node->tt_crc)
1187 goto out;
1188
Antonio Quartulli015758d2011-07-09 17:52:13 +02001189 /* If the full table has been explicitly requested */
Antonio Quartullia73105b2011-04-27 14:27:44 +02001190 if (tt_request->flags & TT_FULL_TABLE ||
1191 !req_dst_orig_node->tt_buff)
1192 full_table = true;
1193 else
1194 full_table = false;
1195
1196 /* In this version, fragmentation is not implemented, then
1197 * I'll send only one packet with as much TT entries as I can */
1198 if (!full_table) {
1199 spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
1200 tt_len = req_dst_orig_node->tt_buff_len;
1201 tt_tot = tt_len / sizeof(struct tt_change);
1202
1203 skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1204 tt_len + ETH_HLEN);
1205 if (!skb)
1206 goto unlock;
1207
1208 skb_reserve(skb, ETH_HLEN);
1209 tt_response = (struct tt_query_packet *)skb_put(skb,
1210 sizeof(struct tt_query_packet) + tt_len);
1211 tt_response->ttvn = req_ttvn;
1212 tt_response->tt_data = htons(tt_tot);
1213
1214 tt_buff = skb->data + sizeof(struct tt_query_packet);
1215 /* Copy the last orig_node's OGM buffer */
1216 memcpy(tt_buff, req_dst_orig_node->tt_buff,
1217 req_dst_orig_node->tt_buff_len);
1218
1219 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1220 } else {
1221 tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) *
1222 sizeof(struct tt_change);
1223 ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1224
1225 skb = tt_response_fill_table(tt_len, ttvn,
1226 bat_priv->tt_global_hash,
1227 primary_if, tt_global_valid_entry,
1228 req_dst_orig_node);
1229 if (!skb)
1230 goto out;
1231
1232 tt_response = (struct tt_query_packet *)skb->data;
1233 }
1234
1235 tt_response->packet_type = BAT_TT_QUERY;
1236 tt_response->version = COMPAT_VERSION;
1237 tt_response->ttl = TTL;
1238 memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN);
1239 memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1240 tt_response->flags = TT_RESPONSE;
1241
1242 if (full_table)
1243 tt_response->flags |= TT_FULL_TABLE;
1244
1245 bat_dbg(DBG_TT, bat_priv,
1246 "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n",
1247 res_dst_orig_node->orig, neigh_node->addr,
1248 req_dst_orig_node->orig, req_ttvn);
1249
1250 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1251 ret = true;
1252 goto out;
1253
1254unlock:
1255 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1256
1257out:
1258 if (res_dst_orig_node)
1259 orig_node_free_ref(res_dst_orig_node);
1260 if (req_dst_orig_node)
1261 orig_node_free_ref(req_dst_orig_node);
1262 if (neigh_node)
1263 neigh_node_free_ref(neigh_node);
1264 if (primary_if)
1265 hardif_free_ref(primary_if);
1266 if (!ret)
1267 kfree_skb(skb);
1268 return ret;
1269
1270}
1271static bool send_my_tt_response(struct bat_priv *bat_priv,
1272 struct tt_query_packet *tt_request)
1273{
1274 struct orig_node *orig_node = NULL;
1275 struct neigh_node *neigh_node = NULL;
1276 struct hard_iface *primary_if = NULL;
1277 uint8_t my_ttvn, req_ttvn, ttvn;
1278 int ret = false;
1279 unsigned char *tt_buff;
1280 bool full_table;
1281 uint16_t tt_len, tt_tot;
1282 struct sk_buff *skb = NULL;
1283 struct tt_query_packet *tt_response;
1284
1285 bat_dbg(DBG_TT, bat_priv,
1286 "Received TT_REQUEST from %pM for "
1287 "ttvn: %u (me) [%c]\n", tt_request->src,
1288 tt_request->ttvn,
1289 (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1290
1291
1292 my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1293 req_ttvn = tt_request->ttvn;
1294
Antonio Quartullieb7e2a12011-10-12 14:54:50 +02001295 orig_node = orig_hash_find(bat_priv, tt_request->src);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001296 if (!orig_node)
1297 goto out;
1298
1299 neigh_node = orig_node_get_router(orig_node);
1300 if (!neigh_node)
1301 goto out;
1302
1303 primary_if = primary_if_get_selected(bat_priv);
1304 if (!primary_if)
1305 goto out;
1306
1307 /* If the full table has been explicitly requested or the gap
1308 * is too big send the whole local translation table */
1309 if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn ||
1310 !bat_priv->tt_buff)
1311 full_table = true;
1312 else
1313 full_table = false;
1314
1315 /* In this version, fragmentation is not implemented, then
1316 * I'll send only one packet with as much TT entries as I can */
1317 if (!full_table) {
1318 spin_lock_bh(&bat_priv->tt_buff_lock);
1319 tt_len = bat_priv->tt_buff_len;
1320 tt_tot = tt_len / sizeof(struct tt_change);
1321
1322 skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1323 tt_len + ETH_HLEN);
1324 if (!skb)
1325 goto unlock;
1326
1327 skb_reserve(skb, ETH_HLEN);
1328 tt_response = (struct tt_query_packet *)skb_put(skb,
1329 sizeof(struct tt_query_packet) + tt_len);
1330 tt_response->ttvn = req_ttvn;
1331 tt_response->tt_data = htons(tt_tot);
1332
1333 tt_buff = skb->data + sizeof(struct tt_query_packet);
1334 memcpy(tt_buff, bat_priv->tt_buff,
1335 bat_priv->tt_buff_len);
1336 spin_unlock_bh(&bat_priv->tt_buff_lock);
1337 } else {
1338 tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) *
1339 sizeof(struct tt_change);
1340 ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1341
1342 skb = tt_response_fill_table(tt_len, ttvn,
1343 bat_priv->tt_local_hash,
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001344 primary_if, tt_local_valid_entry,
1345 NULL);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001346 if (!skb)
1347 goto out;
1348
1349 tt_response = (struct tt_query_packet *)skb->data;
1350 }
1351
1352 tt_response->packet_type = BAT_TT_QUERY;
1353 tt_response->version = COMPAT_VERSION;
1354 tt_response->ttl = TTL;
1355 memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1356 memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1357 tt_response->flags = TT_RESPONSE;
1358
1359 if (full_table)
1360 tt_response->flags |= TT_FULL_TABLE;
1361
1362 bat_dbg(DBG_TT, bat_priv,
1363 "Sending TT_RESPONSE to %pM via %pM [%c]\n",
1364 orig_node->orig, neigh_node->addr,
1365 (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1366
1367 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1368 ret = true;
1369 goto out;
1370
1371unlock:
1372 spin_unlock_bh(&bat_priv->tt_buff_lock);
1373out:
1374 if (orig_node)
1375 orig_node_free_ref(orig_node);
1376 if (neigh_node)
1377 neigh_node_free_ref(neigh_node);
1378 if (primary_if)
1379 hardif_free_ref(primary_if);
1380 if (!ret)
1381 kfree_skb(skb);
1382 /* This packet was for me, so it doesn't need to be re-routed */
1383 return true;
1384}
1385
1386bool send_tt_response(struct bat_priv *bat_priv,
1387 struct tt_query_packet *tt_request)
1388{
1389 if (is_my_mac(tt_request->dst))
1390 return send_my_tt_response(bat_priv, tt_request);
1391 else
1392 return send_other_tt_response(bat_priv, tt_request);
1393}
1394
1395static void _tt_update_changes(struct bat_priv *bat_priv,
1396 struct orig_node *orig_node,
1397 struct tt_change *tt_change,
1398 uint16_t tt_num_changes, uint8_t ttvn)
1399{
1400 int i;
1401
1402 for (i = 0; i < tt_num_changes; i++) {
Antonio Quartulli5fbc1592011-06-17 16:11:27 +02001403 if ((tt_change + i)->flags & TT_CLIENT_DEL)
Antonio Quartullia73105b2011-04-27 14:27:44 +02001404 tt_global_del(bat_priv, orig_node,
1405 (tt_change + i)->addr,
Antonio Quartullicc47f662011-04-27 14:27:57 +02001406 "tt removed by changes",
1407 (tt_change + i)->flags & TT_CLIENT_ROAM);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001408 else
1409 if (!tt_global_add(bat_priv, orig_node,
Antonio Quartullibc279082011-07-07 15:35:35 +02001410 (tt_change + i)->addr, ttvn, false,
1411 (tt_change + i)->flags &
1412 TT_CLIENT_WIFI))
Antonio Quartullia73105b2011-04-27 14:27:44 +02001413 /* In case of problem while storing a
1414 * global_entry, we stop the updating
1415 * procedure without committing the
1416 * ttvn change. This will avoid to send
1417 * corrupted data on tt_request
1418 */
1419 return;
1420 }
1421}
1422
1423static void tt_fill_gtable(struct bat_priv *bat_priv,
1424 struct tt_query_packet *tt_response)
1425{
1426 struct orig_node *orig_node = NULL;
1427
1428 orig_node = orig_hash_find(bat_priv, tt_response->src);
1429 if (!orig_node)
1430 goto out;
1431
1432 /* Purge the old table first.. */
1433 tt_global_del_orig(bat_priv, orig_node, "Received full table");
1434
1435 _tt_update_changes(bat_priv, orig_node,
1436 (struct tt_change *)(tt_response + 1),
1437 tt_response->tt_data, tt_response->ttvn);
1438
1439 spin_lock_bh(&orig_node->tt_buff_lock);
1440 kfree(orig_node->tt_buff);
1441 orig_node->tt_buff_len = 0;
1442 orig_node->tt_buff = NULL;
1443 spin_unlock_bh(&orig_node->tt_buff_lock);
1444
1445 atomic_set(&orig_node->last_ttvn, tt_response->ttvn);
1446
1447out:
1448 if (orig_node)
1449 orig_node_free_ref(orig_node);
1450}
1451
Marek Lindnera943cac2011-07-30 13:10:18 +02001452static void tt_update_changes(struct bat_priv *bat_priv,
1453 struct orig_node *orig_node,
1454 uint16_t tt_num_changes, uint8_t ttvn,
1455 struct tt_change *tt_change)
Antonio Quartullia73105b2011-04-27 14:27:44 +02001456{
1457 _tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes,
1458 ttvn);
1459
1460 tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change,
1461 tt_num_changes);
1462 atomic_set(&orig_node->last_ttvn, ttvn);
1463}
1464
1465bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
1466{
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001467 struct tt_local_entry *tt_local_entry = NULL;
1468 bool ret = false;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001469
Antonio Quartullia73105b2011-04-27 14:27:44 +02001470 tt_local_entry = tt_local_hash_find(bat_priv, addr);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001471 if (!tt_local_entry)
1472 goto out;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001473 /* Check if the client has been logically deleted (but is kept for
1474 * consistency purpose) */
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001475 if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001476 goto out;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001477 ret = true;
1478out:
Antonio Quartullia73105b2011-04-27 14:27:44 +02001479 if (tt_local_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001480 tt_local_entry_free_ref(tt_local_entry);
1481 return ret;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001482}
1483
1484void handle_tt_response(struct bat_priv *bat_priv,
1485 struct tt_query_packet *tt_response)
1486{
1487 struct tt_req_node *node, *safe;
1488 struct orig_node *orig_node = NULL;
1489
1490 bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for "
1491 "ttvn %d t_size: %d [%c]\n",
1492 tt_response->src, tt_response->ttvn,
1493 tt_response->tt_data,
1494 (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1495
1496 orig_node = orig_hash_find(bat_priv, tt_response->src);
1497 if (!orig_node)
1498 goto out;
1499
1500 if (tt_response->flags & TT_FULL_TABLE)
1501 tt_fill_gtable(bat_priv, tt_response);
1502 else
1503 tt_update_changes(bat_priv, orig_node, tt_response->tt_data,
1504 tt_response->ttvn,
1505 (struct tt_change *)(tt_response + 1));
1506
1507 /* Delete the tt_req_node from pending tt_requests list */
1508 spin_lock_bh(&bat_priv->tt_req_list_lock);
1509 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
1510 if (!compare_eth(node->addr, tt_response->src))
1511 continue;
1512 list_del(&node->list);
1513 kfree(node);
1514 }
1515 spin_unlock_bh(&bat_priv->tt_req_list_lock);
1516
1517 /* Recalculate the CRC for this orig_node and store it */
Antonio Quartullia73105b2011-04-27 14:27:44 +02001518 orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
Antonio Quartullicc47f662011-04-27 14:27:57 +02001519 /* Roaming phase is over: tables are in sync again. I can
1520 * unset the flag */
1521 orig_node->tt_poss_change = false;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001522out:
1523 if (orig_node)
1524 orig_node_free_ref(orig_node);
1525}
1526
1527int tt_init(struct bat_priv *bat_priv)
1528{
1529 if (!tt_local_init(bat_priv))
1530 return 0;
1531
1532 if (!tt_global_init(bat_priv))
1533 return 0;
1534
1535 tt_start_timer(bat_priv);
1536
1537 return 1;
1538}
1539
Antonio Quartullicc47f662011-04-27 14:27:57 +02001540static void tt_roam_list_free(struct bat_priv *bat_priv)
Antonio Quartullia73105b2011-04-27 14:27:44 +02001541{
Antonio Quartullicc47f662011-04-27 14:27:57 +02001542 struct tt_roam_node *node, *safe;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001543
Antonio Quartullicc47f662011-04-27 14:27:57 +02001544 spin_lock_bh(&bat_priv->tt_roam_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001545
Antonio Quartullicc47f662011-04-27 14:27:57 +02001546 list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1547 list_del(&node->list);
1548 kfree(node);
1549 }
1550
1551 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1552}
1553
1554static void tt_roam_purge(struct bat_priv *bat_priv)
1555{
1556 struct tt_roam_node *node, *safe;
1557
1558 spin_lock_bh(&bat_priv->tt_roam_list_lock);
1559 list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1560 if (!is_out_of_time(node->first_time,
1561 ROAMING_MAX_TIME * 1000))
1562 continue;
1563
1564 list_del(&node->list);
1565 kfree(node);
1566 }
1567 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1568}
1569
1570/* This function checks whether the client already reached the
1571 * maximum number of possible roaming phases. In this case the ROAMING_ADV
1572 * will not be sent.
1573 *
1574 * returns true if the ROAMING_ADV can be sent, false otherwise */
1575static bool tt_check_roam_count(struct bat_priv *bat_priv,
1576 uint8_t *client)
1577{
1578 struct tt_roam_node *tt_roam_node;
1579 bool ret = false;
1580
1581 spin_lock_bh(&bat_priv->tt_roam_list_lock);
1582 /* The new tt_req will be issued only if I'm not waiting for a
1583 * reply from the same orig_node yet */
1584 list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) {
1585 if (!compare_eth(tt_roam_node->addr, client))
1586 continue;
1587
1588 if (is_out_of_time(tt_roam_node->first_time,
1589 ROAMING_MAX_TIME * 1000))
1590 continue;
1591
1592 if (!atomic_dec_not_zero(&tt_roam_node->counter))
1593 /* Sorry, you roamed too many times! */
1594 goto unlock;
1595 ret = true;
1596 break;
1597 }
1598
1599 if (!ret) {
1600 tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
1601 if (!tt_roam_node)
1602 goto unlock;
1603
1604 tt_roam_node->first_time = jiffies;
1605 atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1);
1606 memcpy(tt_roam_node->addr, client, ETH_ALEN);
1607
1608 list_add(&tt_roam_node->list, &bat_priv->tt_roam_list);
1609 ret = true;
1610 }
1611
1612unlock:
1613 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1614 return ret;
1615}
1616
1617void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
1618 struct orig_node *orig_node)
1619{
1620 struct neigh_node *neigh_node = NULL;
1621 struct sk_buff *skb = NULL;
1622 struct roam_adv_packet *roam_adv_packet;
1623 int ret = 1;
1624 struct hard_iface *primary_if;
1625
1626 /* before going on we have to check whether the client has
1627 * already roamed to us too many times */
1628 if (!tt_check_roam_count(bat_priv, client))
1629 goto out;
1630
1631 skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
1632 if (!skb)
1633 goto out;
1634
1635 skb_reserve(skb, ETH_HLEN);
1636
1637 roam_adv_packet = (struct roam_adv_packet *)skb_put(skb,
1638 sizeof(struct roam_adv_packet));
1639
1640 roam_adv_packet->packet_type = BAT_ROAM_ADV;
1641 roam_adv_packet->version = COMPAT_VERSION;
1642 roam_adv_packet->ttl = TTL;
1643 primary_if = primary_if_get_selected(bat_priv);
1644 if (!primary_if)
1645 goto out;
1646 memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1647 hardif_free_ref(primary_if);
1648 memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN);
1649 memcpy(roam_adv_packet->client, client, ETH_ALEN);
1650
1651 neigh_node = orig_node_get_router(orig_node);
1652 if (!neigh_node)
1653 goto out;
1654
1655 bat_dbg(DBG_TT, bat_priv,
1656 "Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
1657 orig_node->orig, client, neigh_node->addr);
1658
1659 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1660 ret = 0;
1661
1662out:
1663 if (neigh_node)
1664 neigh_node_free_ref(neigh_node);
1665 if (ret)
1666 kfree_skb(skb);
1667 return;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001668}
1669
1670static void tt_purge(struct work_struct *work)
1671{
1672 struct delayed_work *delayed_work =
1673 container_of(work, struct delayed_work, work);
1674 struct bat_priv *bat_priv =
1675 container_of(delayed_work, struct bat_priv, tt_work);
1676
1677 tt_local_purge(bat_priv);
Antonio Quartullicc47f662011-04-27 14:27:57 +02001678 tt_global_roam_purge(bat_priv);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001679 tt_req_purge(bat_priv);
Antonio Quartullicc47f662011-04-27 14:27:57 +02001680 tt_roam_purge(bat_priv);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001681
1682 tt_start_timer(bat_priv);
1683}
Antonio Quartullicc47f662011-04-27 14:27:57 +02001684
1685void tt_free(struct bat_priv *bat_priv)
1686{
1687 cancel_delayed_work_sync(&bat_priv->tt_work);
1688
1689 tt_local_table_free(bat_priv);
1690 tt_global_table_free(bat_priv);
1691 tt_req_list_free(bat_priv);
1692 tt_changes_list_free(bat_priv);
1693 tt_roam_list_free(bat_priv);
1694
1695 kfree(bat_priv->tt_buff);
1696}
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001697
Antonio Quartulli697f2532011-11-07 16:47:01 +01001698/* This function will enable or disable the specified flags for all the entries
1699 * in the given hash table and returns the number of modified entries */
1700static uint16_t tt_set_flags(struct hashtable_t *hash, uint16_t flags,
1701 bool enable)
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001702{
Antonio Quartullic90681b2011-10-05 17:05:25 +02001703 uint32_t i;
Antonio Quartulli697f2532011-11-07 16:47:01 +01001704 uint16_t changed_num = 0;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001705 struct hlist_head *head;
1706 struct hlist_node *node;
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001707 struct tt_common_entry *tt_common_entry;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001708
1709 if (!hash)
Antonio Quartulli697f2532011-11-07 16:47:01 +01001710 goto out;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001711
1712 for (i = 0; i < hash->size; i++) {
1713 head = &hash->table[i];
1714
1715 rcu_read_lock();
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001716 hlist_for_each_entry_rcu(tt_common_entry, node,
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001717 head, hash_entry) {
Antonio Quartulli697f2532011-11-07 16:47:01 +01001718 if (enable) {
1719 if ((tt_common_entry->flags & flags) == flags)
1720 continue;
1721 tt_common_entry->flags |= flags;
1722 } else {
1723 if (!(tt_common_entry->flags & flags))
1724 continue;
1725 tt_common_entry->flags &= ~flags;
1726 }
1727 changed_num++;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001728 }
1729 rcu_read_unlock();
1730 }
Antonio Quartulli697f2532011-11-07 16:47:01 +01001731out:
1732 return changed_num;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001733}
1734
1735/* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
1736static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
1737{
1738 struct hashtable_t *hash = bat_priv->tt_local_hash;
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001739 struct tt_common_entry *tt_common_entry;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001740 struct tt_local_entry *tt_local_entry;
1741 struct hlist_node *node, *node_tmp;
1742 struct hlist_head *head;
1743 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartullic90681b2011-10-05 17:05:25 +02001744 uint32_t i;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001745
1746 if (!hash)
1747 return;
1748
1749 for (i = 0; i < hash->size; i++) {
1750 head = &hash->table[i];
1751 list_lock = &hash->list_locks[i];
1752
1753 spin_lock_bh(list_lock);
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001754 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001755 head, hash_entry) {
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001756 if (!(tt_common_entry->flags & TT_CLIENT_PENDING))
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001757 continue;
1758
1759 bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry "
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001760 "(%pM): pending\n", tt_common_entry->addr);
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001761
1762 atomic_dec(&bat_priv->num_local_tt);
1763 hlist_del_rcu(node);
Antonio Quartulli48100ba2011-10-30 12:17:33 +01001764 tt_local_entry = container_of(tt_common_entry,
1765 struct tt_local_entry,
1766 common);
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001767 tt_local_entry_free_ref(tt_local_entry);
1768 }
1769 spin_unlock_bh(list_lock);
1770 }
1771
1772}
1773
1774void tt_commit_changes(struct bat_priv *bat_priv)
1775{
Antonio Quartulli697f2532011-11-07 16:47:01 +01001776 uint16_t changed_num = tt_set_flags(bat_priv->tt_local_hash,
1777 TT_CLIENT_NEW, false);
1778 /* all the reset entries have now to be effectively counted as local
1779 * entries */
1780 atomic_add(changed_num, &bat_priv->num_local_tt);
Antonio Quartulli058d0e22011-07-07 01:40:58 +02001781 tt_local_purge_pending_clients(bat_priv);
1782
1783 /* Increment the TTVN only once per OGM interval */
1784 atomic_inc(&bat_priv->ttvn);
1785 bat_priv->tt_poss_change = false;
1786}
Antonio Quartulli59b699c2011-07-07 15:35:36 +02001787
1788bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst)
1789{
1790 struct tt_local_entry *tt_local_entry = NULL;
1791 struct tt_global_entry *tt_global_entry = NULL;
1792 bool ret = true;
1793
1794 if (!atomic_read(&bat_priv->ap_isolation))
1795 return false;
1796
1797 tt_local_entry = tt_local_hash_find(bat_priv, dst);
1798 if (!tt_local_entry)
1799 goto out;
1800
1801 tt_global_entry = tt_global_hash_find(bat_priv, src);
1802 if (!tt_global_entry)
1803 goto out;
1804
1805 if (_is_ap_isolated(tt_local_entry, tt_global_entry))
1806 goto out;
1807
1808 ret = false;
1809
1810out:
1811 if (tt_global_entry)
1812 tt_global_entry_free_ref(tt_global_entry);
1813 if (tt_local_entry)
1814 tt_local_entry_free_ref(tt_local_entry);
1815 return ret;
1816}
Marek Lindnera943cac2011-07-30 13:10:18 +02001817
1818void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
1819 const unsigned char *tt_buff, uint8_t tt_num_changes,
1820 uint8_t ttvn, uint16_t tt_crc)
1821{
1822 uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
1823 bool full_table = true;
1824
1825 /* the ttvn increased by one -> we can apply the attached changes */
1826 if (ttvn - orig_ttvn == 1) {
1827 /* the OGM could not contain the changes due to their size or
1828 * because they have already been sent TT_OGM_APPEND_MAX times.
1829 * In this case send a tt request */
1830 if (!tt_num_changes) {
1831 full_table = false;
1832 goto request_table;
1833 }
1834
1835 tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
1836 (struct tt_change *)tt_buff);
1837
1838 /* Even if we received the precomputed crc with the OGM, we
1839 * prefer to recompute it to spot any possible inconsistency
1840 * in the global table */
1841 orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
1842
1843 /* The ttvn alone is not enough to guarantee consistency
1844 * because a single value could represent different states
1845 * (due to the wrap around). Thus a node has to check whether
1846 * the resulting table (after applying the changes) is still
1847 * consistent or not. E.g. a node could disconnect while its
1848 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
1849 * checking the CRC value is mandatory to detect the
1850 * inconsistency */
1851 if (orig_node->tt_crc != tt_crc)
1852 goto request_table;
1853
1854 /* Roaming phase is over: tables are in sync again. I can
1855 * unset the flag */
1856 orig_node->tt_poss_change = false;
1857 } else {
1858 /* if we missed more than one change or our tables are not
1859 * in sync anymore -> request fresh tt data */
1860 if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) {
1861request_table:
1862 bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. "
1863 "Need to retrieve the correct information "
1864 "(ttvn: %u last_ttvn: %u crc: %u last_crc: "
1865 "%u num_changes: %u)\n", orig_node->orig, ttvn,
1866 orig_ttvn, tt_crc, orig_node->tt_crc,
1867 tt_num_changes);
1868 send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
1869 full_table);
1870 return;
1871 }
1872 }
1873}