blob: fe9f8244ac0a743e46b34841d1026bc7319e0bb6 [file] [log] [blame]
Sven Eckelmann9f6446c2015-04-23 13:16:35 +02001/* Copyright (C) 2007-2015 B.A.T.M.A.N. contributors:
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002 *
Antonio Quartulli35c133a2012-03-14 13:03:01 +01003 * Marek Lindner, Simon Wunderlich, Antonio Quartulli
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU General Public
7 * License as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
Antonio Quartulliebf38fb2013-11-03 20:40:48 +010015 * along with this program; if not, see <http://www.gnu.org/licenses/>.
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000016 */
17
18#include "main.h"
19#include "translation-table.h"
20#include "soft-interface.h"
Marek Lindner32ae9b22011-04-20 15:40:58 +020021#include "hard-interface.h"
Antonio Quartullia73105b2011-04-27 14:27:44 +020022#include "send.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000023#include "hash.h"
24#include "originator.h"
Antonio Quartullia73105b2011-04-27 14:27:44 +020025#include "routing.h"
Simon Wunderlich20ff9d52012-01-22 20:00:23 +010026#include "bridge_loop_avoidance.h"
Linus Lüssingc5caf4e2014-02-15 17:47:49 +010027#include "multicast.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000028
Antonio Quartulliced72932013-04-24 16:37:51 +020029#include <linux/crc32c.h>
Antonio Quartullia73105b2011-04-27 14:27:44 +020030
Antonio Quartullidec05072012-11-10 11:00:32 +010031/* hash class keys */
32static struct lock_class_key batadv_tt_local_hash_lock_class_key;
33static struct lock_class_key batadv_tt_global_hash_lock_class_key;
34
Sven Eckelmann56303d32012-06-05 22:31:31 +020035static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client,
Antonio Quartullic018ad32013-06-04 12:11:39 +020036 unsigned short vid,
Sven Eckelmann56303d32012-06-05 22:31:31 +020037 struct batadv_orig_node *orig_node);
Sven Eckelmanna5130882012-05-16 20:23:16 +020038static void batadv_tt_purge(struct work_struct *work);
39static void
Sven Eckelmann56303d32012-06-05 22:31:31 +020040batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry);
Antonio Quartulli30cfd022012-07-05 23:38:29 +020041static void batadv_tt_global_del(struct batadv_priv *bat_priv,
42 struct batadv_orig_node *orig_node,
43 const unsigned char *addr,
Antonio Quartullic018ad32013-06-04 12:11:39 +020044 unsigned short vid, const char *message,
45 bool roaming);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000046
Marek Lindner7aadf882011-02-18 12:28:09 +000047/* returns 1 if they are the same mac addr */
Sven Eckelmanna5130882012-05-16 20:23:16 +020048static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
Marek Lindner7aadf882011-02-18 12:28:09 +000049{
Sven Eckelmann56303d32012-06-05 22:31:31 +020050 const void *data1 = container_of(node, struct batadv_tt_common_entry,
Sven Eckelmann747e4222011-05-14 23:14:50 +020051 hash_entry);
Marek Lindner7aadf882011-02-18 12:28:09 +000052
dingtianhong323813e2013-12-26 19:40:39 +080053 return batadv_compare_eth(data1, data2);
Marek Lindner7aadf882011-02-18 12:28:09 +000054}
55
Antonio Quartullic018ad32013-06-04 12:11:39 +020056/**
57 * batadv_choose_tt - return the index of the tt entry in the hash table
58 * @data: pointer to the tt_common_entry object to map
59 * @size: the size of the hash table
60 *
61 * Returns the hash index where the object represented by 'data' should be
62 * stored at.
63 */
64static inline uint32_t batadv_choose_tt(const void *data, uint32_t size)
65{
66 struct batadv_tt_common_entry *tt;
67 uint32_t hash = 0;
68
69 tt = (struct batadv_tt_common_entry *)data;
Sven Eckelmann36fd61c2015-03-01 09:46:18 +010070 hash = jhash(&tt->addr, ETH_ALEN, hash);
71 hash = jhash(&tt->vid, sizeof(tt->vid), hash);
Antonio Quartullic018ad32013-06-04 12:11:39 +020072
73 return hash % size;
74}
75
76/**
77 * batadv_tt_hash_find - look for a client in the given hash table
78 * @hash: the hash table to search
79 * @addr: the mac address of the client to look for
80 * @vid: VLAN identifier
81 *
82 * Returns a pointer to the tt_common struct belonging to the searched client if
83 * found, NULL otherwise.
84 */
Sven Eckelmann56303d32012-06-05 22:31:31 +020085static struct batadv_tt_common_entry *
Antonio Quartullic018ad32013-06-04 12:11:39 +020086batadv_tt_hash_find(struct batadv_hashtable *hash, const uint8_t *addr,
87 unsigned short vid)
Marek Lindner7aadf882011-02-18 12:28:09 +000088{
Marek Lindner7aadf882011-02-18 12:28:09 +000089 struct hlist_head *head;
Antonio Quartullic018ad32013-06-04 12:11:39 +020090 struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL;
Antonio Quartullic90681b2011-10-05 17:05:25 +020091 uint32_t index;
Marek Lindner7aadf882011-02-18 12:28:09 +000092
93 if (!hash)
94 return NULL;
95
Antonio Quartulli8fdd0152014-01-22 00:42:11 +010096 ether_addr_copy(to_search.addr, addr);
Antonio Quartullic018ad32013-06-04 12:11:39 +020097 to_search.vid = vid;
98
99 index = batadv_choose_tt(&to_search, hash->size);
Marek Lindner7aadf882011-02-18 12:28:09 +0000100 head = &hash->table[index];
101
102 rcu_read_lock();
Antonio Quartullic018ad32013-06-04 12:11:39 +0200103 hlist_for_each_entry_rcu(tt, head, hash_entry) {
104 if (!batadv_compare_eth(tt, addr))
Marek Lindner7aadf882011-02-18 12:28:09 +0000105 continue;
106
Antonio Quartullic018ad32013-06-04 12:11:39 +0200107 if (tt->vid != vid)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200108 continue;
109
Antonio Quartullic018ad32013-06-04 12:11:39 +0200110 if (!atomic_inc_not_zero(&tt->refcount))
111 continue;
112
113 tt_tmp = tt;
Marek Lindner7aadf882011-02-18 12:28:09 +0000114 break;
115 }
116 rcu_read_unlock();
117
Antonio Quartullic018ad32013-06-04 12:11:39 +0200118 return tt_tmp;
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100119}
120
Antonio Quartullic018ad32013-06-04 12:11:39 +0200121/**
122 * batadv_tt_local_hash_find - search the local table for a given client
123 * @bat_priv: the bat priv with all the soft interface information
124 * @addr: the mac address of the client to look for
125 * @vid: VLAN identifier
126 *
127 * Returns a pointer to the corresponding tt_local_entry struct if the client is
128 * found, NULL otherwise.
129 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200130static struct batadv_tt_local_entry *
Antonio Quartullic018ad32013-06-04 12:11:39 +0200131batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr,
132 unsigned short vid)
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100133{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200134 struct batadv_tt_common_entry *tt_common_entry;
135 struct batadv_tt_local_entry *tt_local_entry = NULL;
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100136
Antonio Quartullic018ad32013-06-04 12:11:39 +0200137 tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr,
138 vid);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100139 if (tt_common_entry)
140 tt_local_entry = container_of(tt_common_entry,
Sven Eckelmann56303d32012-06-05 22:31:31 +0200141 struct batadv_tt_local_entry,
142 common);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100143 return tt_local_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +0000144}
145
Antonio Quartullic018ad32013-06-04 12:11:39 +0200146/**
147 * batadv_tt_global_hash_find - search the global table for a given client
148 * @bat_priv: the bat priv with all the soft interface information
149 * @addr: the mac address of the client to look for
150 * @vid: VLAN identifier
151 *
152 * Returns a pointer to the corresponding tt_global_entry struct if the client
153 * is found, NULL otherwise.
154 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200155static struct batadv_tt_global_entry *
Antonio Quartullic018ad32013-06-04 12:11:39 +0200156batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr,
157 unsigned short vid)
Marek Lindner7aadf882011-02-18 12:28:09 +0000158{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200159 struct batadv_tt_common_entry *tt_common_entry;
160 struct batadv_tt_global_entry *tt_global_entry = NULL;
Marek Lindner7aadf882011-02-18 12:28:09 +0000161
Antonio Quartullic018ad32013-06-04 12:11:39 +0200162 tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr,
163 vid);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100164 if (tt_common_entry)
165 tt_global_entry = container_of(tt_common_entry,
Sven Eckelmann56303d32012-06-05 22:31:31 +0200166 struct batadv_tt_global_entry,
167 common);
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100168 return tt_global_entry;
Marek Lindner7aadf882011-02-18 12:28:09 +0000169}
170
Sven Eckelmanna5130882012-05-16 20:23:16 +0200171static void
Sven Eckelmann56303d32012-06-05 22:31:31 +0200172batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200173{
Antonio Quartulli48100ba2011-10-30 12:17:33 +0100174 if (atomic_dec_and_test(&tt_local_entry->common.refcount))
175 kfree_rcu(tt_local_entry, common.rcu);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200176}
177
Antonio Quartulli21026052013-05-07 00:29:22 +0200178/**
179 * batadv_tt_global_entry_free_ref - decrement the refcounter for a
180 * tt_global_entry and possibly free it
181 * @tt_global_entry: the object to free
182 */
Sven Eckelmanna5130882012-05-16 20:23:16 +0200183static void
Sven Eckelmann56303d32012-06-05 22:31:31 +0200184batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200185{
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200186 if (atomic_dec_and_test(&tt_global_entry->common.refcount)) {
Sven Eckelmanna5130882012-05-16 20:23:16 +0200187 batadv_tt_global_del_orig_list(tt_global_entry);
Antonio Quartulli21026052013-05-07 00:29:22 +0200188 kfree_rcu(tt_global_entry, common.rcu);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200189 }
190}
191
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +0100192/**
193 * batadv_tt_global_hash_count - count the number of orig entries
194 * @hash: hash table containing the tt entries
195 * @addr: the mac address of the client to count entries for
196 * @vid: VLAN identifier
197 *
198 * Return the number of originators advertising the given address/data
199 * (excluding ourself).
200 */
201int batadv_tt_global_hash_count(struct batadv_priv *bat_priv,
202 const uint8_t *addr, unsigned short vid)
203{
204 struct batadv_tt_global_entry *tt_global_entry;
205 int count;
206
207 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
208 if (!tt_global_entry)
209 return 0;
210
211 count = atomic_read(&tt_global_entry->orig_list_count);
212 batadv_tt_global_entry_free_ref(tt_global_entry);
213
214 return count;
215}
216
Sven Eckelmanna5130882012-05-16 20:23:16 +0200217static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200218{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200219 struct batadv_tt_orig_list_entry *orig_entry;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200220
Sven Eckelmann56303d32012-06-05 22:31:31 +0200221 orig_entry = container_of(rcu, struct batadv_tt_orig_list_entry, rcu);
Linus Lüssing72822222013-04-15 21:43:29 +0800222
223 /* We are in an rcu callback here, therefore we cannot use
224 * batadv_orig_node_free_ref() and its call_rcu():
225 * An rcu_barrier() wouldn't wait for that to finish
226 */
227 batadv_orig_node_free_ref_now(orig_entry->orig_node);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200228 kfree(orig_entry);
229}
230
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200231/**
232 * batadv_tt_local_size_mod - change the size by v of the local table identified
233 * by vid
234 * @bat_priv: the bat priv with all the soft interface information
235 * @vid: the VLAN identifier of the sub-table to change
236 * @v: the amount to sum to the local table size
237 */
238static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv,
239 unsigned short vid, int v)
240{
241 struct batadv_softif_vlan *vlan;
242
243 vlan = batadv_softif_vlan_get(bat_priv, vid);
244 if (!vlan)
245 return;
246
247 atomic_add(v, &vlan->tt.num_entries);
248
249 batadv_softif_vlan_free_ref(vlan);
250}
251
252/**
253 * batadv_tt_local_size_inc - increase by one the local table size for the given
254 * vid
255 * @bat_priv: the bat priv with all the soft interface information
256 * @vid: the VLAN identifier
257 */
258static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv,
259 unsigned short vid)
260{
261 batadv_tt_local_size_mod(bat_priv, vid, 1);
262}
263
264/**
265 * batadv_tt_local_size_dec - decrease by one the local table size for the given
266 * vid
267 * @bat_priv: the bat priv with all the soft interface information
268 * @vid: the VLAN identifier
269 */
270static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv,
271 unsigned short vid)
272{
273 batadv_tt_local_size_mod(bat_priv, vid, -1);
274}
275
276/**
277 * batadv_tt_global_size_mod - change the size by v of the local table
278 * identified by vid
279 * @bat_priv: the bat priv with all the soft interface information
280 * @vid: the VLAN identifier
281 * @v: the amount to sum to the global table size
282 */
283static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node,
284 unsigned short vid, int v)
285{
286 struct batadv_orig_node_vlan *vlan;
287
288 vlan = batadv_orig_node_vlan_new(orig_node, vid);
289 if (!vlan)
290 return;
291
292 if (atomic_add_return(v, &vlan->tt.num_entries) == 0) {
293 spin_lock_bh(&orig_node->vlan_list_lock);
294 list_del_rcu(&vlan->list);
295 spin_unlock_bh(&orig_node->vlan_list_lock);
296 batadv_orig_node_vlan_free_ref(vlan);
297 }
298
299 batadv_orig_node_vlan_free_ref(vlan);
300}
301
302/**
303 * batadv_tt_global_size_inc - increase by one the global table size for the
304 * given vid
305 * @orig_node: the originator which global table size has to be decreased
306 * @vid: the vlan identifier
307 */
308static void batadv_tt_global_size_inc(struct batadv_orig_node *orig_node,
309 unsigned short vid)
310{
311 batadv_tt_global_size_mod(orig_node, vid, 1);
312}
313
314/**
315 * batadv_tt_global_size_dec - decrease by one the global table size for the
316 * given vid
317 * @orig_node: the originator which global table size has to be decreased
318 * @vid: the vlan identifier
319 */
320static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node,
321 unsigned short vid)
322{
323 batadv_tt_global_size_mod(orig_node, vid, -1);
324}
325
Sven Eckelmanna5130882012-05-16 20:23:16 +0200326static void
Sven Eckelmann56303d32012-06-05 22:31:31 +0200327batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200328{
Antonio Quartullid657e622012-07-01 14:09:12 +0200329 if (!atomic_dec_and_test(&orig_entry->refcount))
330 return;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200331
Sven Eckelmanna5130882012-05-16 20:23:16 +0200332 call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200333}
334
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +0200335/**
336 * batadv_tt_local_event - store a local TT event (ADD/DEL)
337 * @bat_priv: the bat priv with all the soft interface information
338 * @tt_local_entry: the TT entry involved in the event
339 * @event_flags: flags to store in the event structure
340 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200341static void batadv_tt_local_event(struct batadv_priv *bat_priv,
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +0200342 struct batadv_tt_local_entry *tt_local_entry,
343 uint8_t event_flags)
Antonio Quartullia73105b2011-04-27 14:27:44 +0200344{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200345 struct batadv_tt_change_node *tt_change_node, *entry, *safe;
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +0200346 struct batadv_tt_common_entry *common = &tt_local_entry->common;
347 uint8_t flags = common->flags | event_flags;
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200348 bool event_removed = false;
349 bool del_op_requested, del_op_entry;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200350
351 tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200352 if (!tt_change_node)
353 return;
354
Antonio Quartulliff66c972011-06-30 01:14:00 +0200355 tt_change_node->change.flags = flags;
Antonio Quartullica663042013-12-15 13:26:55 +0100356 memset(tt_change_node->change.reserved, 0,
357 sizeof(tt_change_node->change.reserved));
Antonio Quartulli8fdd0152014-01-22 00:42:11 +0100358 ether_addr_copy(tt_change_node->change.addr, common->addr);
Antonio Quartullic018ad32013-06-04 12:11:39 +0200359 tt_change_node->change.vid = htons(common->vid);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200360
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200361 del_op_requested = flags & BATADV_TT_CLIENT_DEL;
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200362
363 /* check for ADD+DEL or DEL+ADD events */
Sven Eckelmann807736f2012-07-15 22:26:51 +0200364 spin_lock_bh(&bat_priv->tt.changes_list_lock);
365 list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200366 list) {
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +0200367 if (!batadv_compare_eth(entry->change.addr, common->addr))
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200368 continue;
369
370 /* DEL+ADD in the same orig interval have no effect and can be
371 * removed to avoid silly behaviour on the receiver side. The
372 * other way around (ADD+DEL) can happen in case of roaming of
373 * a client still in the NEW state. Roaming of NEW clients is
374 * now possible due to automatically recognition of "temporary"
375 * clients
376 */
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200377 del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL;
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200378 if (!del_op_requested && del_op_entry)
379 goto del;
380 if (del_op_requested && !del_op_entry)
381 goto del;
Antonio Quartulli3c4f7ab2013-10-13 02:50:19 +0200382
383 /* this is a second add in the same originator interval. It
384 * means that flags have been changed: update them!
385 */
386 if (!del_op_requested && !del_op_entry)
387 entry->change.flags = flags;
388
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200389 continue;
390del:
391 list_del(&entry->list);
392 kfree(entry);
Jesper Juhl155e4e12012-08-07 08:32:34 +0000393 kfree(tt_change_node);
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200394 event_removed = true;
395 goto unlock;
396 }
397
Antonio Quartullia73105b2011-04-27 14:27:44 +0200398 /* track the change in the OGMinterval list */
Sven Eckelmann807736f2012-07-15 22:26:51 +0200399 list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list);
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200400
401unlock:
Sven Eckelmann807736f2012-07-15 22:26:51 +0200402 spin_unlock_bh(&bat_priv->tt.changes_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200403
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200404 if (event_removed)
Sven Eckelmann807736f2012-07-15 22:26:51 +0200405 atomic_dec(&bat_priv->tt.local_changes);
Antonio Quartulli3b643de2012-05-25 00:00:42 +0200406 else
Sven Eckelmann807736f2012-07-15 22:26:51 +0200407 atomic_inc(&bat_priv->tt.local_changes);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200408}
409
Marek Lindner335fbe02013-04-23 21:40:02 +0800410/**
411 * batadv_tt_len - compute length in bytes of given number of tt changes
412 * @changes_num: number of tt changes
413 *
414 * Returns computed length in bytes.
415 */
416static int batadv_tt_len(int changes_num)
Antonio Quartullia73105b2011-04-27 14:27:44 +0200417{
Marek Lindner335fbe02013-04-23 21:40:02 +0800418 return changes_num * sizeof(struct batadv_tvlv_tt_change);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200419}
420
Antonio Quartulli298e6e62013-05-28 13:14:27 +0200421/**
422 * batadv_tt_entries - compute the number of entries fitting in tt_len bytes
423 * @tt_len: available space
424 *
425 * Returns the number of entries.
426 */
427static uint16_t batadv_tt_entries(uint16_t tt_len)
428{
429 return tt_len / batadv_tt_len(1);
430}
431
Marek Lindnera19d3d82013-05-27 15:33:25 +0800432/**
433 * batadv_tt_local_table_transmit_size - calculates the local translation table
434 * size when transmitted over the air
435 * @bat_priv: the bat priv with all the soft interface information
436 *
437 * Returns local translation table size in bytes.
438 */
439static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv)
440{
441 uint16_t num_vlan = 0, tt_local_entries = 0;
442 struct batadv_softif_vlan *vlan;
443 int hdr_size;
444
445 rcu_read_lock();
446 hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
447 num_vlan++;
448 tt_local_entries += atomic_read(&vlan->tt.num_entries);
449 }
450 rcu_read_unlock();
451
452 /* header size of tvlv encapsulated tt response payload */
453 hdr_size = sizeof(struct batadv_unicast_tvlv_packet);
454 hdr_size += sizeof(struct batadv_tvlv_hdr);
455 hdr_size += sizeof(struct batadv_tvlv_tt_data);
456 hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data);
457
458 return hdr_size + batadv_tt_len(tt_local_entries);
459}
460
Sven Eckelmann56303d32012-06-05 22:31:31 +0200461static int batadv_tt_local_init(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000462{
Sven Eckelmann807736f2012-07-15 22:26:51 +0200463 if (bat_priv->tt.local_hash)
Sven Eckelmann5346c352012-05-05 13:27:28 +0200464 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000465
Sven Eckelmann807736f2012-07-15 22:26:51 +0200466 bat_priv->tt.local_hash = batadv_hash_new(1024);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000467
Sven Eckelmann807736f2012-07-15 22:26:51 +0200468 if (!bat_priv->tt.local_hash)
Sven Eckelmann5346c352012-05-05 13:27:28 +0200469 return -ENOMEM;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000470
Antonio Quartullidec05072012-11-10 11:00:32 +0100471 batadv_hash_set_lock_class(bat_priv->tt.local_hash,
472 &batadv_tt_local_hash_lock_class_key);
473
Sven Eckelmann5346c352012-05-05 13:27:28 +0200474 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000475}
476
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200477static void batadv_tt_global_free(struct batadv_priv *bat_priv,
478 struct batadv_tt_global_entry *tt_global,
479 const char *message)
480{
481 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +0200482 "Deleting global tt entry %pM (vid: %d): %s\n",
483 tt_global->common.addr,
484 BATADV_PRINT_VID(tt_global->common.vid), message);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200485
486 batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt,
Antonio Quartullic018ad32013-06-04 12:11:39 +0200487 batadv_choose_tt, &tt_global->common);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200488 batadv_tt_global_entry_free_ref(tt_global);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200489}
490
Antonio Quartullic018ad32013-06-04 12:11:39 +0200491/**
492 * batadv_tt_local_add - add a new client to the local table or update an
493 * existing client
494 * @soft_iface: netdev struct of the mesh interface
495 * @addr: the mac address of the client to add
496 * @vid: VLAN identifier
497 * @ifindex: index of the interface where the client is connected to (useful to
498 * identify wireless clients)
Antonio Quartulli9464d072013-11-16 12:03:48 +0100499 * @mark: the value contained in the skb->mark field of the received packet (if
500 * any)
Marek Lindnera19d3d82013-05-27 15:33:25 +0800501 *
502 * Returns true if the client was successfully added, false otherwise.
Antonio Quartullic018ad32013-06-04 12:11:39 +0200503 */
Marek Lindnera19d3d82013-05-27 15:33:25 +0800504bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
Antonio Quartulli9464d072013-11-16 12:03:48 +0100505 unsigned short vid, int ifindex, uint32_t mark)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000506{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200507 struct batadv_priv *bat_priv = netdev_priv(soft_iface);
Sven Eckelmann170173b2012-10-07 12:02:22 +0200508 struct batadv_tt_local_entry *tt_local;
Linus Lüssingc5caf4e2014-02-15 17:47:49 +0100509 struct batadv_tt_global_entry *tt_global = NULL;
Antonio Quartulli35df3b22014-05-08 17:13:15 +0200510 struct batadv_softif_vlan *vlan;
Antonio Quartulli0c69aec2013-10-13 02:50:18 +0200511 struct net_device *in_dev = NULL;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200512 struct hlist_head *head;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200513 struct batadv_tt_orig_list_entry *orig_entry;
Marek Lindnera19d3d82013-05-27 15:33:25 +0800514 int hash_added, table_size, packet_size_max;
515 bool ret = false, roamed_back = false;
Antonio Quartulli3c4f7ab2013-10-13 02:50:19 +0200516 uint8_t remote_flags;
Antonio Quartulli9464d072013-11-16 12:03:48 +0100517 uint32_t match_mark;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000518
Antonio Quartulli0c69aec2013-10-13 02:50:18 +0200519 if (ifindex != BATADV_NULL_IFINDEX)
520 in_dev = dev_get_by_index(&init_net, ifindex);
521
Antonio Quartullic018ad32013-06-04 12:11:39 +0200522 tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
Linus Lüssingc5caf4e2014-02-15 17:47:49 +0100523
524 if (!is_multicast_ether_addr(addr))
525 tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000526
Antonio Quartulli47c94652012-09-23 22:38:35 +0200527 if (tt_local) {
528 tt_local->last_seen = jiffies;
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200529 if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) {
530 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +0200531 "Re-adding pending client %pM (vid: %d)\n",
532 addr, BATADV_PRINT_VID(vid));
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200533 /* whatever the reason why the PENDING flag was set,
534 * this is a client which was enqueued to be removed in
535 * this orig_interval. Since it popped up again, the
536 * flag can be reset like it was never enqueued
537 */
538 tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING;
539 goto add_event;
540 }
541
542 if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) {
543 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +0200544 "Roaming client %pM (vid: %d) came back to its original location\n",
545 addr, BATADV_PRINT_VID(vid));
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200546 /* the ROAM flag is set because this client roamed away
547 * and the node got a roaming_advertisement message. Now
548 * that the client popped up again at its original
549 * location such flag can be unset
550 */
551 tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM;
552 roamed_back = true;
553 }
554 goto check_roaming;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000555 }
556
Marek Lindnera19d3d82013-05-27 15:33:25 +0800557 /* Ignore the client if we cannot send it in a full table response. */
558 table_size = batadv_tt_local_table_transmit_size(bat_priv);
559 table_size += batadv_tt_len(1);
560 packet_size_max = atomic_read(&bat_priv->packet_size_max);
561 if (table_size > packet_size_max) {
562 net_ratelimited_function(batadv_info, soft_iface,
563 "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
564 table_size, packet_size_max, addr);
565 goto out;
566 }
567
Antonio Quartulli47c94652012-09-23 22:38:35 +0200568 tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC);
569 if (!tt_local)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200570 goto out;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200571
Antonio Quartulli35df3b22014-05-08 17:13:15 +0200572 /* increase the refcounter of the related vlan */
573 vlan = batadv_softif_vlan_get(bat_priv, vid);
574
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200575 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +0200576 "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
577 addr, BATADV_PRINT_VID(vid),
Sven Eckelmann807736f2012-07-15 22:26:51 +0200578 (uint8_t)atomic_read(&bat_priv->tt.vn));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000579
Antonio Quartulli8fdd0152014-01-22 00:42:11 +0100580 ether_addr_copy(tt_local->common.addr, addr);
Antonio Quartulli8425ec62012-11-19 09:01:44 +0100581 /* The local entry has to be marked as NEW to avoid to send it in
582 * a full table response going out before the next ttvn increment
583 * (consistency check)
584 */
585 tt_local->common.flags = BATADV_TT_CLIENT_NEW;
Antonio Quartullic018ad32013-06-04 12:11:39 +0200586 tt_local->common.vid = vid;
Antonio Quartulli0c69aec2013-10-13 02:50:18 +0200587 if (batadv_is_wifi_netdev(in_dev))
Antonio Quartulli47c94652012-09-23 22:38:35 +0200588 tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
589 atomic_set(&tt_local->common.refcount, 2);
590 tt_local->last_seen = jiffies;
591 tt_local->common.added_at = tt_local->last_seen;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000592
Linus Lüssingc5caf4e2014-02-15 17:47:49 +0100593 /* the batman interface mac and multicast addresses should never be
594 * purged
595 */
596 if (batadv_compare_eth(addr, soft_iface->dev_addr) ||
597 is_multicast_ether_addr(addr))
Antonio Quartulli47c94652012-09-23 22:38:35 +0200598 tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000599
Sven Eckelmann807736f2012-07-15 22:26:51 +0200600 hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
Antonio Quartullic018ad32013-06-04 12:11:39 +0200601 batadv_choose_tt, &tt_local->common,
Antonio Quartulli47c94652012-09-23 22:38:35 +0200602 &tt_local->common.hash_entry);
Simon Wunderlich80b3f582011-11-02 20:26:45 +0100603
604 if (unlikely(hash_added != 0)) {
605 /* remove the reference for the hash */
Antonio Quartulli47c94652012-09-23 22:38:35 +0200606 batadv_tt_local_entry_free_ref(tt_local);
Antonio Quartulli35df3b22014-05-08 17:13:15 +0200607 batadv_softif_vlan_free_ref(vlan);
Simon Wunderlich80b3f582011-11-02 20:26:45 +0100608 goto out;
609 }
610
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200611add_event:
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +0200612 batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
Antonio Quartulliff66c972011-06-30 01:14:00 +0200613
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200614check_roaming:
615 /* Check whether it is a roaming, but don't do anything if the roaming
616 * process has already been handled
617 */
618 if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) {
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200619 /* These node are probably going to update their tt table */
Antonio Quartulli47c94652012-09-23 22:38:35 +0200620 head = &tt_global->orig_list;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200621 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800622 hlist_for_each_entry_rcu(orig_entry, head, list) {
Antonio Quartulli47c94652012-09-23 22:38:35 +0200623 batadv_send_roam_adv(bat_priv, tt_global->common.addr,
Antonio Quartullic018ad32013-06-04 12:11:39 +0200624 tt_global->common.vid,
Sven Eckelmanna5130882012-05-16 20:23:16 +0200625 orig_entry->orig_node);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +0200626 }
627 rcu_read_unlock();
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200628 if (roamed_back) {
629 batadv_tt_global_free(bat_priv, tt_global,
630 "Roaming canceled");
631 tt_global = NULL;
632 } else {
633 /* The global entry has to be marked as ROAMING and
634 * has to be kept for consistency purpose
635 */
636 tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
637 tt_global->roam_at = jiffies;
638 }
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200639 }
Antonio Quartulli068ee6e2012-09-23 22:38:37 +0200640
Antonio Quartulli3c4f7ab2013-10-13 02:50:19 +0200641 /* store the current remote flags before altering them. This helps
642 * understanding is flags are changing or not
643 */
644 remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK;
Marek Lindnera19d3d82013-05-27 15:33:25 +0800645
Antonio Quartulli3c4f7ab2013-10-13 02:50:19 +0200646 if (batadv_is_wifi_netdev(in_dev))
647 tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
648 else
649 tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI;
650
Antonio Quartulli9464d072013-11-16 12:03:48 +0100651 /* check the mark in the skb: if it's equal to the configured
652 * isolation_mark, it means the packet is coming from an isolated
653 * non-mesh client
654 */
655 match_mark = (mark & bat_priv->isolation_mark_mask);
656 if (bat_priv->isolation_mark_mask &&
657 match_mark == bat_priv->isolation_mark)
658 tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA;
659 else
660 tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA;
661
Antonio Quartulli3c4f7ab2013-10-13 02:50:19 +0200662 /* if any "dynamic" flag has been modified, resend an ADD event for this
663 * entry so that all the nodes can get the new flags
664 */
665 if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK))
666 batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
667
668 ret = true;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +0200669out:
Antonio Quartulli0c69aec2013-10-13 02:50:18 +0200670 if (in_dev)
671 dev_put(in_dev);
Antonio Quartulli47c94652012-09-23 22:38:35 +0200672 if (tt_local)
673 batadv_tt_local_entry_free_ref(tt_local);
674 if (tt_global)
675 batadv_tt_global_entry_free_ref(tt_global);
Marek Lindnera19d3d82013-05-27 15:33:25 +0800676 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000677}
678
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800679/**
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200680 * batadv_tt_prepare_tvlv_global_data - prepare the TVLV TT header to send
681 * within a TT Response directed to another node
682 * @orig_node: originator for which the TT data has to be prepared
683 * @tt_data: uninitialised pointer to the address of the TVLV buffer
684 * @tt_change: uninitialised pointer to the address of the area where the TT
685 * changed can be stored
686 * @tt_len: pointer to the length to reserve to the tt_change. if -1 this
687 * function reserves the amount of space needed to send the entire global TT
688 * table. In case of success the value is updated with the real amount of
689 * reserved bytes
690
691 * Allocate the needed amount of memory for the entire TT TVLV and write its
692 * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data
693 * objects, one per active VLAN served by the originator node.
694 *
695 * Return the size of the allocated buffer or 0 in case of failure.
696 */
697static uint16_t
698batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
699 struct batadv_tvlv_tt_data **tt_data,
700 struct batadv_tvlv_tt_change **tt_change,
701 int32_t *tt_len)
702{
703 uint16_t num_vlan = 0, num_entries = 0, change_offset, tvlv_len;
704 struct batadv_tvlv_tt_vlan_data *tt_vlan;
705 struct batadv_orig_node_vlan *vlan;
706 uint8_t *tt_change_ptr;
707
708 rcu_read_lock();
709 list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
710 num_vlan++;
711 num_entries += atomic_read(&vlan->tt.num_entries);
712 }
713
714 change_offset = sizeof(**tt_data);
715 change_offset += num_vlan * sizeof(*tt_vlan);
716
717 /* if tt_len is negative, allocate the space needed by the full table */
718 if (*tt_len < 0)
719 *tt_len = batadv_tt_len(num_entries);
720
721 tvlv_len = *tt_len;
722 tvlv_len += change_offset;
723
724 *tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
725 if (!*tt_data) {
726 *tt_len = 0;
727 goto out;
728 }
729
730 (*tt_data)->flags = BATADV_NO_FLAGS;
731 (*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn);
732 (*tt_data)->num_vlan = htons(num_vlan);
733
734 tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
735 list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
736 tt_vlan->vid = htons(vlan->vid);
737 tt_vlan->crc = htonl(vlan->tt.crc);
738
739 tt_vlan++;
740 }
741
742 tt_change_ptr = (uint8_t *)*tt_data + change_offset;
743 *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;
744
745out:
746 rcu_read_unlock();
747 return tvlv_len;
748}
749
750/**
751 * batadv_tt_prepare_tvlv_local_data - allocate and prepare the TT TVLV for this
752 * node
753 * @bat_priv: the bat priv with all the soft interface information
754 * @tt_data: uninitialised pointer to the address of the TVLV buffer
755 * @tt_change: uninitialised pointer to the address of the area where the TT
756 * changes can be stored
757 * @tt_len: pointer to the length to reserve to the tt_change. if -1 this
758 * function reserves the amount of space needed to send the entire local TT
759 * table. In case of success the value is updated with the real amount of
760 * reserved bytes
761 *
762 * Allocate the needed amount of memory for the entire TT TVLV and write its
763 * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data
764 * objects, one per active VLAN.
765 *
766 * Return the size of the allocated buffer or 0 in case of failure.
767 */
768static uint16_t
769batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
770 struct batadv_tvlv_tt_data **tt_data,
771 struct batadv_tvlv_tt_change **tt_change,
772 int32_t *tt_len)
773{
774 struct batadv_tvlv_tt_vlan_data *tt_vlan;
775 struct batadv_softif_vlan *vlan;
776 uint16_t num_vlan = 0, num_entries = 0, tvlv_len;
777 uint8_t *tt_change_ptr;
778 int change_offset;
779
780 rcu_read_lock();
781 hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
782 num_vlan++;
783 num_entries += atomic_read(&vlan->tt.num_entries);
784 }
785
786 change_offset = sizeof(**tt_data);
787 change_offset += num_vlan * sizeof(*tt_vlan);
788
789 /* if tt_len is negative, allocate the space needed by the full table */
790 if (*tt_len < 0)
791 *tt_len = batadv_tt_len(num_entries);
792
793 tvlv_len = *tt_len;
794 tvlv_len += change_offset;
795
796 *tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
797 if (!*tt_data) {
798 tvlv_len = 0;
799 goto out;
800 }
801
802 (*tt_data)->flags = BATADV_NO_FLAGS;
803 (*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn);
804 (*tt_data)->num_vlan = htons(num_vlan);
805
806 tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
807 hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
808 tt_vlan->vid = htons(vlan->vid);
809 tt_vlan->crc = htonl(vlan->tt.crc);
810
811 tt_vlan++;
812 }
813
814 tt_change_ptr = (uint8_t *)*tt_data + change_offset;
815 *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;
816
817out:
818 rcu_read_unlock();
819 return tvlv_len;
820}
821
822/**
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800823 * batadv_tt_tvlv_container_update - update the translation table tvlv container
824 * after local tt changes have been committed
825 * @bat_priv: the bat priv with all the soft interface information
826 */
827static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000828{
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800829 struct batadv_tt_change_node *entry, *safe;
830 struct batadv_tvlv_tt_data *tt_data;
831 struct batadv_tvlv_tt_change *tt_change;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200832 int tt_diff_len, tt_change_len = 0;
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800833 int tt_diff_entries_num = 0, tt_diff_entries_count = 0;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200834 uint16_t tvlv_len;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000835
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200836 tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes);
837 tt_diff_len = batadv_tt_len(tt_diff_entries_num);
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +0800838
839 /* if we have too many changes for one packet don't send any
840 * and wait for the tt table request which will be fragmented
841 */
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800842 if (tt_diff_len > bat_priv->soft_iface->mtu)
843 tt_diff_len = 0;
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +0800844
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200845 tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data,
846 &tt_change, &tt_diff_len);
847 if (!tvlv_len)
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800848 return;
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +0800849
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800850 tt_data->flags = BATADV_TT_OGM_DIFF;
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +0800851
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800852 if (tt_diff_len == 0)
853 goto container_register;
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +0800854
Sven Eckelmann807736f2012-07-15 22:26:51 +0200855 spin_lock_bh(&bat_priv->tt.changes_list_lock);
856 atomic_set(&bat_priv->tt.local_changes, 0);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000857
Sven Eckelmann807736f2012-07-15 22:26:51 +0200858 list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
Sven Eckelmann7c64fd92012-02-28 10:55:36 +0100859 list) {
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800860 if (tt_diff_entries_count < tt_diff_entries_num) {
861 memcpy(tt_change + tt_diff_entries_count,
862 &entry->change,
863 sizeof(struct batadv_tvlv_tt_change));
864 tt_diff_entries_count++;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000865 }
Antonio Quartullia73105b2011-04-27 14:27:44 +0200866 list_del(&entry->list);
867 kfree(entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000868 }
Sven Eckelmann807736f2012-07-15 22:26:51 +0200869 spin_unlock_bh(&bat_priv->tt.changes_list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000870
Antonio Quartullia73105b2011-04-27 14:27:44 +0200871 /* Keep the buffer for possible tt_request */
Sven Eckelmann807736f2012-07-15 22:26:51 +0200872 spin_lock_bh(&bat_priv->tt.last_changeset_lock);
873 kfree(bat_priv->tt.last_changeset);
874 bat_priv->tt.last_changeset_len = 0;
875 bat_priv->tt.last_changeset = NULL;
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800876 tt_change_len = batadv_tt_len(tt_diff_entries_count);
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +0800877 /* check whether this new OGM has no changes due to size problems */
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800878 if (tt_diff_entries_count > 0) {
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +0800879 /* if kmalloc() fails we will reply with the full table
Antonio Quartullia73105b2011-04-27 14:27:44 +0200880 * instead of providing the diff
881 */
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800882 bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC);
Sven Eckelmann807736f2012-07-15 22:26:51 +0200883 if (bat_priv->tt.last_changeset) {
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800884 memcpy(bat_priv->tt.last_changeset,
885 tt_change, tt_change_len);
886 bat_priv->tt.last_changeset_len = tt_diff_len;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200887 }
888 }
Sven Eckelmann807736f2012-07-15 22:26:51 +0200889 spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000890
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800891container_register:
892 batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200893 tvlv_len);
Marek Lindnere1bf0c12013-04-23 21:40:01 +0800894 kfree(tt_data);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000895}
896
Sven Eckelmann08c36d32012-05-12 02:09:39 +0200897int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000898{
899 struct net_device *net_dev = (struct net_device *)seq->private;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200900 struct batadv_priv *bat_priv = netdev_priv(net_dev);
Sven Eckelmann807736f2012-07-15 22:26:51 +0200901 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200902 struct batadv_tt_common_entry *tt_common_entry;
Antonio Quartulli85766a82012-11-08 22:16:16 +0100903 struct batadv_tt_local_entry *tt_local;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200904 struct batadv_hard_iface *primary_if;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200905 struct batadv_softif_vlan *vlan;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000906 struct hlist_head *head;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200907 unsigned short vid;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200908 uint32_t i;
Antonio Quartulli85766a82012-11-08 22:16:16 +0100909 int last_seen_secs;
910 int last_seen_msecs;
911 unsigned long last_seen_jiffies;
912 bool no_purge;
913 uint16_t np_flag = BATADV_TT_CLIENT_NOPURGE;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000914
Marek Lindner30da63a2012-08-03 17:15:46 +0200915 primary_if = batadv_seq_print_text_primary_if_get(seq);
916 if (!primary_if)
Marek Lindner32ae9b22011-04-20 15:40:58 +0200917 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000918
Sven Eckelmann86ceb362012-03-07 09:07:45 +0100919 seq_printf(seq,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200920 "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n",
921 net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn));
Antonio Quartullidd24ddb2013-11-16 12:03:49 +0100922 seq_printf(seq, " %-13s %s %-8s %-9s (%-10s)\n", "Client", "VID",
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200923 "Flags", "Last seen", "CRC");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000924
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000925 for (i = 0; i < hash->size; i++) {
926 head = &hash->table[i];
927
Marek Lindner7aadf882011-02-18 12:28:09 +0000928 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800929 hlist_for_each_entry_rcu(tt_common_entry,
Marek Lindner7aadf882011-02-18 12:28:09 +0000930 head, hash_entry) {
Antonio Quartulli85766a82012-11-08 22:16:16 +0100931 tt_local = container_of(tt_common_entry,
932 struct batadv_tt_local_entry,
933 common);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200934 vid = tt_common_entry->vid;
Antonio Quartulli85766a82012-11-08 22:16:16 +0100935 last_seen_jiffies = jiffies - tt_local->last_seen;
936 last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
937 last_seen_secs = last_seen_msecs / 1000;
938 last_seen_msecs = last_seen_msecs % 1000;
939
940 no_purge = tt_common_entry->flags & np_flag;
941
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200942 vlan = batadv_softif_vlan_get(bat_priv, vid);
943 if (!vlan) {
944 seq_printf(seq, "Cannot retrieve VLAN %d\n",
945 BATADV_PRINT_VID(vid));
946 continue;
947 }
948
949 seq_printf(seq,
Antonio Quartullidd24ddb2013-11-16 12:03:49 +0100950 " * %pM %4i [%c%c%c%c%c%c] %3u.%03u (%#.8x)\n",
Sven Eckelmann7c64fd92012-02-28 10:55:36 +0100951 tt_common_entry->addr,
Antonio Quartulli16052782013-06-04 12:11:41 +0200952 BATADV_PRINT_VID(tt_common_entry->vid),
Sven Eckelmann7c64fd92012-02-28 10:55:36 +0100953 (tt_common_entry->flags &
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200954 BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
Antonio Quartulli85766a82012-11-08 22:16:16 +0100955 no_purge ? 'P' : '.',
Sven Eckelmann7c64fd92012-02-28 10:55:36 +0100956 (tt_common_entry->flags &
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200957 BATADV_TT_CLIENT_NEW ? 'N' : '.'),
Sven Eckelmann7c64fd92012-02-28 10:55:36 +0100958 (tt_common_entry->flags &
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200959 BATADV_TT_CLIENT_PENDING ? 'X' : '.'),
Sven Eckelmann7c64fd92012-02-28 10:55:36 +0100960 (tt_common_entry->flags &
Antonio Quartulli85766a82012-11-08 22:16:16 +0100961 BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
Antonio Quartullidd24ddb2013-11-16 12:03:49 +0100962 (tt_common_entry->flags &
963 BATADV_TT_CLIENT_ISOLA ? 'I' : '.'),
Antonio Quartullia7966d92013-01-24 11:41:39 +0100964 no_purge ? 0 : last_seen_secs,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200965 no_purge ? 0 : last_seen_msecs,
966 vlan->tt.crc);
967
968 batadv_softif_vlan_free_ref(vlan);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000969 }
Marek Lindner7aadf882011-02-18 12:28:09 +0000970 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000971 }
Marek Lindner32ae9b22011-04-20 15:40:58 +0200972out:
973 if (primary_if)
Sven Eckelmanne5d89252012-05-12 13:48:54 +0200974 batadv_hardif_free_ref(primary_if);
Marek Lindner30da63a2012-08-03 17:15:46 +0200975 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000976}
977
Sven Eckelmann56303d32012-06-05 22:31:31 +0200978static void
979batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
980 struct batadv_tt_local_entry *tt_local_entry,
981 uint16_t flags, const char *message)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000982{
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +0200983 batadv_tt_local_event(bat_priv, tt_local_entry, flags);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000984
Antonio Quartulli015758d2011-07-09 17:52:13 +0200985 /* The local client has to be marked as "pending to be removed" but has
986 * to be kept in the table in order to send it in a full table
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +0200987 * response issued before the net ttvn increment (consistency check)
988 */
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200989 tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
Antonio Quartullic566dbb2012-01-06 21:31:34 +0100990
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200991 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +0200992 "Local tt entry (%pM, vid: %d) pending to be removed: %s\n",
993 tt_local_entry->common.addr,
994 BATADV_PRINT_VID(tt_local_entry->common.vid), message);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000995}
996
Antonio Quartulli7f91d062012-08-27 11:44:43 +0200997/**
998 * batadv_tt_local_remove - logically remove an entry from the local table
999 * @bat_priv: the bat priv with all the soft interface information
1000 * @addr: the MAC address of the client to remove
Antonio Quartullic018ad32013-06-04 12:11:39 +02001001 * @vid: VLAN identifier
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001002 * @message: message to append to the log on deletion
1003 * @roaming: true if the deletion is due to a roaming event
1004 *
1005 * Returns the flags assigned to the local entry before being deleted
1006 */
1007uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
Antonio Quartullic018ad32013-06-04 12:11:39 +02001008 const uint8_t *addr, unsigned short vid,
1009 const char *message, bool roaming)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001010{
Sven Eckelmann170173b2012-10-07 12:02:22 +02001011 struct batadv_tt_local_entry *tt_local_entry;
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001012 uint16_t flags, curr_flags = BATADV_NO_FLAGS;
Antonio Quartulli35df3b22014-05-08 17:13:15 +02001013 struct batadv_softif_vlan *vlan;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001014
Antonio Quartullic018ad32013-06-04 12:11:39 +02001015 tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001016 if (!tt_local_entry)
1017 goto out;
1018
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001019 curr_flags = tt_local_entry->common.flags;
1020
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001021 flags = BATADV_TT_CLIENT_DEL;
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001022 /* if this global entry addition is due to a roaming, the node has to
1023 * mark the local entry as "roamed" in order to correctly reroute
1024 * packets later
1025 */
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02001026 if (roaming) {
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001027 flags |= BATADV_TT_CLIENT_ROAM;
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02001028 /* mark the local client as ROAMed */
1029 tt_local_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
1030 }
Sven Eckelmann42d0b042012-06-03 22:19:17 +02001031
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001032 if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) {
1033 batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags,
1034 message);
1035 goto out;
1036 }
1037 /* if this client has been added right now, it is possible to
1038 * immediately purge it
1039 */
Antonio Quartulli3abe4ad2013-04-03 11:15:33 +02001040 batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001041 hlist_del_rcu(&tt_local_entry->common.hash_entry);
1042 batadv_tt_local_entry_free_ref(tt_local_entry);
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001043
Antonio Quartulli35df3b22014-05-08 17:13:15 +02001044 /* decrease the reference held for this vlan */
1045 vlan = batadv_softif_vlan_get(bat_priv, vid);
1046 batadv_softif_vlan_free_ref(vlan);
1047 batadv_softif_vlan_free_ref(vlan);
1048
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001049out:
1050 if (tt_local_entry)
Sven Eckelmanna5130882012-05-16 20:23:16 +02001051 batadv_tt_local_entry_free_ref(tt_local_entry);
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001052
1053 return curr_flags;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001054}
1055
Marek Lindnera19d3d82013-05-27 15:33:25 +08001056/**
1057 * batadv_tt_local_purge_list - purge inactive tt local entries
1058 * @bat_priv: the bat priv with all the soft interface information
1059 * @head: pointer to the list containing the local tt entries
1060 * @timeout: parameter deciding whether a given tt local entry is considered
1061 * inactive or not
1062 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02001063static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
Marek Lindnera19d3d82013-05-27 15:33:25 +08001064 struct hlist_head *head,
1065 int timeout)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001066{
Sven Eckelmann56303d32012-06-05 22:31:31 +02001067 struct batadv_tt_local_entry *tt_local_entry;
1068 struct batadv_tt_common_entry *tt_common_entry;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001069 struct hlist_node *node_tmp;
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001070
Sasha Levinb67bfe02013-02-27 17:06:00 -08001071 hlist_for_each_entry_safe(tt_common_entry, node_tmp, head,
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001072 hash_entry) {
1073 tt_local_entry = container_of(tt_common_entry,
Sven Eckelmann56303d32012-06-05 22:31:31 +02001074 struct batadv_tt_local_entry,
1075 common);
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001076 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE)
1077 continue;
1078
1079 /* entry already marked for deletion */
1080 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
1081 continue;
1082
Marek Lindnera19d3d82013-05-27 15:33:25 +08001083 if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout))
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001084 continue;
1085
1086 batadv_tt_local_set_pending(bat_priv, tt_local_entry,
1087 BATADV_TT_CLIENT_DEL, "timed out");
1088 }
1089}
1090
Marek Lindnera19d3d82013-05-27 15:33:25 +08001091/**
1092 * batadv_tt_local_purge - purge inactive tt local entries
1093 * @bat_priv: the bat priv with all the soft interface information
1094 * @timeout: parameter deciding whether a given tt local entry is considered
1095 * inactive or not
1096 */
1097static void batadv_tt_local_purge(struct batadv_priv *bat_priv,
1098 int timeout)
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001099{
Sven Eckelmann807736f2012-07-15 22:26:51 +02001100 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001101 struct hlist_head *head;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001102 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartullic90681b2011-10-05 17:05:25 +02001103 uint32_t i;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001104
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001105 for (i = 0; i < hash->size; i++) {
1106 head = &hash->table[i];
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001107 list_lock = &hash->list_locks[i];
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001108
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001109 spin_lock_bh(list_lock);
Marek Lindnera19d3d82013-05-27 15:33:25 +08001110 batadv_tt_local_purge_list(bat_priv, head, timeout);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001111 spin_unlock_bh(list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001112 }
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001113}
1114
Sven Eckelmann56303d32012-06-05 22:31:31 +02001115static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001116{
Sven Eckelmann5bf74e92012-06-05 22:31:28 +02001117 struct batadv_hashtable *hash;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001118 spinlock_t *list_lock; /* protects write access to the hash lists */
Sven Eckelmann56303d32012-06-05 22:31:31 +02001119 struct batadv_tt_common_entry *tt_common_entry;
1120 struct batadv_tt_local_entry *tt_local;
Antonio Quartulli35df3b22014-05-08 17:13:15 +02001121 struct batadv_softif_vlan *vlan;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001122 struct hlist_node *node_tmp;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001123 struct hlist_head *head;
Antonio Quartullic90681b2011-10-05 17:05:25 +02001124 uint32_t i;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001125
Sven Eckelmann807736f2012-07-15 22:26:51 +02001126 if (!bat_priv->tt.local_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001127 return;
1128
Sven Eckelmann807736f2012-07-15 22:26:51 +02001129 hash = bat_priv->tt.local_hash;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001130
1131 for (i = 0; i < hash->size; i++) {
1132 head = &hash->table[i];
1133 list_lock = &hash->list_locks[i];
1134
1135 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -08001136 hlist_for_each_entry_safe(tt_common_entry, node_tmp,
Antonio Quartullia73105b2011-04-27 14:27:44 +02001137 head, hash_entry) {
Sasha Levinb67bfe02013-02-27 17:06:00 -08001138 hlist_del_rcu(&tt_common_entry->hash_entry);
Sven Eckelmann56303d32012-06-05 22:31:31 +02001139 tt_local = container_of(tt_common_entry,
1140 struct batadv_tt_local_entry,
1141 common);
Antonio Quartulli35df3b22014-05-08 17:13:15 +02001142
1143 /* decrease the reference held for this vlan */
1144 vlan = batadv_softif_vlan_get(bat_priv,
1145 tt_common_entry->vid);
1146 batadv_softif_vlan_free_ref(vlan);
1147 batadv_softif_vlan_free_ref(vlan);
1148
Sven Eckelmann56303d32012-06-05 22:31:31 +02001149 batadv_tt_local_entry_free_ref(tt_local);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001150 }
1151 spin_unlock_bh(list_lock);
1152 }
1153
Sven Eckelmann1a8eaf02012-05-12 02:09:32 +02001154 batadv_hash_destroy(hash);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001155
Sven Eckelmann807736f2012-07-15 22:26:51 +02001156 bat_priv->tt.local_hash = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001157}
1158
Sven Eckelmann56303d32012-06-05 22:31:31 +02001159static int batadv_tt_global_init(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001160{
Sven Eckelmann807736f2012-07-15 22:26:51 +02001161 if (bat_priv->tt.global_hash)
Sven Eckelmann5346c352012-05-05 13:27:28 +02001162 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001163
Sven Eckelmann807736f2012-07-15 22:26:51 +02001164 bat_priv->tt.global_hash = batadv_hash_new(1024);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001165
Sven Eckelmann807736f2012-07-15 22:26:51 +02001166 if (!bat_priv->tt.global_hash)
Sven Eckelmann5346c352012-05-05 13:27:28 +02001167 return -ENOMEM;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001168
Antonio Quartullidec05072012-11-10 11:00:32 +01001169 batadv_hash_set_lock_class(bat_priv->tt.global_hash,
1170 &batadv_tt_global_hash_lock_class_key);
1171
Sven Eckelmann5346c352012-05-05 13:27:28 +02001172 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001173}
1174
Sven Eckelmann56303d32012-06-05 22:31:31 +02001175static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv)
Antonio Quartullia73105b2011-04-27 14:27:44 +02001176{
Sven Eckelmann56303d32012-06-05 22:31:31 +02001177 struct batadv_tt_change_node *entry, *safe;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001178
Sven Eckelmann807736f2012-07-15 22:26:51 +02001179 spin_lock_bh(&bat_priv->tt.changes_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001180
Sven Eckelmann807736f2012-07-15 22:26:51 +02001181 list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
Antonio Quartullia73105b2011-04-27 14:27:44 +02001182 list) {
1183 list_del(&entry->list);
1184 kfree(entry);
1185 }
1186
Sven Eckelmann807736f2012-07-15 22:26:51 +02001187 atomic_set(&bat_priv->tt.local_changes, 0);
1188 spin_unlock_bh(&bat_priv->tt.changes_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001189}
1190
Antonio Quartullid657e622012-07-01 14:09:12 +02001191/* retrieves the orig_tt_list_entry belonging to orig_node from the
1192 * batadv_tt_global_entry list
1193 *
1194 * returns it with an increased refcounter, NULL if not found
1195 */
1196static struct batadv_tt_orig_list_entry *
1197batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
1198 const struct batadv_orig_node *orig_node)
1199{
1200 struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL;
1201 const struct hlist_head *head;
Antonio Quartullid657e622012-07-01 14:09:12 +02001202
1203 rcu_read_lock();
1204 head = &entry->orig_list;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001205 hlist_for_each_entry_rcu(tmp_orig_entry, head, list) {
Antonio Quartullid657e622012-07-01 14:09:12 +02001206 if (tmp_orig_entry->orig_node != orig_node)
1207 continue;
1208 if (!atomic_inc_not_zero(&tmp_orig_entry->refcount))
1209 continue;
1210
1211 orig_entry = tmp_orig_entry;
1212 break;
1213 }
1214 rcu_read_unlock();
1215
1216 return orig_entry;
1217}
1218
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001219/* find out if an orig_node is already in the list of a tt_global_entry.
Antonio Quartullid657e622012-07-01 14:09:12 +02001220 * returns true if found, false otherwise
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001221 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02001222static bool
1223batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
1224 const struct batadv_orig_node *orig_node)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001225{
Antonio Quartullid657e622012-07-01 14:09:12 +02001226 struct batadv_tt_orig_list_entry *orig_entry;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001227 bool found = false;
1228
Antonio Quartullid657e622012-07-01 14:09:12 +02001229 orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node);
1230 if (orig_entry) {
1231 found = true;
1232 batadv_tt_orig_list_entry_free_ref(orig_entry);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001233 }
Antonio Quartullid657e622012-07-01 14:09:12 +02001234
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001235 return found;
1236}
1237
Sven Eckelmanna5130882012-05-16 20:23:16 +02001238static void
Antonio Quartullid657e622012-07-01 14:09:12 +02001239batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
Sven Eckelmann56303d32012-06-05 22:31:31 +02001240 struct batadv_orig_node *orig_node, int ttvn)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001241{
Sven Eckelmann56303d32012-06-05 22:31:31 +02001242 struct batadv_tt_orig_list_entry *orig_entry;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001243
Antonio Quartullid657e622012-07-01 14:09:12 +02001244 orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node);
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001245 if (orig_entry) {
1246 /* refresh the ttvn: the current value could be a bogus one that
1247 * was added during a "temporary client detection"
1248 */
1249 orig_entry->ttvn = ttvn;
Antonio Quartullid657e622012-07-01 14:09:12 +02001250 goto out;
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001251 }
Antonio Quartullid657e622012-07-01 14:09:12 +02001252
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001253 orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC);
1254 if (!orig_entry)
Antonio Quartullid657e622012-07-01 14:09:12 +02001255 goto out;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001256
1257 INIT_HLIST_NODE(&orig_entry->list);
1258 atomic_inc(&orig_node->refcount);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001259 batadv_tt_global_size_inc(orig_node, tt_global->common.vid);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001260 orig_entry->orig_node = orig_node;
1261 orig_entry->ttvn = ttvn;
Antonio Quartullid657e622012-07-01 14:09:12 +02001262 atomic_set(&orig_entry->refcount, 2);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001263
Antonio Quartullid657e622012-07-01 14:09:12 +02001264 spin_lock_bh(&tt_global->list_lock);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001265 hlist_add_head_rcu(&orig_entry->list,
Antonio Quartullid657e622012-07-01 14:09:12 +02001266 &tt_global->orig_list);
1267 spin_unlock_bh(&tt_global->list_lock);
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01001268 atomic_inc(&tt_global->orig_list_count);
1269
Antonio Quartullid657e622012-07-01 14:09:12 +02001270out:
1271 if (orig_entry)
1272 batadv_tt_orig_list_entry_free_ref(orig_entry);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001273}
1274
Antonio Quartullid4ff40f2013-04-18 15:13:01 +02001275/**
1276 * batadv_tt_global_add - add a new TT global entry or update an existing one
1277 * @bat_priv: the bat priv with all the soft interface information
1278 * @orig_node: the originator announcing the client
1279 * @tt_addr: the mac address of the non-mesh client
Antonio Quartullic018ad32013-06-04 12:11:39 +02001280 * @vid: VLAN identifier
Antonio Quartullid4ff40f2013-04-18 15:13:01 +02001281 * @flags: TT flags that have to be set for this non-mesh client
1282 * @ttvn: the tt version number ever announcing this non-mesh client
1283 *
1284 * Add a new TT global entry for the given originator. If the entry already
1285 * exists add a new reference to the given originator (a global entry can have
1286 * references to multiple originators) and adjust the flags attribute to reflect
1287 * the function argument.
1288 * If a TT local entry exists for this non-mesh client remove it.
1289 *
1290 * The caller must hold orig_node refcount.
Antonio Quartulli1e5d49f2013-05-05 19:32:38 +02001291 *
1292 * Return true if the new entry has been added, false otherwise
Antonio Quartullid4ff40f2013-04-18 15:13:01 +02001293 */
Antonio Quartulli1e5d49f2013-05-05 19:32:38 +02001294static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
1295 struct batadv_orig_node *orig_node,
Antonio Quartullic018ad32013-06-04 12:11:39 +02001296 const unsigned char *tt_addr,
1297 unsigned short vid, uint16_t flags,
Antonio Quartulli1e5d49f2013-05-05 19:32:38 +02001298 uint8_t ttvn)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001299{
Sven Eckelmann170173b2012-10-07 12:02:22 +02001300 struct batadv_tt_global_entry *tt_global_entry;
1301 struct batadv_tt_local_entry *tt_local_entry;
Antonio Quartulli1e5d49f2013-05-05 19:32:38 +02001302 bool ret = false;
Simon Wunderlich80b3f582011-11-02 20:26:45 +01001303 int hash_added;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001304 struct batadv_tt_common_entry *common;
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001305 uint16_t local_flags;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001306
Antonio Quartullicfd4f752013-08-07 18:28:56 +02001307 /* ignore global entries from backbone nodes */
1308 if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid))
1309 return true;
1310
Antonio Quartullic018ad32013-06-04 12:11:39 +02001311 tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid);
1312 tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001313
1314 /* if the node already has a local client for this entry, it has to wait
1315 * for a roaming advertisement instead of manually messing up the global
1316 * table
1317 */
1318 if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry &&
1319 !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW))
1320 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001321
Antonio Quartullia73105b2011-04-27 14:27:44 +02001322 if (!tt_global_entry) {
Antonio Quartullid4f44692012-05-25 00:00:54 +02001323 tt_global_entry = kzalloc(sizeof(*tt_global_entry), GFP_ATOMIC);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001324 if (!tt_global_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001325 goto out;
1326
Sven Eckelmannc0a55922012-05-12 13:48:55 +02001327 common = &tt_global_entry->common;
Antonio Quartulli8fdd0152014-01-22 00:42:11 +01001328 ether_addr_copy(common->addr, tt_addr);
Antonio Quartullic018ad32013-06-04 12:11:39 +02001329 common->vid = vid;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001330
Antonio Quartullid4f44692012-05-25 00:00:54 +02001331 common->flags = flags;
Antonio Quartullicc47f662011-04-27 14:27:57 +02001332 tt_global_entry->roam_at = 0;
Antonio Quartullifdf79322012-08-24 17:54:07 +02001333 /* node must store current time in case of roaming. This is
1334 * needed to purge this entry out on timeout (if nobody claims
1335 * it)
1336 */
1337 if (flags & BATADV_TT_CLIENT_ROAM)
1338 tt_global_entry->roam_at = jiffies;
Sven Eckelmannc0a55922012-05-12 13:48:55 +02001339 atomic_set(&common->refcount, 2);
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001340 common->added_at = jiffies;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001341
1342 INIT_HLIST_HEAD(&tt_global_entry->orig_list);
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01001343 atomic_set(&tt_global_entry->orig_list_count, 0);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001344 spin_lock_init(&tt_global_entry->list_lock);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001345
Sven Eckelmann807736f2012-07-15 22:26:51 +02001346 hash_added = batadv_hash_add(bat_priv->tt.global_hash,
Sven Eckelmanna5130882012-05-16 20:23:16 +02001347 batadv_compare_tt,
Antonio Quartullic018ad32013-06-04 12:11:39 +02001348 batadv_choose_tt, common,
Sven Eckelmanna5130882012-05-16 20:23:16 +02001349 &common->hash_entry);
Simon Wunderlich80b3f582011-11-02 20:26:45 +01001350
1351 if (unlikely(hash_added != 0)) {
1352 /* remove the reference for the hash */
Sven Eckelmanna5130882012-05-16 20:23:16 +02001353 batadv_tt_global_entry_free_ref(tt_global_entry);
Simon Wunderlich80b3f582011-11-02 20:26:45 +01001354 goto out_remove;
1355 }
Antonio Quartullia73105b2011-04-27 14:27:44 +02001356 } else {
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001357 common = &tt_global_entry->common;
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001358 /* If there is already a global entry, we can use this one for
1359 * our processing.
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001360 * But if we are trying to add a temporary client then here are
1361 * two options at this point:
1362 * 1) the global client is not a temporary client: the global
1363 * client has to be left as it is, temporary information
1364 * should never override any already known client state
1365 * 2) the global client is a temporary client: purge the
1366 * originator list and add the new one orig_entry
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001367 */
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001368 if (flags & BATADV_TT_CLIENT_TEMP) {
1369 if (!(common->flags & BATADV_TT_CLIENT_TEMP))
1370 goto out;
1371 if (batadv_tt_global_entry_has_orig(tt_global_entry,
1372 orig_node))
1373 goto out_remove;
1374 batadv_tt_global_del_orig_list(tt_global_entry);
1375 goto add_orig_entry;
1376 }
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001377
1378 /* if the client was temporary added before receiving the first
1379 * OGM announcing it, we have to clear the TEMP flag
1380 */
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001381 common->flags &= ~BATADV_TT_CLIENT_TEMP;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001382
Antonio Quartullie9c001362012-11-07 15:05:33 +01001383 /* the change can carry possible "attribute" flags like the
1384 * TT_CLIENT_WIFI, therefore they have to be copied in the
1385 * client entry
1386 */
1387 tt_global_entry->common.flags |= flags;
1388
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001389 /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
1390 * one originator left in the list and we previously received a
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001391 * delete + roaming change for this originator.
1392 *
1393 * We should first delete the old originator before adding the
1394 * new one.
1395 */
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001396 if (common->flags & BATADV_TT_CLIENT_ROAM) {
Sven Eckelmanna5130882012-05-16 20:23:16 +02001397 batadv_tt_global_del_orig_list(tt_global_entry);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001398 common->flags &= ~BATADV_TT_CLIENT_ROAM;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001399 tt_global_entry->roam_at = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001400 }
1401 }
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001402add_orig_entry:
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001403 /* add the new orig_entry (if needed) or update it */
Antonio Quartullid657e622012-07-01 14:09:12 +02001404 batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001405
Sven Eckelmann39c75a52012-06-03 22:19:22 +02001406 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02001407 "Creating new global tt entry: %pM (vid: %d, via %pM)\n",
1408 common->addr, BATADV_PRINT_VID(common->vid),
1409 orig_node->orig);
Antonio Quartulli1e5d49f2013-05-05 19:32:38 +02001410 ret = true;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001411
Simon Wunderlich80b3f582011-11-02 20:26:45 +01001412out_remove:
Linus Lüssingc5caf4e2014-02-15 17:47:49 +01001413 /* Do not remove multicast addresses from the local hash on
1414 * global additions
1415 */
1416 if (is_multicast_ether_addr(tt_addr))
1417 goto out;
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001418
Antonio Quartullia73105b2011-04-27 14:27:44 +02001419 /* remove address from local hash if present */
Antonio Quartullic018ad32013-06-04 12:11:39 +02001420 local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid,
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001421 "global tt received",
Antonio Quartullic1d07432013-01-15 22:17:19 +10001422 flags & BATADV_TT_CLIENT_ROAM);
Antonio Quartulli7f91d062012-08-27 11:44:43 +02001423 tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI;
1424
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001425 if (!(flags & BATADV_TT_CLIENT_ROAM))
1426 /* this is a normal global add. Therefore the client is not in a
1427 * roaming state anymore.
1428 */
1429 tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
1430
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001431out:
1432 if (tt_global_entry)
Sven Eckelmanna5130882012-05-16 20:23:16 +02001433 batadv_tt_global_entry_free_ref(tt_global_entry);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001434 if (tt_local_entry)
1435 batadv_tt_local_entry_free_ref(tt_local_entry);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001436 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001437}
1438
Simon Wunderlich1b371d12014-01-15 21:17:54 +01001439/**
1440 * batadv_transtable_best_orig - Get best originator list entry from tt entry
Antonio Quartulli46274562013-09-03 11:10:24 +02001441 * @bat_priv: the bat priv with all the soft interface information
Sven Eckelmann981d8902012-10-07 13:34:15 +02001442 * @tt_global_entry: global translation table entry to be analyzed
1443 *
1444 * This functon assumes the caller holds rcu_read_lock().
1445 * Returns best originator list entry or NULL on errors.
1446 */
1447static struct batadv_tt_orig_list_entry *
Antonio Quartulli46274562013-09-03 11:10:24 +02001448batadv_transtable_best_orig(struct batadv_priv *bat_priv,
1449 struct batadv_tt_global_entry *tt_global_entry)
Sven Eckelmann981d8902012-10-07 13:34:15 +02001450{
Antonio Quartulli46274562013-09-03 11:10:24 +02001451 struct batadv_neigh_node *router, *best_router = NULL;
1452 struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
Sven Eckelmann981d8902012-10-07 13:34:15 +02001453 struct hlist_head *head;
Sven Eckelmann981d8902012-10-07 13:34:15 +02001454 struct batadv_tt_orig_list_entry *orig_entry, *best_entry = NULL;
Sven Eckelmann981d8902012-10-07 13:34:15 +02001455
1456 head = &tt_global_entry->orig_list;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001457 hlist_for_each_entry_rcu(orig_entry, head, list) {
Simon Wunderlich7351a4822013-11-13 19:14:47 +01001458 router = batadv_orig_router_get(orig_entry->orig_node,
1459 BATADV_IF_DEFAULT);
Sven Eckelmann981d8902012-10-07 13:34:15 +02001460 if (!router)
1461 continue;
1462
Antonio Quartulli46274562013-09-03 11:10:24 +02001463 if (best_router &&
Simon Wunderlich89652332013-11-13 19:14:46 +01001464 bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT,
1465 best_router, BATADV_IF_DEFAULT) <= 0) {
Antonio Quartulli46274562013-09-03 11:10:24 +02001466 batadv_neigh_node_free_ref(router);
1467 continue;
Sven Eckelmann981d8902012-10-07 13:34:15 +02001468 }
1469
Antonio Quartulli46274562013-09-03 11:10:24 +02001470 /* release the refcount for the "old" best */
1471 if (best_router)
1472 batadv_neigh_node_free_ref(best_router);
1473
1474 best_entry = orig_entry;
1475 best_router = router;
Sven Eckelmann981d8902012-10-07 13:34:15 +02001476 }
1477
Antonio Quartulli46274562013-09-03 11:10:24 +02001478 if (best_router)
1479 batadv_neigh_node_free_ref(best_router);
1480
Sven Eckelmann981d8902012-10-07 13:34:15 +02001481 return best_entry;
1482}
1483
Simon Wunderlich1b371d12014-01-15 21:17:54 +01001484/**
1485 * batadv_tt_global_print_entry - print all orig nodes who announce the address
1486 * for this global entry
Antonio Quartulli46274562013-09-03 11:10:24 +02001487 * @bat_priv: the bat priv with all the soft interface information
Sven Eckelmann981d8902012-10-07 13:34:15 +02001488 * @tt_global_entry: global translation table entry to be printed
1489 * @seq: debugfs table seq_file struct
1490 *
1491 * This functon assumes the caller holds rcu_read_lock().
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001492 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02001493static void
Antonio Quartulli46274562013-09-03 11:10:24 +02001494batadv_tt_global_print_entry(struct batadv_priv *bat_priv,
1495 struct batadv_tt_global_entry *tt_global_entry,
Sven Eckelmanna5130882012-05-16 20:23:16 +02001496 struct seq_file *seq)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001497{
Sven Eckelmann981d8902012-10-07 13:34:15 +02001498 struct batadv_tt_orig_list_entry *orig_entry, *best_entry;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001499 struct batadv_tt_common_entry *tt_common_entry;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001500 struct batadv_orig_node_vlan *vlan;
1501 struct hlist_head *head;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001502 uint8_t last_ttvn;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001503 uint16_t flags;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001504
1505 tt_common_entry = &tt_global_entry->common;
Sven Eckelmann981d8902012-10-07 13:34:15 +02001506 flags = tt_common_entry->flags;
1507
Antonio Quartulli46274562013-09-03 11:10:24 +02001508 best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry);
Sven Eckelmann981d8902012-10-07 13:34:15 +02001509 if (best_entry) {
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001510 vlan = batadv_orig_node_vlan_get(best_entry->orig_node,
1511 tt_common_entry->vid);
1512 if (!vlan) {
1513 seq_printf(seq,
1514 " * Cannot retrieve VLAN %d for originator %pM\n",
1515 BATADV_PRINT_VID(tt_common_entry->vid),
1516 best_entry->orig_node->orig);
1517 goto print_list;
1518 }
1519
Sven Eckelmann981d8902012-10-07 13:34:15 +02001520 last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn);
Antonio Quartullif9d8a532012-11-19 09:01:42 +01001521 seq_printf(seq,
Antonio Quartullidd24ddb2013-11-16 12:03:49 +01001522 " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n",
Sven Eckelmann981d8902012-10-07 13:34:15 +02001523 '*', tt_global_entry->common.addr,
Antonio Quartulli16052782013-06-04 12:11:41 +02001524 BATADV_PRINT_VID(tt_global_entry->common.vid),
Sven Eckelmann981d8902012-10-07 13:34:15 +02001525 best_entry->ttvn, best_entry->orig_node->orig,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001526 last_ttvn, vlan->tt.crc,
Sven Eckelmann981d8902012-10-07 13:34:15 +02001527 (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
1528 (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
Antonio Quartullidd24ddb2013-11-16 12:03:49 +01001529 (flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'),
Sven Eckelmann981d8902012-10-07 13:34:15 +02001530 (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001531
1532 batadv_orig_node_vlan_free_ref(vlan);
Sven Eckelmann981d8902012-10-07 13:34:15 +02001533 }
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001534
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001535print_list:
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001536 head = &tt_global_entry->orig_list;
1537
Sasha Levinb67bfe02013-02-27 17:06:00 -08001538 hlist_for_each_entry_rcu(orig_entry, head, list) {
Sven Eckelmann981d8902012-10-07 13:34:15 +02001539 if (best_entry == orig_entry)
1540 continue;
1541
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001542 vlan = batadv_orig_node_vlan_get(orig_entry->orig_node,
1543 tt_common_entry->vid);
1544 if (!vlan) {
1545 seq_printf(seq,
1546 " + Cannot retrieve VLAN %d for originator %pM\n",
1547 BATADV_PRINT_VID(tt_common_entry->vid),
1548 orig_entry->orig_node->orig);
1549 continue;
1550 }
1551
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001552 last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
Antonio Quartulli16052782013-06-04 12:11:41 +02001553 seq_printf(seq,
Antonio Quartullidd24ddb2013-11-16 12:03:49 +01001554 " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n",
Sven Eckelmann981d8902012-10-07 13:34:15 +02001555 '+', tt_global_entry->common.addr,
Antonio Quartulli16052782013-06-04 12:11:41 +02001556 BATADV_PRINT_VID(tt_global_entry->common.vid),
Sven Eckelmann981d8902012-10-07 13:34:15 +02001557 orig_entry->ttvn, orig_entry->orig_node->orig,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001558 last_ttvn, vlan->tt.crc,
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001559 (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001560 (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
Antonio Quartullidd24ddb2013-11-16 12:03:49 +01001561 (flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'),
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001562 (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02001563
1564 batadv_orig_node_vlan_free_ref(vlan);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001565 }
1566}
1567
Sven Eckelmann08c36d32012-05-12 02:09:39 +02001568int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001569{
1570 struct net_device *net_dev = (struct net_device *)seq->private;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001571 struct batadv_priv *bat_priv = netdev_priv(net_dev);
Sven Eckelmann807736f2012-07-15 22:26:51 +02001572 struct batadv_hashtable *hash = bat_priv->tt.global_hash;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001573 struct batadv_tt_common_entry *tt_common_entry;
1574 struct batadv_tt_global_entry *tt_global;
1575 struct batadv_hard_iface *primary_if;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001576 struct hlist_head *head;
Antonio Quartullic90681b2011-10-05 17:05:25 +02001577 uint32_t i;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001578
Marek Lindner30da63a2012-08-03 17:15:46 +02001579 primary_if = batadv_seq_print_text_primary_if_get(seq);
1580 if (!primary_if)
Marek Lindner32ae9b22011-04-20 15:40:58 +02001581 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001582
Antonio Quartulli2dafb492011-05-05 08:42:45 +02001583 seq_printf(seq,
1584 "Globally announced TT entries received via the mesh %s\n",
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001585 net_dev->name);
Antonio Quartulli16052782013-06-04 12:11:41 +02001586 seq_printf(seq, " %-13s %s %s %-15s %s (%-10s) %s\n",
1587 "Client", "VID", "(TTVN)", "Originator", "(Curr TTVN)",
1588 "CRC", "Flags");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001589
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001590 for (i = 0; i < hash->size; i++) {
1591 head = &hash->table[i];
1592
Marek Lindner7aadf882011-02-18 12:28:09 +00001593 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -08001594 hlist_for_each_entry_rcu(tt_common_entry,
Marek Lindner7aadf882011-02-18 12:28:09 +00001595 head, hash_entry) {
Sven Eckelmann56303d32012-06-05 22:31:31 +02001596 tt_global = container_of(tt_common_entry,
1597 struct batadv_tt_global_entry,
1598 common);
Antonio Quartulli46274562013-09-03 11:10:24 +02001599 batadv_tt_global_print_entry(bat_priv, tt_global, seq);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001600 }
Marek Lindner7aadf882011-02-18 12:28:09 +00001601 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001602 }
Marek Lindner32ae9b22011-04-20 15:40:58 +02001603out:
1604 if (primary_if)
Sven Eckelmanne5d89252012-05-12 13:48:54 +02001605 batadv_hardif_free_ref(primary_if);
Marek Lindner30da63a2012-08-03 17:15:46 +02001606 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001607}
1608
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01001609/**
1610 * batadv_tt_global_del_orig_entry - remove and free an orig_entry
1611 * @tt_global_entry: the global entry to remove the orig_entry from
1612 * @orig_entry: the orig entry to remove and free
1613 *
1614 * Remove an orig_entry from its list in the given tt_global_entry and
1615 * free this orig_entry afterwards.
1616 */
1617static void
1618batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry,
1619 struct batadv_tt_orig_list_entry *orig_entry)
1620{
1621 batadv_tt_global_size_dec(orig_entry->orig_node,
1622 tt_global_entry->common.vid);
1623 atomic_dec(&tt_global_entry->orig_list_count);
1624 hlist_del_rcu(&orig_entry->list);
1625 batadv_tt_orig_list_entry_free_ref(orig_entry);
1626}
1627
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001628/* deletes the orig list of a tt_global_entry */
Sven Eckelmanna5130882012-05-16 20:23:16 +02001629static void
Sven Eckelmann56303d32012-06-05 22:31:31 +02001630batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001631{
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001632 struct hlist_head *head;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001633 struct hlist_node *safe;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001634 struct batadv_tt_orig_list_entry *orig_entry;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001635
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001636 spin_lock_bh(&tt_global_entry->list_lock);
1637 head = &tt_global_entry->orig_list;
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01001638 hlist_for_each_entry_safe(orig_entry, safe, head, list)
1639 batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001640 spin_unlock_bh(&tt_global_entry->list_lock);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001641}
1642
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01001643/**
1644 * batadv_tt_global_del_orig_node - remove orig_node from a global tt entry
1645 * @bat_priv: the bat priv with all the soft interface information
1646 * @tt_global_entry: the global entry to remove the orig_node from
1647 * @orig_node: the originator announcing the client
1648 * @message: message to append to the log on deletion
1649 *
1650 * Remove the given orig_node and its according orig_entry from the given
1651 * global tt entry.
1652 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02001653static void
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01001654batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv,
1655 struct batadv_tt_global_entry *tt_global_entry,
1656 struct batadv_orig_node *orig_node,
1657 const char *message)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001658{
1659 struct hlist_head *head;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001660 struct hlist_node *safe;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001661 struct batadv_tt_orig_list_entry *orig_entry;
Antonio Quartulli16052782013-06-04 12:11:41 +02001662 unsigned short vid;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001663
1664 spin_lock_bh(&tt_global_entry->list_lock);
1665 head = &tt_global_entry->orig_list;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001666 hlist_for_each_entry_safe(orig_entry, safe, head, list) {
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001667 if (orig_entry->orig_node == orig_node) {
Antonio Quartulli16052782013-06-04 12:11:41 +02001668 vid = tt_global_entry->common.vid;
Sven Eckelmann39c75a52012-06-03 22:19:22 +02001669 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02001670 "Deleting %pM from global tt entry %pM (vid: %d): %s\n",
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02001671 orig_node->orig,
Antonio Quartulli16052782013-06-04 12:11:41 +02001672 tt_global_entry->common.addr,
1673 BATADV_PRINT_VID(vid), message);
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01001674 batadv_tt_global_del_orig_entry(tt_global_entry,
1675 orig_entry);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001676 }
1677 }
1678 spin_unlock_bh(&tt_global_entry->list_lock);
1679}
1680
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001681/* If the client is to be deleted, we check if it is the last origantor entry
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001682 * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the
1683 * timer, otherwise we simply remove the originator scheduled for deletion.
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001684 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02001685static void
Sven Eckelmann56303d32012-06-05 22:31:31 +02001686batadv_tt_global_del_roaming(struct batadv_priv *bat_priv,
1687 struct batadv_tt_global_entry *tt_global_entry,
1688 struct batadv_orig_node *orig_node,
1689 const char *message)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001690{
1691 bool last_entry = true;
1692 struct hlist_head *head;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001693 struct batadv_tt_orig_list_entry *orig_entry;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001694
1695 /* no local entry exists, case 1:
1696 * Check if this is the last one or if other entries exist.
1697 */
1698
1699 rcu_read_lock();
1700 head = &tt_global_entry->orig_list;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001701 hlist_for_each_entry_rcu(orig_entry, head, list) {
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001702 if (orig_entry->orig_node != orig_node) {
1703 last_entry = false;
1704 break;
1705 }
1706 }
1707 rcu_read_unlock();
1708
1709 if (last_entry) {
1710 /* its the last one, mark for roaming. */
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001711 tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001712 tt_global_entry->roam_at = jiffies;
1713 } else
1714 /* there is another entry, we can simply delete this
1715 * one and can still use the other one.
1716 */
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01001717 batadv_tt_global_del_orig_node(bat_priv, tt_global_entry,
1718 orig_node, message);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001719}
1720
Antonio Quartullic018ad32013-06-04 12:11:39 +02001721/**
1722 * batadv_tt_global_del - remove a client from the global table
1723 * @bat_priv: the bat priv with all the soft interface information
1724 * @orig_node: an originator serving this client
1725 * @addr: the mac address of the client
1726 * @vid: VLAN identifier
1727 * @message: a message explaining the reason for deleting the client to print
1728 * for debugging purpose
1729 * @roaming: true if the deletion has been triggered by a roaming event
1730 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02001731static void batadv_tt_global_del(struct batadv_priv *bat_priv,
1732 struct batadv_orig_node *orig_node,
Antonio Quartullic018ad32013-06-04 12:11:39 +02001733 const unsigned char *addr, unsigned short vid,
Sven Eckelmanna5130882012-05-16 20:23:16 +02001734 const char *message, bool roaming)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001735{
Sven Eckelmann170173b2012-10-07 12:02:22 +02001736 struct batadv_tt_global_entry *tt_global_entry;
Sven Eckelmann56303d32012-06-05 22:31:31 +02001737 struct batadv_tt_local_entry *local_entry = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001738
Antonio Quartullic018ad32013-06-04 12:11:39 +02001739 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001740 if (!tt_global_entry)
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001741 goto out;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001742
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001743 if (!roaming) {
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01001744 batadv_tt_global_del_orig_node(bat_priv, tt_global_entry,
1745 orig_node, message);
Sven Eckelmann92f90f52011-12-22 20:31:12 +08001746
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001747 if (hlist_empty(&tt_global_entry->orig_list))
Antonio Quartullibe73b482012-09-23 22:38:36 +02001748 batadv_tt_global_free(bat_priv, tt_global_entry,
1749 message);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001750
Sven Eckelmann92f90f52011-12-22 20:31:12 +08001751 goto out;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001752 }
Sven Eckelmann92f90f52011-12-22 20:31:12 +08001753
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001754 /* if we are deleting a global entry due to a roam
1755 * event, there are two possibilities:
1756 * 1) the client roamed from node A to node B => if there
1757 * is only one originator left for this client, we mark
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001758 * it with BATADV_TT_CLIENT_ROAM, we start a timer and we
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001759 * wait for node B to claim it. In case of timeout
1760 * the entry is purged.
1761 *
1762 * If there are other originators left, we directly delete
1763 * the originator.
1764 * 2) the client roamed to us => we can directly delete
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02001765 * the global entry, since it is useless now.
1766 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02001767 local_entry = batadv_tt_local_hash_find(bat_priv,
Antonio Quartullic018ad32013-06-04 12:11:39 +02001768 tt_global_entry->common.addr,
1769 vid);
Sven Eckelmanna5130882012-05-16 20:23:16 +02001770 if (local_entry) {
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001771 /* local entry exists, case 2: client roamed to us. */
Sven Eckelmanna5130882012-05-16 20:23:16 +02001772 batadv_tt_global_del_orig_list(tt_global_entry);
Antonio Quartullibe73b482012-09-23 22:38:36 +02001773 batadv_tt_global_free(bat_priv, tt_global_entry, message);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001774 } else
1775 /* no local entry exists, case 1: check for roaming */
Sven Eckelmanna5130882012-05-16 20:23:16 +02001776 batadv_tt_global_del_roaming(bat_priv, tt_global_entry,
1777 orig_node, message);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001778
Antonio Quartullicc47f662011-04-27 14:27:57 +02001779out:
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001780 if (tt_global_entry)
Sven Eckelmanna5130882012-05-16 20:23:16 +02001781 batadv_tt_global_entry_free_ref(tt_global_entry);
1782 if (local_entry)
1783 batadv_tt_local_entry_free_ref(local_entry);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001784}
1785
Antonio Quartulli95fb1302013-08-07 18:28:55 +02001786/**
1787 * batadv_tt_global_del_orig - remove all the TT global entries belonging to the
1788 * given originator matching the provided vid
1789 * @bat_priv: the bat priv with all the soft interface information
1790 * @orig_node: the originator owning the entries to remove
1791 * @match_vid: the VLAN identifier to match. If negative all the entries will be
1792 * removed
1793 * @message: debug message to print as "reason"
1794 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02001795void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
1796 struct batadv_orig_node *orig_node,
Antonio Quartulli95fb1302013-08-07 18:28:55 +02001797 int32_t match_vid,
Sven Eckelmann56303d32012-06-05 22:31:31 +02001798 const char *message)
Antonio Quartullia73105b2011-04-27 14:27:44 +02001799{
Sven Eckelmann56303d32012-06-05 22:31:31 +02001800 struct batadv_tt_global_entry *tt_global;
1801 struct batadv_tt_common_entry *tt_common_entry;
Antonio Quartullic90681b2011-10-05 17:05:25 +02001802 uint32_t i;
Sven Eckelmann807736f2012-07-15 22:26:51 +02001803 struct batadv_hashtable *hash = bat_priv->tt.global_hash;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001804 struct hlist_node *safe;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001805 struct hlist_head *head;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001806 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartulli16052782013-06-04 12:11:41 +02001807 unsigned short vid;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001808
Simon Wunderlich6e801492011-10-19 10:28:26 +02001809 if (!hash)
1810 return;
1811
Antonio Quartullia73105b2011-04-27 14:27:44 +02001812 for (i = 0; i < hash->size; i++) {
1813 head = &hash->table[i];
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001814 list_lock = &hash->list_locks[i];
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001815
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001816 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -08001817 hlist_for_each_entry_safe(tt_common_entry, safe,
Sven Eckelmann7c64fd92012-02-28 10:55:36 +01001818 head, hash_entry) {
Antonio Quartulli95fb1302013-08-07 18:28:55 +02001819 /* remove only matching entries */
1820 if (match_vid >= 0 && tt_common_entry->vid != match_vid)
1821 continue;
1822
Sven Eckelmann56303d32012-06-05 22:31:31 +02001823 tt_global = container_of(tt_common_entry,
1824 struct batadv_tt_global_entry,
1825 common);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001826
Linus Lüssing1d8ab8d2014-02-15 17:47:52 +01001827 batadv_tt_global_del_orig_node(bat_priv, tt_global,
1828 orig_node, message);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02001829
Sven Eckelmann56303d32012-06-05 22:31:31 +02001830 if (hlist_empty(&tt_global->orig_list)) {
Antonio Quartulli16052782013-06-04 12:11:41 +02001831 vid = tt_global->common.vid;
Sven Eckelmann39c75a52012-06-03 22:19:22 +02001832 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02001833 "Deleting global tt entry %pM (vid: %d): %s\n",
1834 tt_global->common.addr,
1835 BATADV_PRINT_VID(vid), message);
Sasha Levinb67bfe02013-02-27 17:06:00 -08001836 hlist_del_rcu(&tt_common_entry->hash_entry);
Sven Eckelmann56303d32012-06-05 22:31:31 +02001837 batadv_tt_global_entry_free_ref(tt_global);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001838 }
Antonio Quartullia73105b2011-04-27 14:27:44 +02001839 }
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001840 spin_unlock_bh(list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001841 }
Linus Lüssinge17931d2014-02-15 17:47:50 +01001842 orig_node->capa_initialized &= ~BATADV_ORIG_CAPA_HAS_TT;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001843}
1844
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001845static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
1846 char **msg)
Antonio Quartullicc47f662011-04-27 14:27:57 +02001847{
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001848 bool purge = false;
1849 unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT;
1850 unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT;
Sven Eckelmann42d0b042012-06-03 22:19:17 +02001851
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001852 if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
1853 batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
1854 purge = true;
1855 *msg = "Roaming timeout\n";
Sven Eckelmann42d0b042012-06-03 22:19:17 +02001856 }
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001857
1858 if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
1859 batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
1860 purge = true;
1861 *msg = "Temporary client timeout\n";
1862 }
1863
1864 return purge;
Sven Eckelmann42d0b042012-06-03 22:19:17 +02001865}
1866
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001867static void batadv_tt_global_purge(struct batadv_priv *bat_priv)
Sven Eckelmann42d0b042012-06-03 22:19:17 +02001868{
Sven Eckelmann807736f2012-07-15 22:26:51 +02001869 struct batadv_hashtable *hash = bat_priv->tt.global_hash;
Antonio Quartullicc47f662011-04-27 14:27:57 +02001870 struct hlist_head *head;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001871 struct hlist_node *node_tmp;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001872 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartullic90681b2011-10-05 17:05:25 +02001873 uint32_t i;
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001874 char *msg = NULL;
1875 struct batadv_tt_common_entry *tt_common;
1876 struct batadv_tt_global_entry *tt_global;
Antonio Quartullicc47f662011-04-27 14:27:57 +02001877
Antonio Quartullicc47f662011-04-27 14:27:57 +02001878 for (i = 0; i < hash->size; i++) {
1879 head = &hash->table[i];
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001880 list_lock = &hash->list_locks[i];
Antonio Quartullicc47f662011-04-27 14:27:57 +02001881
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001882 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -08001883 hlist_for_each_entry_safe(tt_common, node_tmp, head,
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001884 hash_entry) {
1885 tt_global = container_of(tt_common,
1886 struct batadv_tt_global_entry,
1887 common);
1888
1889 if (!batadv_tt_global_to_purge(tt_global, &msg))
1890 continue;
1891
1892 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02001893 "Deleting global tt entry %pM (vid: %d): %s\n",
1894 tt_global->common.addr,
1895 BATADV_PRINT_VID(tt_global->common.vid),
1896 msg);
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001897
Sasha Levinb67bfe02013-02-27 17:06:00 -08001898 hlist_del_rcu(&tt_common->hash_entry);
Antonio Quartulli30cfd022012-07-05 23:38:29 +02001899
1900 batadv_tt_global_entry_free_ref(tt_global);
1901 }
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001902 spin_unlock_bh(list_lock);
Antonio Quartullicc47f662011-04-27 14:27:57 +02001903 }
Antonio Quartullicc47f662011-04-27 14:27:57 +02001904}
1905
Sven Eckelmann56303d32012-06-05 22:31:31 +02001906static void batadv_tt_global_table_free(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001907{
Sven Eckelmann5bf74e92012-06-05 22:31:28 +02001908 struct batadv_hashtable *hash;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001909 spinlock_t *list_lock; /* protects write access to the hash lists */
Sven Eckelmann56303d32012-06-05 22:31:31 +02001910 struct batadv_tt_common_entry *tt_common_entry;
1911 struct batadv_tt_global_entry *tt_global;
Sasha Levinb67bfe02013-02-27 17:06:00 -08001912 struct hlist_node *node_tmp;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001913 struct hlist_head *head;
Antonio Quartullic90681b2011-10-05 17:05:25 +02001914 uint32_t i;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001915
Sven Eckelmann807736f2012-07-15 22:26:51 +02001916 if (!bat_priv->tt.global_hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001917 return;
1918
Sven Eckelmann807736f2012-07-15 22:26:51 +02001919 hash = bat_priv->tt.global_hash;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001920
1921 for (i = 0; i < hash->size; i++) {
1922 head = &hash->table[i];
1923 list_lock = &hash->list_locks[i];
1924
1925 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -08001926 hlist_for_each_entry_safe(tt_common_entry, node_tmp,
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001927 head, hash_entry) {
Sasha Levinb67bfe02013-02-27 17:06:00 -08001928 hlist_del_rcu(&tt_common_entry->hash_entry);
Sven Eckelmann56303d32012-06-05 22:31:31 +02001929 tt_global = container_of(tt_common_entry,
1930 struct batadv_tt_global_entry,
1931 common);
1932 batadv_tt_global_entry_free_ref(tt_global);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001933 }
1934 spin_unlock_bh(list_lock);
1935 }
1936
Sven Eckelmann1a8eaf02012-05-12 02:09:32 +02001937 batadv_hash_destroy(hash);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02001938
Sven Eckelmann807736f2012-07-15 22:26:51 +02001939 bat_priv->tt.global_hash = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001940}
1941
Sven Eckelmann56303d32012-06-05 22:31:31 +02001942static bool
1943_batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,
1944 struct batadv_tt_global_entry *tt_global_entry)
Antonio Quartulli59b699c2011-07-07 15:35:36 +02001945{
1946 bool ret = false;
1947
Sven Eckelmannacd34af2012-06-03 22:19:21 +02001948 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI &&
1949 tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI)
Antonio Quartulli59b699c2011-07-07 15:35:36 +02001950 ret = true;
1951
Antonio Quartulli2d2fcc2a2013-11-16 12:03:50 +01001952 /* check if the two clients are marked as isolated */
1953 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA &&
1954 tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA)
1955 ret = true;
1956
Antonio Quartulli59b699c2011-07-07 15:35:36 +02001957 return ret;
1958}
1959
Antonio Quartullic018ad32013-06-04 12:11:39 +02001960/**
1961 * batadv_transtable_search - get the mesh destination for a given client
1962 * @bat_priv: the bat priv with all the soft interface information
1963 * @src: mac address of the source client
1964 * @addr: mac address of the destination client
1965 * @vid: VLAN identifier
1966 *
1967 * Returns a pointer to the originator that was selected as destination in the
1968 * mesh for contacting the client 'addr', NULL otherwise.
1969 * In case of multiple originators serving the same client, the function returns
1970 * the best one (best in terms of metric towards the destination node).
1971 *
1972 * If the two clients are AP isolated the function returns NULL.
1973 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02001974struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
1975 const uint8_t *src,
Antonio Quartullic018ad32013-06-04 12:11:39 +02001976 const uint8_t *addr,
1977 unsigned short vid)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001978{
Sven Eckelmann56303d32012-06-05 22:31:31 +02001979 struct batadv_tt_local_entry *tt_local_entry = NULL;
1980 struct batadv_tt_global_entry *tt_global_entry = NULL;
1981 struct batadv_orig_node *orig_node = NULL;
Sven Eckelmann981d8902012-10-07 13:34:15 +02001982 struct batadv_tt_orig_list_entry *best_entry;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001983
Antonio Quartullieceb22a2013-11-16 12:03:51 +01001984 if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) {
Antonio Quartullic018ad32013-06-04 12:11:39 +02001985 tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
Antonio Quartulli068ee6e2012-09-23 22:38:37 +02001986 if (!tt_local_entry ||
1987 (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
Antonio Quartulli3d393e42011-07-07 15:35:37 +02001988 goto out;
1989 }
Marek Lindner7aadf882011-02-18 12:28:09 +00001990
Antonio Quartullic018ad32013-06-04 12:11:39 +02001991 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
Antonio Quartulli2dafb492011-05-05 08:42:45 +02001992 if (!tt_global_entry)
Marek Lindner7b36e8e2011-02-18 12:28:10 +00001993 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001994
Antonio Quartulli3d393e42011-07-07 15:35:37 +02001995 /* check whether the clients should not communicate due to AP
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02001996 * isolation
1997 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02001998 if (tt_local_entry &&
1999 _batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
Antonio Quartulli3d393e42011-07-07 15:35:37 +02002000 goto out;
2001
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002002 rcu_read_lock();
Antonio Quartulli46274562013-09-03 11:10:24 +02002003 best_entry = batadv_transtable_best_orig(bat_priv, tt_global_entry);
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002004 /* found anything? */
Sven Eckelmann981d8902012-10-07 13:34:15 +02002005 if (best_entry)
2006 orig_node = best_entry->orig_node;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002007 if (orig_node && !atomic_inc_not_zero(&orig_node->refcount))
2008 orig_node = NULL;
2009 rcu_read_unlock();
Sven Eckelmann981d8902012-10-07 13:34:15 +02002010
Marek Lindner7b36e8e2011-02-18 12:28:10 +00002011out:
Antonio Quartulli3d393e42011-07-07 15:35:37 +02002012 if (tt_global_entry)
Sven Eckelmanna5130882012-05-16 20:23:16 +02002013 batadv_tt_global_entry_free_ref(tt_global_entry);
Antonio Quartulli3d393e42011-07-07 15:35:37 +02002014 if (tt_local_entry)
Sven Eckelmanna5130882012-05-16 20:23:16 +02002015 batadv_tt_local_entry_free_ref(tt_local_entry);
Antonio Quartulli3d393e42011-07-07 15:35:37 +02002016
Marek Lindner7b36e8e2011-02-18 12:28:10 +00002017 return orig_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002018}
Antonio Quartullia73105b2011-04-27 14:27:44 +02002019
Antonio Quartulliced72932013-04-24 16:37:51 +02002020/**
2021 * batadv_tt_global_crc - calculates the checksum of the local table belonging
2022 * to the given orig_node
2023 * @bat_priv: the bat priv with all the soft interface information
Antonio Quartulli0ffa9e82013-06-04 12:11:40 +02002024 * @orig_node: originator for which the CRC should be computed
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002025 * @vid: VLAN identifier for which the CRC32 has to be computed
Antonio Quartulli0ffa9e82013-06-04 12:11:40 +02002026 *
2027 * This function computes the checksum for the global table corresponding to a
2028 * specific originator. In particular, the checksum is computed as follows: For
2029 * each client connected to the originator the CRC32C of the MAC address and the
2030 * VID is computed and then all the CRC32Cs of the various clients are xor'ed
2031 * together.
2032 *
2033 * The idea behind is that CRC32C should be used as much as possible in order to
2034 * produce a unique hash of the table, but since the order which is used to feed
2035 * the CRC32C function affects the result and since every node in the network
2036 * probably sorts the clients differently, the hash function cannot be directly
2037 * computed over the entire table. Hence the CRC32C is used only on
2038 * the single client entry, while all the results are then xor'ed together
2039 * because the XOR operation can combine them all while trying to reduce the
2040 * noise as much as possible.
2041 *
2042 * Returns the checksum of the global table of a given originator.
Antonio Quartulliced72932013-04-24 16:37:51 +02002043 */
2044static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002045 struct batadv_orig_node *orig_node,
2046 unsigned short vid)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002047{
Sven Eckelmann807736f2012-07-15 22:26:51 +02002048 struct batadv_hashtable *hash = bat_priv->tt.global_hash;
Sven Eckelmann56303d32012-06-05 22:31:31 +02002049 struct batadv_tt_common_entry *tt_common;
2050 struct batadv_tt_global_entry *tt_global;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002051 struct hlist_head *head;
Antonio Quartulli0ffa9e82013-06-04 12:11:40 +02002052 uint32_t i, crc_tmp, crc = 0;
Antonio Quartulli0eb015682013-10-13 02:50:20 +02002053 uint8_t flags;
Antonio Quartullia30e22c2014-02-11 17:05:06 +01002054 __be16 tmp_vid;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002055
2056 for (i = 0; i < hash->size; i++) {
2057 head = &hash->table[i];
2058
2059 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -08002060 hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
Sven Eckelmann56303d32012-06-05 22:31:31 +02002061 tt_global = container_of(tt_common,
2062 struct batadv_tt_global_entry,
2063 common);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002064 /* compute the CRC only for entries belonging to the
2065 * VLAN identified by the vid passed as parameter
2066 */
2067 if (tt_common->vid != vid)
2068 continue;
2069
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002070 /* Roaming clients are in the global table for
2071 * consistency only. They don't have to be
2072 * taken into account while computing the
2073 * global crc
2074 */
Sven Eckelmannacd34af2012-06-03 22:19:21 +02002075 if (tt_common->flags & BATADV_TT_CLIENT_ROAM)
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002076 continue;
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002077 /* Temporary clients have not been announced yet, so
2078 * they have to be skipped while computing the global
2079 * crc
2080 */
2081 if (tt_common->flags & BATADV_TT_CLIENT_TEMP)
2082 continue;
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002083
2084 /* find out if this global entry is announced by this
2085 * originator
2086 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02002087 if (!batadv_tt_global_entry_has_orig(tt_global,
Sven Eckelmanna5130882012-05-16 20:23:16 +02002088 orig_node))
Simon Wunderlichdb08e6e2011-10-22 20:12:51 +02002089 continue;
2090
Antonio Quartullia30e22c2014-02-11 17:05:06 +01002091 /* use network order to read the VID: this ensures that
2092 * every node reads the bytes in the same order.
2093 */
2094 tmp_vid = htons(tt_common->vid);
2095 crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
Antonio Quartulli0eb015682013-10-13 02:50:20 +02002096
2097 /* compute the CRC on flags that have to be kept in sync
2098 * among nodes
2099 */
2100 flags = tt_common->flags & BATADV_TT_SYNC_MASK;
2101 crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags));
2102
Antonio Quartulli0ffa9e82013-06-04 12:11:40 +02002103 crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002104 }
2105 rcu_read_unlock();
2106 }
2107
Antonio Quartulliced72932013-04-24 16:37:51 +02002108 return crc;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002109}
2110
Antonio Quartulliced72932013-04-24 16:37:51 +02002111/**
2112 * batadv_tt_local_crc - calculates the checksum of the local table
2113 * @bat_priv: the bat priv with all the soft interface information
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002114 * @vid: VLAN identifier for which the CRC32 has to be computed
Antonio Quartulli0ffa9e82013-06-04 12:11:40 +02002115 *
2116 * For details about the computation, please refer to the documentation for
2117 * batadv_tt_global_crc().
2118 *
2119 * Returns the checksum of the local table
Antonio Quartulliced72932013-04-24 16:37:51 +02002120 */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002121static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv,
2122 unsigned short vid)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002123{
Sven Eckelmann807736f2012-07-15 22:26:51 +02002124 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
Sven Eckelmann56303d32012-06-05 22:31:31 +02002125 struct batadv_tt_common_entry *tt_common;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002126 struct hlist_head *head;
Antonio Quartulli0ffa9e82013-06-04 12:11:40 +02002127 uint32_t i, crc_tmp, crc = 0;
Antonio Quartulli0eb015682013-10-13 02:50:20 +02002128 uint8_t flags;
Antonio Quartullia30e22c2014-02-11 17:05:06 +01002129 __be16 tmp_vid;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002130
2131 for (i = 0; i < hash->size; i++) {
2132 head = &hash->table[i];
2133
2134 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -08002135 hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002136 /* compute the CRC only for entries belonging to the
2137 * VLAN identified by vid
2138 */
2139 if (tt_common->vid != vid)
2140 continue;
2141
Antonio Quartulli058d0e22011-07-07 01:40:58 +02002142 /* not yet committed clients have not to be taken into
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002143 * account while computing the CRC
2144 */
Sven Eckelmannacd34af2012-06-03 22:19:21 +02002145 if (tt_common->flags & BATADV_TT_CLIENT_NEW)
Antonio Quartulli058d0e22011-07-07 01:40:58 +02002146 continue;
Antonio Quartulliced72932013-04-24 16:37:51 +02002147
Antonio Quartullia30e22c2014-02-11 17:05:06 +01002148 /* use network order to read the VID: this ensures that
2149 * every node reads the bytes in the same order.
2150 */
2151 tmp_vid = htons(tt_common->vid);
2152 crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
Antonio Quartulli0eb015682013-10-13 02:50:20 +02002153
2154 /* compute the CRC on flags that have to be kept in sync
2155 * among nodes
2156 */
2157 flags = tt_common->flags & BATADV_TT_SYNC_MASK;
2158 crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags));
2159
Antonio Quartulli0ffa9e82013-06-04 12:11:40 +02002160 crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002161 }
Antonio Quartullia73105b2011-04-27 14:27:44 +02002162 rcu_read_unlock();
2163 }
2164
Antonio Quartulliced72932013-04-24 16:37:51 +02002165 return crc;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002166}
2167
Sven Eckelmann56303d32012-06-05 22:31:31 +02002168static void batadv_tt_req_list_free(struct batadv_priv *bat_priv)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002169{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002170 struct batadv_tt_req_node *node, *safe;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002171
Sven Eckelmann807736f2012-07-15 22:26:51 +02002172 spin_lock_bh(&bat_priv->tt.req_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002173
Sven Eckelmann807736f2012-07-15 22:26:51 +02002174 list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
Antonio Quartullia73105b2011-04-27 14:27:44 +02002175 list_del(&node->list);
2176 kfree(node);
2177 }
2178
Sven Eckelmann807736f2012-07-15 22:26:51 +02002179 spin_unlock_bh(&bat_priv->tt.req_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002180}
2181
Sven Eckelmann56303d32012-06-05 22:31:31 +02002182static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv,
2183 struct batadv_orig_node *orig_node,
Antonio Quartullie8cf2342013-05-28 13:14:28 +02002184 const void *tt_buff,
2185 uint16_t tt_buff_len)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002186{
Antonio Quartullia73105b2011-04-27 14:27:44 +02002187 /* Replace the old buffer only if I received something in the
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002188 * last OGM (the OGM could carry no changes)
2189 */
Antonio Quartullia73105b2011-04-27 14:27:44 +02002190 spin_lock_bh(&orig_node->tt_buff_lock);
2191 if (tt_buff_len > 0) {
2192 kfree(orig_node->tt_buff);
2193 orig_node->tt_buff_len = 0;
2194 orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
2195 if (orig_node->tt_buff) {
2196 memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
2197 orig_node->tt_buff_len = tt_buff_len;
2198 }
2199 }
2200 spin_unlock_bh(&orig_node->tt_buff_lock);
2201}
2202
Sven Eckelmann56303d32012-06-05 22:31:31 +02002203static void batadv_tt_req_purge(struct batadv_priv *bat_priv)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002204{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002205 struct batadv_tt_req_node *node, *safe;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002206
Sven Eckelmann807736f2012-07-15 22:26:51 +02002207 spin_lock_bh(&bat_priv->tt.req_list_lock);
2208 list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
Sven Eckelmann42d0b042012-06-03 22:19:17 +02002209 if (batadv_has_timed_out(node->issued_at,
2210 BATADV_TT_REQUEST_TIMEOUT)) {
Antonio Quartullia73105b2011-04-27 14:27:44 +02002211 list_del(&node->list);
2212 kfree(node);
2213 }
2214 }
Sven Eckelmann807736f2012-07-15 22:26:51 +02002215 spin_unlock_bh(&bat_priv->tt.req_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002216}
2217
2218/* returns the pointer to the new tt_req_node struct if no request
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002219 * has already been issued for this orig_node, NULL otherwise
2220 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02002221static struct batadv_tt_req_node *
2222batadv_new_tt_req_node(struct batadv_priv *bat_priv,
2223 struct batadv_orig_node *orig_node)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002224{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002225 struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002226
Sven Eckelmann807736f2012-07-15 22:26:51 +02002227 spin_lock_bh(&bat_priv->tt.req_list_lock);
2228 list_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) {
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02002229 if (batadv_compare_eth(tt_req_node_tmp, orig_node) &&
2230 !batadv_has_timed_out(tt_req_node_tmp->issued_at,
Sven Eckelmann42d0b042012-06-03 22:19:17 +02002231 BATADV_TT_REQUEST_TIMEOUT))
Antonio Quartullia73105b2011-04-27 14:27:44 +02002232 goto unlock;
2233 }
2234
2235 tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
2236 if (!tt_req_node)
2237 goto unlock;
2238
Antonio Quartulli8fdd0152014-01-22 00:42:11 +01002239 ether_addr_copy(tt_req_node->addr, orig_node->orig);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002240 tt_req_node->issued_at = jiffies;
2241
Sven Eckelmann807736f2012-07-15 22:26:51 +02002242 list_add(&tt_req_node->list, &bat_priv->tt.req_list);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002243unlock:
Sven Eckelmann807736f2012-07-15 22:26:51 +02002244 spin_unlock_bh(&bat_priv->tt.req_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002245 return tt_req_node;
2246}
2247
Marek Lindner335fbe02013-04-23 21:40:02 +08002248/**
2249 * batadv_tt_local_valid - verify that given tt entry is a valid one
2250 * @entry_ptr: to be checked local tt entry
2251 * @data_ptr: not used but definition required to satisfy the callback prototype
2252 *
2253 * Returns 1 if the entry is a valid, 0 otherwise.
2254 */
2255static int batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr)
Antonio Quartulli058d0e22011-07-07 01:40:58 +02002256{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002257 const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02002258
Sven Eckelmannacd34af2012-06-03 22:19:21 +02002259 if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
Antonio Quartulli058d0e22011-07-07 01:40:58 +02002260 return 0;
2261 return 1;
2262}
2263
Sven Eckelmanna5130882012-05-16 20:23:16 +02002264static int batadv_tt_global_valid(const void *entry_ptr,
2265 const void *data_ptr)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002266{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002267 const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
2268 const struct batadv_tt_global_entry *tt_global_entry;
2269 const struct batadv_orig_node *orig_node = data_ptr;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002270
Antonio Quartulli30cfd022012-07-05 23:38:29 +02002271 if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ||
2272 tt_common_entry->flags & BATADV_TT_CLIENT_TEMP)
Antonio Quartullicc47f662011-04-27 14:27:57 +02002273 return 0;
2274
Sven Eckelmann56303d32012-06-05 22:31:31 +02002275 tt_global_entry = container_of(tt_common_entry,
2276 struct batadv_tt_global_entry,
Antonio Quartulli48100ba2011-10-30 12:17:33 +01002277 common);
2278
Sven Eckelmanna5130882012-05-16 20:23:16 +02002279 return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002280}
2281
Marek Lindner335fbe02013-04-23 21:40:02 +08002282/**
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002283 * batadv_tt_tvlv_generate - fill the tvlv buff with the tt entries from the
2284 * specified tt hash
Marek Lindner335fbe02013-04-23 21:40:02 +08002285 * @bat_priv: the bat priv with all the soft interface information
2286 * @hash: hash table containing the tt entries
2287 * @tt_len: expected tvlv tt data buffer length in number of bytes
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002288 * @tvlv_buff: pointer to the buffer to fill with the TT data
Marek Lindner335fbe02013-04-23 21:40:02 +08002289 * @valid_cb: function to filter tt change entries
2290 * @cb_data: data passed to the filter function as argument
Marek Lindner335fbe02013-04-23 21:40:02 +08002291 */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002292static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
2293 struct batadv_hashtable *hash,
2294 void *tvlv_buff, uint16_t tt_len,
2295 int (*valid_cb)(const void *, const void *),
2296 void *cb_data)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002297{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002298 struct batadv_tt_common_entry *tt_common_entry;
Marek Lindner335fbe02013-04-23 21:40:02 +08002299 struct batadv_tvlv_tt_change *tt_change;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002300 struct hlist_head *head;
Marek Lindner335fbe02013-04-23 21:40:02 +08002301 uint16_t tt_tot, tt_num_entries = 0;
Antonio Quartullic90681b2011-10-05 17:05:25 +02002302 uint32_t i;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002303
Antonio Quartulli298e6e62013-05-28 13:14:27 +02002304 tt_tot = batadv_tt_entries(tt_len);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002305 tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002306
2307 rcu_read_lock();
2308 for (i = 0; i < hash->size; i++) {
2309 head = &hash->table[i];
2310
Sasha Levinb67bfe02013-02-27 17:06:00 -08002311 hlist_for_each_entry_rcu(tt_common_entry,
Antonio Quartullia73105b2011-04-27 14:27:44 +02002312 head, hash_entry) {
Marek Lindner335fbe02013-04-23 21:40:02 +08002313 if (tt_tot == tt_num_entries)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002314 break;
2315
Antonio Quartulli48100ba2011-10-30 12:17:33 +01002316 if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
Antonio Quartullia73105b2011-04-27 14:27:44 +02002317 continue;
2318
Antonio Quartulli8fdd0152014-01-22 00:42:11 +01002319 ether_addr_copy(tt_change->addr, tt_common_entry->addr);
Antonio Quartulli27b37eb2012-11-08 14:21:11 +01002320 tt_change->flags = tt_common_entry->flags;
Antonio Quartullic018ad32013-06-04 12:11:39 +02002321 tt_change->vid = htons(tt_common_entry->vid);
Antonio Quartullica663042013-12-15 13:26:55 +01002322 memset(tt_change->reserved, 0,
2323 sizeof(tt_change->reserved));
Antonio Quartullia73105b2011-04-27 14:27:44 +02002324
Marek Lindner335fbe02013-04-23 21:40:02 +08002325 tt_num_entries++;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002326 tt_change++;
2327 }
2328 }
2329 rcu_read_unlock();
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002330}
Antonio Quartullia73105b2011-04-27 14:27:44 +02002331
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002332/**
2333 * batadv_tt_global_check_crc - check if all the CRCs are correct
2334 * @orig_node: originator for which the CRCs have to be checked
2335 * @tt_vlan: pointer to the first tvlv VLAN entry
2336 * @num_vlan: number of tvlv VLAN entries
2337 * @create: if true, create VLAN objects if not found
2338 *
2339 * Return true if all the received CRCs match the locally stored ones, false
2340 * otherwise
2341 */
2342static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node,
2343 struct batadv_tvlv_tt_vlan_data *tt_vlan,
2344 uint16_t num_vlan)
2345{
2346 struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp;
2347 struct batadv_orig_node_vlan *vlan;
Antonio Quartulli91c2b1a2014-01-28 02:06:47 +01002348 uint32_t crc;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002349 int i;
2350
2351 /* check if each received CRC matches the locally stored one */
2352 for (i = 0; i < num_vlan; i++) {
2353 tt_vlan_tmp = tt_vlan + i;
2354
2355 /* if orig_node is a backbone node for this VLAN, don't check
2356 * the CRC as we ignore all the global entries over it
2357 */
2358 if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv,
Antonio Quartullicfd4f752013-08-07 18:28:56 +02002359 orig_node->orig,
2360 ntohs(tt_vlan_tmp->vid)))
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002361 continue;
2362
2363 vlan = batadv_orig_node_vlan_get(orig_node,
2364 ntohs(tt_vlan_tmp->vid));
2365 if (!vlan)
2366 return false;
2367
Antonio Quartulli91c2b1a2014-01-28 02:06:47 +01002368 crc = vlan->tt.crc;
2369 batadv_orig_node_vlan_free_ref(vlan);
2370
2371 if (crc != ntohl(tt_vlan_tmp->crc))
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002372 return false;
2373 }
2374
2375 return true;
2376}
2377
2378/**
2379 * batadv_tt_local_update_crc - update all the local CRCs
2380 * @bat_priv: the bat priv with all the soft interface information
2381 */
2382static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv)
2383{
2384 struct batadv_softif_vlan *vlan;
2385
2386 /* recompute the global CRC for each VLAN */
2387 rcu_read_lock();
2388 hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
2389 vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid);
2390 }
2391 rcu_read_unlock();
2392}
2393
2394/**
2395 * batadv_tt_global_update_crc - update all the global CRCs for this orig_node
2396 * @bat_priv: the bat priv with all the soft interface information
2397 * @orig_node: the orig_node for which the CRCs have to be updated
2398 */
2399static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv,
2400 struct batadv_orig_node *orig_node)
2401{
2402 struct batadv_orig_node_vlan *vlan;
2403 uint32_t crc;
2404
2405 /* recompute the global CRC for each VLAN */
2406 rcu_read_lock();
2407 list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
2408 /* if orig_node is a backbone node for this VLAN, don't compute
2409 * the CRC as we ignore all the global entries over it
2410 */
Antonio Quartullicfd4f752013-08-07 18:28:56 +02002411 if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig,
2412 vlan->vid))
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002413 continue;
2414
2415 crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid);
2416 vlan->tt.crc = crc;
2417 }
2418 rcu_read_unlock();
Antonio Quartullia73105b2011-04-27 14:27:44 +02002419}
2420
Antonio Quartulliced72932013-04-24 16:37:51 +02002421/**
2422 * batadv_send_tt_request - send a TT Request message to a given node
2423 * @bat_priv: the bat priv with all the soft interface information
2424 * @dst_orig_node: the destination of the message
2425 * @ttvn: the version number that the source of the message is looking for
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002426 * @tt_vlan: pointer to the first tvlv VLAN object to request
2427 * @num_vlan: number of tvlv VLAN entries
Antonio Quartulliced72932013-04-24 16:37:51 +02002428 * @full_table: ask for the entire translation table if true, while only for the
2429 * last TT diff otherwise
2430 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02002431static int batadv_send_tt_request(struct batadv_priv *bat_priv,
2432 struct batadv_orig_node *dst_orig_node,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002433 uint8_t ttvn,
2434 struct batadv_tvlv_tt_vlan_data *tt_vlan,
2435 uint16_t num_vlan, bool full_table)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002436{
Marek Lindner335fbe02013-04-23 21:40:02 +08002437 struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
Sven Eckelmann56303d32012-06-05 22:31:31 +02002438 struct batadv_tt_req_node *tt_req_node = NULL;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002439 struct batadv_tvlv_tt_vlan_data *tt_vlan_req;
2440 struct batadv_hard_iface *primary_if;
Marek Lindner335fbe02013-04-23 21:40:02 +08002441 bool ret = false;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002442 int i, size;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002443
Sven Eckelmanne5d89252012-05-12 13:48:54 +02002444 primary_if = batadv_primary_if_get_selected(bat_priv);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002445 if (!primary_if)
2446 goto out;
2447
2448 /* The new tt_req will be issued only if I'm not waiting for a
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002449 * reply from the same orig_node yet
2450 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02002451 tt_req_node = batadv_new_tt_req_node(bat_priv, dst_orig_node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002452 if (!tt_req_node)
2453 goto out;
2454
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002455 size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan;
2456 tvlv_tt_data = kzalloc(size, GFP_ATOMIC);
Marek Lindner335fbe02013-04-23 21:40:02 +08002457 if (!tvlv_tt_data)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002458 goto out;
2459
Marek Lindner335fbe02013-04-23 21:40:02 +08002460 tvlv_tt_data->flags = BATADV_TT_REQUEST;
2461 tvlv_tt_data->ttvn = ttvn;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002462 tvlv_tt_data->num_vlan = htons(num_vlan);
2463
2464 /* send all the CRCs within the request. This is needed by intermediate
2465 * nodes to ensure they have the correct table before replying
2466 */
2467 tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1);
2468 for (i = 0; i < num_vlan; i++) {
2469 tt_vlan_req->vid = tt_vlan->vid;
2470 tt_vlan_req->crc = tt_vlan->crc;
2471
2472 tt_vlan_req++;
2473 tt_vlan++;
2474 }
Antonio Quartullia73105b2011-04-27 14:27:44 +02002475
2476 if (full_table)
Marek Lindner335fbe02013-04-23 21:40:02 +08002477 tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002478
Martin Hundebøllbb351ba2012-10-16 16:13:48 +02002479 batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n",
Marek Lindner335fbe02013-04-23 21:40:02 +08002480 dst_orig_node->orig, full_table ? 'F' : '.');
Antonio Quartullia73105b2011-04-27 14:27:44 +02002481
Sven Eckelmannd69909d2012-06-03 22:19:20 +02002482 batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX);
Marek Lindner335fbe02013-04-23 21:40:02 +08002483 batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
2484 dst_orig_node->orig, BATADV_TVLV_TT, 1,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002485 tvlv_tt_data, size);
Marek Lindner335fbe02013-04-23 21:40:02 +08002486 ret = true;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002487
2488out:
Antonio Quartullia73105b2011-04-27 14:27:44 +02002489 if (primary_if)
Sven Eckelmanne5d89252012-05-12 13:48:54 +02002490 batadv_hardif_free_ref(primary_if);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002491 if (ret && tt_req_node) {
Sven Eckelmann807736f2012-07-15 22:26:51 +02002492 spin_lock_bh(&bat_priv->tt.req_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002493 list_del(&tt_req_node->list);
Sven Eckelmann807736f2012-07-15 22:26:51 +02002494 spin_unlock_bh(&bat_priv->tt.req_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002495 kfree(tt_req_node);
2496 }
Marek Lindner335fbe02013-04-23 21:40:02 +08002497 kfree(tvlv_tt_data);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002498 return ret;
2499}
2500
Marek Lindner335fbe02013-04-23 21:40:02 +08002501/**
2502 * batadv_send_other_tt_response - send reply to tt request concerning another
2503 * node's translation table
2504 * @bat_priv: the bat priv with all the soft interface information
2505 * @tt_data: tt data containing the tt request information
2506 * @req_src: mac address of tt request sender
2507 * @req_dst: mac address of tt request recipient
2508 *
2509 * Returns true if tt request reply was sent, false otherwise.
2510 */
2511static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
2512 struct batadv_tvlv_tt_data *tt_data,
2513 uint8_t *req_src, uint8_t *req_dst)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002514{
Sven Eckelmann170173b2012-10-07 12:02:22 +02002515 struct batadv_orig_node *req_dst_orig_node;
Sven Eckelmann56303d32012-06-05 22:31:31 +02002516 struct batadv_orig_node *res_dst_orig_node = NULL;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002517 struct batadv_tvlv_tt_change *tt_change;
Marek Lindner335fbe02013-04-23 21:40:02 +08002518 struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002519 struct batadv_tvlv_tt_vlan_data *tt_vlan;
Marek Lindner335fbe02013-04-23 21:40:02 +08002520 bool ret = false, full_table;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002521 uint8_t orig_ttvn, req_ttvn;
2522 uint16_t tvlv_len;
2523 int32_t tt_len;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002524
Sven Eckelmann39c75a52012-06-03 22:19:22 +02002525 batadv_dbg(BATADV_DBG_TT, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02002526 "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n",
Marek Lindner335fbe02013-04-23 21:40:02 +08002527 req_src, tt_data->ttvn, req_dst,
2528 (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
Antonio Quartullia73105b2011-04-27 14:27:44 +02002529
2530 /* Let's get the orig node of the REAL destination */
Marek Lindner335fbe02013-04-23 21:40:02 +08002531 req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002532 if (!req_dst_orig_node)
2533 goto out;
2534
Marek Lindner335fbe02013-04-23 21:40:02 +08002535 res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002536 if (!res_dst_orig_node)
2537 goto out;
2538
Antonio Quartullia73105b2011-04-27 14:27:44 +02002539 orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
Marek Lindner335fbe02013-04-23 21:40:02 +08002540 req_ttvn = tt_data->ttvn;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002541
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002542 tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1);
Marek Lindner335fbe02013-04-23 21:40:02 +08002543 /* this node doesn't have the requested data */
Antonio Quartullia73105b2011-04-27 14:27:44 +02002544 if (orig_ttvn != req_ttvn ||
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002545 !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan,
2546 ntohs(tt_data->num_vlan)))
Antonio Quartullia73105b2011-04-27 14:27:44 +02002547 goto out;
2548
Antonio Quartulli015758d2011-07-09 17:52:13 +02002549 /* If the full table has been explicitly requested */
Marek Lindner335fbe02013-04-23 21:40:02 +08002550 if (tt_data->flags & BATADV_TT_FULL_TABLE ||
Antonio Quartullia73105b2011-04-27 14:27:44 +02002551 !req_dst_orig_node->tt_buff)
2552 full_table = true;
2553 else
2554 full_table = false;
2555
Marek Lindner335fbe02013-04-23 21:40:02 +08002556 /* TT fragmentation hasn't been implemented yet, so send as many
2557 * TT entries fit a single packet as possible only
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002558 */
Antonio Quartullia73105b2011-04-27 14:27:44 +02002559 if (!full_table) {
2560 spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
2561 tt_len = req_dst_orig_node->tt_buff_len;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002562
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002563 tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node,
2564 &tvlv_tt_data,
2565 &tt_change,
2566 &tt_len);
2567 if (!tt_len)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002568 goto unlock;
2569
Antonio Quartullia73105b2011-04-27 14:27:44 +02002570 /* Copy the last orig_node's OGM buffer */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002571 memcpy(tt_change, req_dst_orig_node->tt_buff,
Antonio Quartullia73105b2011-04-27 14:27:44 +02002572 req_dst_orig_node->tt_buff_len);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002573 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
2574 } else {
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002575 /* allocate the tvlv, put the tt_data and all the tt_vlan_data
2576 * in the initial part
2577 */
2578 tt_len = -1;
2579 tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node,
2580 &tvlv_tt_data,
2581 &tt_change,
2582 &tt_len);
2583 if (!tt_len)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002584 goto out;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002585
2586 /* fill the rest of the tvlv with the real TT entries */
2587 batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash,
2588 tt_change, tt_len,
2589 batadv_tt_global_valid,
2590 req_dst_orig_node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002591 }
2592
Marek Lindnera19d3d82013-05-27 15:33:25 +08002593 /* Don't send the response, if larger than fragmented packet. */
2594 tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len;
2595 if (tt_len > atomic_read(&bat_priv->packet_size_max)) {
2596 net_ratelimited_function(batadv_info, bat_priv->soft_iface,
2597 "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n",
2598 res_dst_orig_node->orig);
2599 goto out;
2600 }
2601
Marek Lindner335fbe02013-04-23 21:40:02 +08002602 tvlv_tt_data->flags = BATADV_TT_RESPONSE;
2603 tvlv_tt_data->ttvn = req_ttvn;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002604
2605 if (full_table)
Marek Lindner335fbe02013-04-23 21:40:02 +08002606 tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002607
Sven Eckelmann39c75a52012-06-03 22:19:22 +02002608 batadv_dbg(BATADV_DBG_TT, bat_priv,
Marek Lindner335fbe02013-04-23 21:40:02 +08002609 "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n",
2610 res_dst_orig_node->orig, req_dst_orig_node->orig,
2611 full_table ? 'F' : '.', req_ttvn);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002612
Sven Eckelmannd69909d2012-06-03 22:19:20 +02002613 batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
Martin Hundebøllf8214862012-04-20 17:02:45 +02002614
Marek Lindner335fbe02013-04-23 21:40:02 +08002615 batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002616 req_src, BATADV_TVLV_TT, 1, tvlv_tt_data,
2617 tvlv_len);
Martin Hundebølle91ecfc2013-04-20 13:54:39 +02002618
Marek Lindner335fbe02013-04-23 21:40:02 +08002619 ret = true;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002620 goto out;
2621
2622unlock:
2623 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
2624
2625out:
2626 if (res_dst_orig_node)
Sven Eckelmann7d211ef2012-05-12 02:09:34 +02002627 batadv_orig_node_free_ref(res_dst_orig_node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002628 if (req_dst_orig_node)
Sven Eckelmann7d211ef2012-05-12 02:09:34 +02002629 batadv_orig_node_free_ref(req_dst_orig_node);
Marek Lindner335fbe02013-04-23 21:40:02 +08002630 kfree(tvlv_tt_data);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002631 return ret;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002632}
Sven Eckelmann96412692012-06-05 22:31:30 +02002633
Marek Lindner335fbe02013-04-23 21:40:02 +08002634/**
2635 * batadv_send_my_tt_response - send reply to tt request concerning this node's
2636 * translation table
2637 * @bat_priv: the bat priv with all the soft interface information
2638 * @tt_data: tt data containing the tt request information
2639 * @req_src: mac address of tt request sender
2640 *
2641 * Returns true if tt request reply was sent, false otherwise.
2642 */
2643static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
2644 struct batadv_tvlv_tt_data *tt_data,
2645 uint8_t *req_src)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002646{
Marek Lindner335fbe02013-04-23 21:40:02 +08002647 struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
Sven Eckelmann56303d32012-06-05 22:31:31 +02002648 struct batadv_hard_iface *primary_if = NULL;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002649 struct batadv_tvlv_tt_change *tt_change;
2650 struct batadv_orig_node *orig_node;
Marek Lindner335fbe02013-04-23 21:40:02 +08002651 uint8_t my_ttvn, req_ttvn;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002652 uint16_t tvlv_len;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002653 bool full_table;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002654 int32_t tt_len;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002655
Sven Eckelmann39c75a52012-06-03 22:19:22 +02002656 batadv_dbg(BATADV_DBG_TT, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02002657 "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n",
Marek Lindner335fbe02013-04-23 21:40:02 +08002658 req_src, tt_data->ttvn,
2659 (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
Antonio Quartullia73105b2011-04-27 14:27:44 +02002660
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02002661 spin_lock_bh(&bat_priv->tt.commit_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002662
Sven Eckelmann807736f2012-07-15 22:26:51 +02002663 my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn);
Marek Lindner335fbe02013-04-23 21:40:02 +08002664 req_ttvn = tt_data->ttvn;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002665
Marek Lindner335fbe02013-04-23 21:40:02 +08002666 orig_node = batadv_orig_hash_find(bat_priv, req_src);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002667 if (!orig_node)
2668 goto out;
2669
Sven Eckelmanne5d89252012-05-12 13:48:54 +02002670 primary_if = batadv_primary_if_get_selected(bat_priv);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002671 if (!primary_if)
2672 goto out;
2673
2674 /* If the full table has been explicitly requested or the gap
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002675 * is too big send the whole local translation table
2676 */
Marek Lindner335fbe02013-04-23 21:40:02 +08002677 if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn ||
Sven Eckelmann807736f2012-07-15 22:26:51 +02002678 !bat_priv->tt.last_changeset)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002679 full_table = true;
2680 else
2681 full_table = false;
2682
Marek Lindner335fbe02013-04-23 21:40:02 +08002683 /* TT fragmentation hasn't been implemented yet, so send as many
2684 * TT entries fit a single packet as possible only
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002685 */
Antonio Quartullia73105b2011-04-27 14:27:44 +02002686 if (!full_table) {
Sven Eckelmann807736f2012-07-15 22:26:51 +02002687 spin_lock_bh(&bat_priv->tt.last_changeset_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002688
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002689 tt_len = bat_priv->tt.last_changeset_len;
2690 tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv,
2691 &tvlv_tt_data,
2692 &tt_change,
2693 &tt_len);
2694 if (!tt_len)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002695 goto unlock;
2696
Marek Lindner335fbe02013-04-23 21:40:02 +08002697 /* Copy the last orig_node's OGM buffer */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002698 memcpy(tt_change, bat_priv->tt.last_changeset,
Sven Eckelmann807736f2012-07-15 22:26:51 +02002699 bat_priv->tt.last_changeset_len);
2700 spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002701 } else {
Marek Lindner335fbe02013-04-23 21:40:02 +08002702 req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002703
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002704 /* allocate the tvlv, put the tt_data and all the tt_vlan_data
2705 * in the initial part
2706 */
2707 tt_len = -1;
2708 tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv,
2709 &tvlv_tt_data,
2710 &tt_change,
2711 &tt_len);
2712 if (!tt_len)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002713 goto out;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002714
2715 /* fill the rest of the tvlv with the real TT entries */
2716 batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash,
2717 tt_change, tt_len,
2718 batadv_tt_local_valid, NULL);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002719 }
2720
Marek Lindner335fbe02013-04-23 21:40:02 +08002721 tvlv_tt_data->flags = BATADV_TT_RESPONSE;
2722 tvlv_tt_data->ttvn = req_ttvn;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002723
2724 if (full_table)
Marek Lindner335fbe02013-04-23 21:40:02 +08002725 tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002726
Sven Eckelmann39c75a52012-06-03 22:19:22 +02002727 batadv_dbg(BATADV_DBG_TT, bat_priv,
Marek Lindner335fbe02013-04-23 21:40:02 +08002728 "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n",
2729 orig_node->orig, full_table ? 'F' : '.', req_ttvn);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002730
Sven Eckelmannd69909d2012-06-03 22:19:20 +02002731 batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
Martin Hundebøllf8214862012-04-20 17:02:45 +02002732
Marek Lindner335fbe02013-04-23 21:40:02 +08002733 batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002734 req_src, BATADV_TVLV_TT, 1, tvlv_tt_data,
2735 tvlv_len);
Marek Lindner335fbe02013-04-23 21:40:02 +08002736
Antonio Quartullia73105b2011-04-27 14:27:44 +02002737 goto out;
2738
2739unlock:
Sven Eckelmann807736f2012-07-15 22:26:51 +02002740 spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002741out:
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02002742 spin_unlock_bh(&bat_priv->tt.commit_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002743 if (orig_node)
Sven Eckelmann7d211ef2012-05-12 02:09:34 +02002744 batadv_orig_node_free_ref(orig_node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002745 if (primary_if)
Sven Eckelmanne5d89252012-05-12 13:48:54 +02002746 batadv_hardif_free_ref(primary_if);
Marek Lindner335fbe02013-04-23 21:40:02 +08002747 kfree(tvlv_tt_data);
2748 /* The packet was for this host, so it doesn't need to be re-routed */
Antonio Quartullia73105b2011-04-27 14:27:44 +02002749 return true;
2750}
2751
Marek Lindner335fbe02013-04-23 21:40:02 +08002752/**
2753 * batadv_send_tt_response - send reply to tt request
2754 * @bat_priv: the bat priv with all the soft interface information
2755 * @tt_data: tt data containing the tt request information
2756 * @req_src: mac address of tt request sender
2757 * @req_dst: mac address of tt request recipient
2758 *
2759 * Returns true if tt request reply was sent, false otherwise.
2760 */
2761static bool batadv_send_tt_response(struct batadv_priv *bat_priv,
2762 struct batadv_tvlv_tt_data *tt_data,
2763 uint8_t *req_src, uint8_t *req_dst)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002764{
Antonio Quartullicfd4f752013-08-07 18:28:56 +02002765 if (batadv_is_my_mac(bat_priv, req_dst))
Marek Lindner335fbe02013-04-23 21:40:02 +08002766 return batadv_send_my_tt_response(bat_priv, tt_data, req_src);
Antonio Quartulli24820df2014-09-01 14:37:25 +02002767 return batadv_send_other_tt_response(bat_priv, tt_data, req_src,
2768 req_dst);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002769}
2770
Sven Eckelmann56303d32012-06-05 22:31:31 +02002771static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
2772 struct batadv_orig_node *orig_node,
Marek Lindner335fbe02013-04-23 21:40:02 +08002773 struct batadv_tvlv_tt_change *tt_change,
Sven Eckelmanna5130882012-05-16 20:23:16 +02002774 uint16_t tt_num_changes, uint8_t ttvn)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002775{
2776 int i;
Sven Eckelmanna5130882012-05-16 20:23:16 +02002777 int roams;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002778
2779 for (i = 0; i < tt_num_changes; i++) {
Sven Eckelmannacd34af2012-06-03 22:19:21 +02002780 if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) {
2781 roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM;
Sven Eckelmanna5130882012-05-16 20:23:16 +02002782 batadv_tt_global_del(bat_priv, orig_node,
2783 (tt_change + i)->addr,
Antonio Quartullic018ad32013-06-04 12:11:39 +02002784 ntohs((tt_change + i)->vid),
Antonio Quartullid4f44692012-05-25 00:00:54 +02002785 "tt removed by changes",
2786 roams);
Sven Eckelmann08c36d32012-05-12 02:09:39 +02002787 } else {
Sven Eckelmann08c36d32012-05-12 02:09:39 +02002788 if (!batadv_tt_global_add(bat_priv, orig_node,
Antonio Quartullid4f44692012-05-25 00:00:54 +02002789 (tt_change + i)->addr,
Antonio Quartullic018ad32013-06-04 12:11:39 +02002790 ntohs((tt_change + i)->vid),
Antonio Quartullid4f44692012-05-25 00:00:54 +02002791 (tt_change + i)->flags, ttvn))
Antonio Quartullia73105b2011-04-27 14:27:44 +02002792 /* In case of problem while storing a
2793 * global_entry, we stop the updating
2794 * procedure without committing the
2795 * ttvn change. This will avoid to send
2796 * corrupted data on tt_request
2797 */
2798 return;
Sven Eckelmann08c36d32012-05-12 02:09:39 +02002799 }
Antonio Quartullia73105b2011-04-27 14:27:44 +02002800 }
Linus Lüssinge17931d2014-02-15 17:47:50 +01002801 orig_node->capa_initialized |= BATADV_ORIG_CAPA_HAS_TT;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002802}
2803
Sven Eckelmann56303d32012-06-05 22:31:31 +02002804static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002805 struct batadv_tvlv_tt_change *tt_change,
2806 uint8_t ttvn, uint8_t *resp_src,
2807 uint16_t num_entries)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002808{
Sven Eckelmann170173b2012-10-07 12:02:22 +02002809 struct batadv_orig_node *orig_node;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002810
Marek Lindner335fbe02013-04-23 21:40:02 +08002811 orig_node = batadv_orig_hash_find(bat_priv, resp_src);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002812 if (!orig_node)
2813 goto out;
2814
2815 /* Purge the old table first.. */
Antonio Quartulli95fb1302013-08-07 18:28:55 +02002816 batadv_tt_global_del_orig(bat_priv, orig_node, -1,
2817 "Received full table");
Antonio Quartullia73105b2011-04-27 14:27:44 +02002818
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002819 _batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries,
2820 ttvn);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002821
2822 spin_lock_bh(&orig_node->tt_buff_lock);
2823 kfree(orig_node->tt_buff);
2824 orig_node->tt_buff_len = 0;
2825 orig_node->tt_buff = NULL;
2826 spin_unlock_bh(&orig_node->tt_buff_lock);
2827
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002828 atomic_set(&orig_node->last_ttvn, ttvn);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002829
2830out:
2831 if (orig_node)
Sven Eckelmann7d211ef2012-05-12 02:09:34 +02002832 batadv_orig_node_free_ref(orig_node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002833}
2834
Sven Eckelmann56303d32012-06-05 22:31:31 +02002835static void batadv_tt_update_changes(struct batadv_priv *bat_priv,
2836 struct batadv_orig_node *orig_node,
Sven Eckelmanna5130882012-05-16 20:23:16 +02002837 uint16_t tt_num_changes, uint8_t ttvn,
Marek Lindner335fbe02013-04-23 21:40:02 +08002838 struct batadv_tvlv_tt_change *tt_change)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002839{
Sven Eckelmanna5130882012-05-16 20:23:16 +02002840 _batadv_tt_update_changes(bat_priv, orig_node, tt_change,
2841 tt_num_changes, ttvn);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002842
Antonio Quartullie8cf2342013-05-28 13:14:28 +02002843 batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change,
2844 batadv_tt_len(tt_num_changes));
Antonio Quartullia73105b2011-04-27 14:27:44 +02002845 atomic_set(&orig_node->last_ttvn, ttvn);
2846}
2847
Antonio Quartullic018ad32013-06-04 12:11:39 +02002848/**
2849 * batadv_is_my_client - check if a client is served by the local node
2850 * @bat_priv: the bat priv with all the soft interface information
Antonio Quartulli3f687852014-11-02 11:29:56 +01002851 * @addr: the mac address of the client to check
Antonio Quartullic018ad32013-06-04 12:11:39 +02002852 * @vid: VLAN identifier
2853 *
2854 * Returns true if the client is served by this node, false otherwise.
2855 */
2856bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr,
2857 unsigned short vid)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002858{
Sven Eckelmann170173b2012-10-07 12:02:22 +02002859 struct batadv_tt_local_entry *tt_local_entry;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002860 bool ret = false;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002861
Antonio Quartullic018ad32013-06-04 12:11:39 +02002862 tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002863 if (!tt_local_entry)
2864 goto out;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02002865 /* Check if the client has been logically deleted (but is kept for
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002866 * consistency purpose)
2867 */
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02002868 if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) ||
2869 (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM))
Antonio Quartulli058d0e22011-07-07 01:40:58 +02002870 goto out;
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002871 ret = true;
2872out:
Antonio Quartullia73105b2011-04-27 14:27:44 +02002873 if (tt_local_entry)
Sven Eckelmanna5130882012-05-16 20:23:16 +02002874 batadv_tt_local_entry_free_ref(tt_local_entry);
Antonio Quartulli7683fdc2011-04-27 14:28:07 +02002875 return ret;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002876}
2877
Marek Lindner335fbe02013-04-23 21:40:02 +08002878/**
2879 * batadv_handle_tt_response - process incoming tt reply
2880 * @bat_priv: the bat priv with all the soft interface information
2881 * @tt_data: tt data containing the tt request information
2882 * @resp_src: mac address of tt reply sender
2883 * @num_entries: number of tt change entries appended to the tt data
2884 */
2885static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
2886 struct batadv_tvlv_tt_data *tt_data,
2887 uint8_t *resp_src, uint16_t num_entries)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002888{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002889 struct batadv_tt_req_node *node, *safe;
2890 struct batadv_orig_node *orig_node = NULL;
Marek Lindner335fbe02013-04-23 21:40:02 +08002891 struct batadv_tvlv_tt_change *tt_change;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002892 uint8_t *tvlv_ptr = (uint8_t *)tt_data;
2893 uint16_t change_offset;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002894
Sven Eckelmann39c75a52012-06-03 22:19:22 +02002895 batadv_dbg(BATADV_DBG_TT, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02002896 "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n",
Marek Lindner335fbe02013-04-23 21:40:02 +08002897 resp_src, tt_data->ttvn, num_entries,
2898 (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
Antonio Quartullia73105b2011-04-27 14:27:44 +02002899
Marek Lindner335fbe02013-04-23 21:40:02 +08002900 orig_node = batadv_orig_hash_find(bat_priv, resp_src);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002901 if (!orig_node)
2902 goto out;
2903
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02002904 spin_lock_bh(&orig_node->tt_lock);
2905
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002906 change_offset = sizeof(struct batadv_tvlv_tt_vlan_data);
2907 change_offset *= ntohs(tt_data->num_vlan);
2908 change_offset += sizeof(*tt_data);
2909 tvlv_ptr += change_offset;
2910
2911 tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr;
Marek Lindner335fbe02013-04-23 21:40:02 +08002912 if (tt_data->flags & BATADV_TT_FULL_TABLE) {
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002913 batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn,
2914 resp_src, num_entries);
Sven Eckelmann96412692012-06-05 22:31:30 +02002915 } else {
Marek Lindner335fbe02013-04-23 21:40:02 +08002916 batadv_tt_update_changes(bat_priv, orig_node, num_entries,
2917 tt_data->ttvn, tt_change);
Sven Eckelmann96412692012-06-05 22:31:30 +02002918 }
Antonio Quartullia73105b2011-04-27 14:27:44 +02002919
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02002920 /* Recalculate the CRC for this orig_node and store it */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002921 batadv_tt_global_update_crc(bat_priv, orig_node);
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02002922
2923 spin_unlock_bh(&orig_node->tt_lock);
2924
Antonio Quartullia73105b2011-04-27 14:27:44 +02002925 /* Delete the tt_req_node from pending tt_requests list */
Sven Eckelmann807736f2012-07-15 22:26:51 +02002926 spin_lock_bh(&bat_priv->tt.req_list_lock);
2927 list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
Marek Lindner335fbe02013-04-23 21:40:02 +08002928 if (!batadv_compare_eth(node->addr, resp_src))
Antonio Quartullia73105b2011-04-27 14:27:44 +02002929 continue;
2930 list_del(&node->list);
2931 kfree(node);
2932 }
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02002933
Sven Eckelmann807736f2012-07-15 22:26:51 +02002934 spin_unlock_bh(&bat_priv->tt.req_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002935out:
2936 if (orig_node)
Sven Eckelmann7d211ef2012-05-12 02:09:34 +02002937 batadv_orig_node_free_ref(orig_node);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002938}
2939
Sven Eckelmann56303d32012-06-05 22:31:31 +02002940static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv)
Antonio Quartullia73105b2011-04-27 14:27:44 +02002941{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002942 struct batadv_tt_roam_node *node, *safe;
Antonio Quartullia73105b2011-04-27 14:27:44 +02002943
Sven Eckelmann807736f2012-07-15 22:26:51 +02002944 spin_lock_bh(&bat_priv->tt.roam_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +02002945
Sven Eckelmann807736f2012-07-15 22:26:51 +02002946 list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
Antonio Quartullicc47f662011-04-27 14:27:57 +02002947 list_del(&node->list);
2948 kfree(node);
2949 }
2950
Sven Eckelmann807736f2012-07-15 22:26:51 +02002951 spin_unlock_bh(&bat_priv->tt.roam_list_lock);
Antonio Quartullicc47f662011-04-27 14:27:57 +02002952}
2953
Sven Eckelmann56303d32012-06-05 22:31:31 +02002954static void batadv_tt_roam_purge(struct batadv_priv *bat_priv)
Antonio Quartullicc47f662011-04-27 14:27:57 +02002955{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002956 struct batadv_tt_roam_node *node, *safe;
Antonio Quartullicc47f662011-04-27 14:27:57 +02002957
Sven Eckelmann807736f2012-07-15 22:26:51 +02002958 spin_lock_bh(&bat_priv->tt.roam_list_lock);
2959 list_for_each_entry_safe(node, safe, &bat_priv->tt.roam_list, list) {
Sven Eckelmann42d0b042012-06-03 22:19:17 +02002960 if (!batadv_has_timed_out(node->first_time,
2961 BATADV_ROAMING_MAX_TIME))
Antonio Quartullicc47f662011-04-27 14:27:57 +02002962 continue;
2963
2964 list_del(&node->list);
2965 kfree(node);
2966 }
Sven Eckelmann807736f2012-07-15 22:26:51 +02002967 spin_unlock_bh(&bat_priv->tt.roam_list_lock);
Antonio Quartullicc47f662011-04-27 14:27:57 +02002968}
2969
2970/* This function checks whether the client already reached the
2971 * maximum number of possible roaming phases. In this case the ROAMING_ADV
2972 * will not be sent.
2973 *
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002974 * returns true if the ROAMING_ADV can be sent, false otherwise
2975 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02002976static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv,
Sven Eckelmanna5130882012-05-16 20:23:16 +02002977 uint8_t *client)
Antonio Quartullicc47f662011-04-27 14:27:57 +02002978{
Sven Eckelmann56303d32012-06-05 22:31:31 +02002979 struct batadv_tt_roam_node *tt_roam_node;
Antonio Quartullicc47f662011-04-27 14:27:57 +02002980 bool ret = false;
2981
Sven Eckelmann807736f2012-07-15 22:26:51 +02002982 spin_lock_bh(&bat_priv->tt.roam_list_lock);
Antonio Quartullicc47f662011-04-27 14:27:57 +02002983 /* The new tt_req will be issued only if I'm not waiting for a
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02002984 * reply from the same orig_node yet
2985 */
Sven Eckelmann807736f2012-07-15 22:26:51 +02002986 list_for_each_entry(tt_roam_node, &bat_priv->tt.roam_list, list) {
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02002987 if (!batadv_compare_eth(tt_roam_node->addr, client))
Antonio Quartullicc47f662011-04-27 14:27:57 +02002988 continue;
2989
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02002990 if (batadv_has_timed_out(tt_roam_node->first_time,
Sven Eckelmann42d0b042012-06-03 22:19:17 +02002991 BATADV_ROAMING_MAX_TIME))
Antonio Quartullicc47f662011-04-27 14:27:57 +02002992 continue;
2993
Sven Eckelmann3e348192012-05-16 20:23:22 +02002994 if (!batadv_atomic_dec_not_zero(&tt_roam_node->counter))
Antonio Quartullicc47f662011-04-27 14:27:57 +02002995 /* Sorry, you roamed too many times! */
2996 goto unlock;
2997 ret = true;
2998 break;
2999 }
3000
3001 if (!ret) {
3002 tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
3003 if (!tt_roam_node)
3004 goto unlock;
3005
3006 tt_roam_node->first_time = jiffies;
Sven Eckelmann42d0b042012-06-03 22:19:17 +02003007 atomic_set(&tt_roam_node->counter,
3008 BATADV_ROAMING_MAX_COUNT - 1);
Antonio Quartulli8fdd0152014-01-22 00:42:11 +01003009 ether_addr_copy(tt_roam_node->addr, client);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003010
Sven Eckelmann807736f2012-07-15 22:26:51 +02003011 list_add(&tt_roam_node->list, &bat_priv->tt.roam_list);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003012 ret = true;
3013 }
3014
3015unlock:
Sven Eckelmann807736f2012-07-15 22:26:51 +02003016 spin_unlock_bh(&bat_priv->tt.roam_list_lock);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003017 return ret;
3018}
3019
Antonio Quartullic018ad32013-06-04 12:11:39 +02003020/**
3021 * batadv_send_roam_adv - send a roaming advertisement message
3022 * @bat_priv: the bat priv with all the soft interface information
3023 * @client: mac address of the roaming client
3024 * @vid: VLAN identifier
3025 * @orig_node: message destination
3026 *
3027 * Send a ROAMING_ADV message to the node which was previously serving this
3028 * client. This is done to inform the node that from now on all traffic destined
3029 * for this particular roamed client has to be forwarded to the sender of the
3030 * roaming message.
3031 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02003032static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client,
Antonio Quartullic018ad32013-06-04 12:11:39 +02003033 unsigned short vid,
Sven Eckelmann56303d32012-06-05 22:31:31 +02003034 struct batadv_orig_node *orig_node)
Antonio Quartullicc47f662011-04-27 14:27:57 +02003035{
Sven Eckelmann56303d32012-06-05 22:31:31 +02003036 struct batadv_hard_iface *primary_if;
Marek Lindner122edaa2013-04-23 21:40:03 +08003037 struct batadv_tvlv_roam_adv tvlv_roam;
3038
3039 primary_if = batadv_primary_if_get_selected(bat_priv);
3040 if (!primary_if)
3041 goto out;
Antonio Quartullicc47f662011-04-27 14:27:57 +02003042
3043 /* before going on we have to check whether the client has
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003044 * already roamed to us too many times
3045 */
Sven Eckelmanna5130882012-05-16 20:23:16 +02003046 if (!batadv_tt_check_roam_count(bat_priv, client))
Antonio Quartullicc47f662011-04-27 14:27:57 +02003047 goto out;
3048
Sven Eckelmann39c75a52012-06-03 22:19:22 +02003049 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02003050 "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n",
3051 orig_node->orig, client, BATADV_PRINT_VID(vid));
Antonio Quartullicc47f662011-04-27 14:27:57 +02003052
Sven Eckelmannd69909d2012-06-03 22:19:20 +02003053 batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX);
Martin Hundebøllf8214862012-04-20 17:02:45 +02003054
Marek Lindner122edaa2013-04-23 21:40:03 +08003055 memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client));
Antonio Quartullic018ad32013-06-04 12:11:39 +02003056 tvlv_roam.vid = htons(vid);
Marek Lindner122edaa2013-04-23 21:40:03 +08003057
3058 batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
3059 orig_node->orig, BATADV_TVLV_ROAM, 1,
3060 &tvlv_roam, sizeof(tvlv_roam));
Antonio Quartullicc47f662011-04-27 14:27:57 +02003061
3062out:
Marek Lindner122edaa2013-04-23 21:40:03 +08003063 if (primary_if)
3064 batadv_hardif_free_ref(primary_if);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003065}
3066
Sven Eckelmanna5130882012-05-16 20:23:16 +02003067static void batadv_tt_purge(struct work_struct *work)
Antonio Quartullia73105b2011-04-27 14:27:44 +02003068{
Sven Eckelmann56303d32012-06-05 22:31:31 +02003069 struct delayed_work *delayed_work;
Sven Eckelmann807736f2012-07-15 22:26:51 +02003070 struct batadv_priv_tt *priv_tt;
Sven Eckelmann56303d32012-06-05 22:31:31 +02003071 struct batadv_priv *bat_priv;
3072
3073 delayed_work = container_of(work, struct delayed_work, work);
Sven Eckelmann807736f2012-07-15 22:26:51 +02003074 priv_tt = container_of(delayed_work, struct batadv_priv_tt, work);
3075 bat_priv = container_of(priv_tt, struct batadv_priv, tt);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003076
Marek Lindnera19d3d82013-05-27 15:33:25 +08003077 batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT);
Antonio Quartulli30cfd022012-07-05 23:38:29 +02003078 batadv_tt_global_purge(bat_priv);
Sven Eckelmanna5130882012-05-16 20:23:16 +02003079 batadv_tt_req_purge(bat_priv);
3080 batadv_tt_roam_purge(bat_priv);
Antonio Quartullia73105b2011-04-27 14:27:44 +02003081
Antonio Quartulli72414442012-12-25 13:14:37 +01003082 queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
3083 msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
Antonio Quartullia73105b2011-04-27 14:27:44 +02003084}
Antonio Quartullicc47f662011-04-27 14:27:57 +02003085
Sven Eckelmann56303d32012-06-05 22:31:31 +02003086void batadv_tt_free(struct batadv_priv *bat_priv)
Antonio Quartullicc47f662011-04-27 14:27:57 +02003087{
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003088 batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1);
3089 batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1);
3090
Sven Eckelmann807736f2012-07-15 22:26:51 +02003091 cancel_delayed_work_sync(&bat_priv->tt.work);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003092
Sven Eckelmanna5130882012-05-16 20:23:16 +02003093 batadv_tt_local_table_free(bat_priv);
3094 batadv_tt_global_table_free(bat_priv);
3095 batadv_tt_req_list_free(bat_priv);
3096 batadv_tt_changes_list_free(bat_priv);
3097 batadv_tt_roam_list_free(bat_priv);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003098
Sven Eckelmann807736f2012-07-15 22:26:51 +02003099 kfree(bat_priv->tt.last_changeset);
Antonio Quartullicc47f662011-04-27 14:27:57 +02003100}
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003101
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003102/**
3103 * batadv_tt_local_set_flags - set or unset the specified flags on the local
3104 * table and possibly count them in the TT size
3105 * @bat_priv: the bat priv with all the soft interface information
3106 * @flags: the flag to switch
3107 * @enable: whether to set or unset the flag
3108 * @count: whether to increase the TT size by the number of changed entries
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003109 */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003110static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv,
3111 uint16_t flags, bool enable, bool count)
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003112{
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003113 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
3114 struct batadv_tt_common_entry *tt_common_entry;
Antonio Quartulli697f2532011-11-07 16:47:01 +01003115 uint16_t changed_num = 0;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003116 struct hlist_head *head;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003117 uint32_t i;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003118
3119 if (!hash)
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003120 return;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003121
3122 for (i = 0; i < hash->size; i++) {
3123 head = &hash->table[i];
3124
3125 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -08003126 hlist_for_each_entry_rcu(tt_common_entry,
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003127 head, hash_entry) {
Antonio Quartulli697f2532011-11-07 16:47:01 +01003128 if (enable) {
3129 if ((tt_common_entry->flags & flags) == flags)
3130 continue;
3131 tt_common_entry->flags |= flags;
3132 } else {
3133 if (!(tt_common_entry->flags & flags))
3134 continue;
3135 tt_common_entry->flags &= ~flags;
3136 }
3137 changed_num++;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003138
3139 if (!count)
3140 continue;
3141
3142 batadv_tt_local_size_inc(bat_priv,
3143 tt_common_entry->vid);
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003144 }
3145 rcu_read_unlock();
3146 }
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003147}
3148
Sven Eckelmannacd34af2012-06-03 22:19:21 +02003149/* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */
Sven Eckelmann56303d32012-06-05 22:31:31 +02003150static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003151{
Sven Eckelmann807736f2012-07-15 22:26:51 +02003152 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
Sven Eckelmann56303d32012-06-05 22:31:31 +02003153 struct batadv_tt_common_entry *tt_common;
3154 struct batadv_tt_local_entry *tt_local;
Antonio Quartulli35df3b22014-05-08 17:13:15 +02003155 struct batadv_softif_vlan *vlan;
Sasha Levinb67bfe02013-02-27 17:06:00 -08003156 struct hlist_node *node_tmp;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003157 struct hlist_head *head;
3158 spinlock_t *list_lock; /* protects write access to the hash lists */
Antonio Quartullic90681b2011-10-05 17:05:25 +02003159 uint32_t i;
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003160
3161 if (!hash)
3162 return;
3163
3164 for (i = 0; i < hash->size; i++) {
3165 head = &hash->table[i];
3166 list_lock = &hash->list_locks[i];
3167
3168 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -08003169 hlist_for_each_entry_safe(tt_common, node_tmp, head,
Sven Eckelmannacd34af2012-06-03 22:19:21 +02003170 hash_entry) {
3171 if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING))
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003172 continue;
3173
Sven Eckelmann39c75a52012-06-03 22:19:22 +02003174 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02003175 "Deleting local tt entry (%pM, vid: %d): pending\n",
3176 tt_common->addr,
3177 BATADV_PRINT_VID(tt_common->vid));
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003178
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003179 batadv_tt_local_size_dec(bat_priv, tt_common->vid);
Sasha Levinb67bfe02013-02-27 17:06:00 -08003180 hlist_del_rcu(&tt_common->hash_entry);
Sven Eckelmann56303d32012-06-05 22:31:31 +02003181 tt_local = container_of(tt_common,
3182 struct batadv_tt_local_entry,
3183 common);
Antonio Quartulli35df3b22014-05-08 17:13:15 +02003184
3185 /* decrease the reference held for this vlan */
3186 vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid);
3187 batadv_softif_vlan_free_ref(vlan);
3188 batadv_softif_vlan_free_ref(vlan);
3189
Sven Eckelmann56303d32012-06-05 22:31:31 +02003190 batadv_tt_local_entry_free_ref(tt_local);
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003191 }
3192 spin_unlock_bh(list_lock);
3193 }
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003194}
3195
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003196/**
Marek Lindnera19d3d82013-05-27 15:33:25 +08003197 * batadv_tt_local_commit_changes_nolock - commit all pending local tt changes
3198 * which have been queued in the time since the last commit
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003199 * @bat_priv: the bat priv with all the soft interface information
Marek Lindnera19d3d82013-05-27 15:33:25 +08003200 *
3201 * Caller must hold tt->commit_lock.
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003202 */
Marek Lindnera19d3d82013-05-27 15:33:25 +08003203static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003204{
Linus Lüssingc5caf4e2014-02-15 17:47:49 +01003205 /* Update multicast addresses in local translation table */
3206 batadv_mcast_mla_update(bat_priv);
3207
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003208 if (atomic_read(&bat_priv->tt.local_changes) < 1) {
3209 if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
3210 batadv_tt_tvlv_container_update(bat_priv);
Marek Lindnera19d3d82013-05-27 15:33:25 +08003211 return;
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003212 }
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +08003213
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003214 batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +08003215
Sven Eckelmanna5130882012-05-16 20:23:16 +02003216 batadv_tt_local_purge_pending_clients(bat_priv);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003217 batadv_tt_local_update_crc(bat_priv);
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003218
3219 /* Increment the TTVN only once per OGM interval */
Sven Eckelmann807736f2012-07-15 22:26:51 +02003220 atomic_inc(&bat_priv->tt.vn);
Sven Eckelmann39c75a52012-06-03 22:19:22 +02003221 batadv_dbg(BATADV_DBG_TT, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +02003222 "Local changes committed, updating to ttvn %u\n",
Sven Eckelmann807736f2012-07-15 22:26:51 +02003223 (uint8_t)atomic_read(&bat_priv->tt.vn));
Marek Lindnerbe9aa4c2012-05-07 04:22:05 +08003224
3225 /* reset the sending counter */
Sven Eckelmann807736f2012-07-15 22:26:51 +02003226 atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003227 batadv_tt_tvlv_container_update(bat_priv);
Marek Lindnera19d3d82013-05-27 15:33:25 +08003228}
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02003229
Marek Lindnera19d3d82013-05-27 15:33:25 +08003230/**
3231 * batadv_tt_local_commit_changes - commit all pending local tt changes which
3232 * have been queued in the time since the last commit
3233 * @bat_priv: the bat priv with all the soft interface information
3234 */
3235void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
3236{
3237 spin_lock_bh(&bat_priv->tt.commit_lock);
3238 batadv_tt_local_commit_changes_nolock(bat_priv);
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02003239 spin_unlock_bh(&bat_priv->tt.commit_lock);
Antonio Quartulli058d0e22011-07-07 01:40:58 +02003240}
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003241
Sven Eckelmann56303d32012-06-05 22:31:31 +02003242bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src,
Antonio Quartullib8cbd812013-07-02 11:04:36 +02003243 uint8_t *dst, unsigned short vid)
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003244{
Sven Eckelmann56303d32012-06-05 22:31:31 +02003245 struct batadv_tt_local_entry *tt_local_entry = NULL;
3246 struct batadv_tt_global_entry *tt_global_entry = NULL;
Antonio Quartullib8cbd812013-07-02 11:04:36 +02003247 struct batadv_softif_vlan *vlan;
Marek Lindner5870adc2012-06-20 17:16:05 +02003248 bool ret = false;
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003249
Antonio Quartullib8cbd812013-07-02 11:04:36 +02003250 vlan = batadv_softif_vlan_get(bat_priv, vid);
3251 if (!vlan || !atomic_read(&vlan->ap_isolation))
Marek Lindner5870adc2012-06-20 17:16:05 +02003252 goto out;
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003253
Antonio Quartullib8cbd812013-07-02 11:04:36 +02003254 tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid);
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003255 if (!tt_local_entry)
3256 goto out;
3257
Antonio Quartullib8cbd812013-07-02 11:04:36 +02003258 tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid);
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003259 if (!tt_global_entry)
3260 goto out;
3261
Antonio Quartulli1f129fe2012-06-25 20:49:50 +00003262 if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003263 goto out;
3264
Marek Lindner5870adc2012-06-20 17:16:05 +02003265 ret = true;
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003266
3267out:
Antonio Quartullib8cbd812013-07-02 11:04:36 +02003268 if (vlan)
3269 batadv_softif_vlan_free_ref(vlan);
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003270 if (tt_global_entry)
Sven Eckelmanna5130882012-05-16 20:23:16 +02003271 batadv_tt_global_entry_free_ref(tt_global_entry);
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003272 if (tt_local_entry)
Sven Eckelmanna5130882012-05-16 20:23:16 +02003273 batadv_tt_local_entry_free_ref(tt_local_entry);
Antonio Quartulli59b699c2011-07-07 15:35:36 +02003274 return ret;
3275}
Marek Lindnera943cac2011-07-30 13:10:18 +02003276
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003277/**
3278 * batadv_tt_update_orig - update global translation table with new tt
3279 * information received via ogms
3280 * @bat_priv: the bat priv with all the soft interface information
3281 * @orig: the orig_node of the ogm
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003282 * @tt_vlan: pointer to the first tvlv VLAN entry
3283 * @tt_num_vlan: number of tvlv VLAN entries
3284 * @tt_change: pointer to the first entry in the TT buffer
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003285 * @tt_num_changes: number of tt changes inside the tt buffer
3286 * @ttvn: translation table version number of this changeset
Antonio Quartulliced72932013-04-24 16:37:51 +02003287 * @tt_crc: crc32 checksum of orig node's translation table
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003288 */
3289static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
3290 struct batadv_orig_node *orig_node,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003291 const void *tt_buff, uint16_t tt_num_vlan,
3292 struct batadv_tvlv_tt_change *tt_change,
3293 uint16_t tt_num_changes, uint8_t ttvn)
Marek Lindnera943cac2011-07-30 13:10:18 +02003294{
3295 uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003296 struct batadv_tvlv_tt_vlan_data *tt_vlan;
Marek Lindnera943cac2011-07-30 13:10:18 +02003297 bool full_table = true;
Linus Lüssinge17931d2014-02-15 17:47:50 +01003298 bool has_tt_init;
Marek Lindnera943cac2011-07-30 13:10:18 +02003299
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003300 tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff;
Linus Lüssinge17931d2014-02-15 17:47:50 +01003301 has_tt_init = orig_node->capa_initialized & BATADV_ORIG_CAPA_HAS_TT;
3302
Antonio Quartulli17071572011-11-07 16:36:40 +01003303 /* orig table not initialised AND first diff is in the OGM OR the ttvn
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003304 * increased by one -> we can apply the attached changes
3305 */
Linus Lüssinge17931d2014-02-15 17:47:50 +01003306 if ((!has_tt_init && ttvn == 1) || ttvn - orig_ttvn == 1) {
Marek Lindnera943cac2011-07-30 13:10:18 +02003307 /* the OGM could not contain the changes due to their size or
Sven Eckelmann42d0b042012-06-03 22:19:17 +02003308 * because they have already been sent BATADV_TT_OGM_APPEND_MAX
3309 * times.
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003310 * In this case send a tt request
3311 */
Marek Lindnera943cac2011-07-30 13:10:18 +02003312 if (!tt_num_changes) {
3313 full_table = false;
3314 goto request_table;
3315 }
3316
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02003317 spin_lock_bh(&orig_node->tt_lock);
3318
Sven Eckelmanna5130882012-05-16 20:23:16 +02003319 batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
Sven Eckelmann96412692012-06-05 22:31:30 +02003320 ttvn, tt_change);
Marek Lindnera943cac2011-07-30 13:10:18 +02003321
3322 /* Even if we received the precomputed crc with the OGM, we
3323 * prefer to recompute it to spot any possible inconsistency
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003324 * in the global table
3325 */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003326 batadv_tt_global_update_crc(bat_priv, orig_node);
Marek Lindnera943cac2011-07-30 13:10:18 +02003327
Antonio Quartullia70a9aa2013-07-30 22:16:24 +02003328 spin_unlock_bh(&orig_node->tt_lock);
3329
Marek Lindnera943cac2011-07-30 13:10:18 +02003330 /* The ttvn alone is not enough to guarantee consistency
3331 * because a single value could represent different states
3332 * (due to the wrap around). Thus a node has to check whether
3333 * the resulting table (after applying the changes) is still
3334 * consistent or not. E.g. a node could disconnect while its
3335 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
3336 * checking the CRC value is mandatory to detect the
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003337 * inconsistency
3338 */
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003339 if (!batadv_tt_global_check_crc(orig_node, tt_vlan,
3340 tt_num_vlan))
Marek Lindnera943cac2011-07-30 13:10:18 +02003341 goto request_table;
Marek Lindnera943cac2011-07-30 13:10:18 +02003342 } else {
3343 /* if we missed more than one change or our tables are not
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +02003344 * in sync anymore -> request fresh tt data
3345 */
Linus Lüssinge17931d2014-02-15 17:47:50 +01003346 if (!has_tt_init || ttvn != orig_ttvn ||
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003347 !batadv_tt_global_check_crc(orig_node, tt_vlan,
3348 tt_num_vlan)) {
Marek Lindnera943cac2011-07-30 13:10:18 +02003349request_table:
Sven Eckelmann39c75a52012-06-03 22:19:22 +02003350 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003351 "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n",
3352 orig_node->orig, ttvn, orig_ttvn,
3353 tt_num_changes);
Sven Eckelmanna5130882012-05-16 20:23:16 +02003354 batadv_send_tt_request(bat_priv, orig_node, ttvn,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003355 tt_vlan, tt_num_vlan,
3356 full_table);
Marek Lindnera943cac2011-07-30 13:10:18 +02003357 return;
3358 }
3359 }
3360}
Antonio Quartulli3275e7c2012-03-16 18:03:28 +01003361
Antonio Quartullic018ad32013-06-04 12:11:39 +02003362/**
3363 * batadv_tt_global_client_is_roaming - check if a client is marked as roaming
3364 * @bat_priv: the bat priv with all the soft interface information
3365 * @addr: the mac address of the client to check
3366 * @vid: VLAN identifier
3367 *
3368 * Returns true if we know that the client has moved from its old originator
3369 * to another one. This entry is still kept for consistency purposes and will be
3370 * deleted later by a DEL or because of timeout
Antonio Quartulli3275e7c2012-03-16 18:03:28 +01003371 */
Sven Eckelmann56303d32012-06-05 22:31:31 +02003372bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
Antonio Quartullic018ad32013-06-04 12:11:39 +02003373 uint8_t *addr, unsigned short vid)
Antonio Quartulli3275e7c2012-03-16 18:03:28 +01003374{
Sven Eckelmann56303d32012-06-05 22:31:31 +02003375 struct batadv_tt_global_entry *tt_global_entry;
Antonio Quartulli3275e7c2012-03-16 18:03:28 +01003376 bool ret = false;
3377
Antonio Quartullic018ad32013-06-04 12:11:39 +02003378 tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
Antonio Quartulli3275e7c2012-03-16 18:03:28 +01003379 if (!tt_global_entry)
3380 goto out;
3381
Antonio Quartullic1d07432013-01-15 22:17:19 +10003382 ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
Sven Eckelmanna5130882012-05-16 20:23:16 +02003383 batadv_tt_global_entry_free_ref(tt_global_entry);
Antonio Quartulli3275e7c2012-03-16 18:03:28 +01003384out:
3385 return ret;
3386}
Antonio Quartulli30cfd022012-07-05 23:38:29 +02003387
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02003388/**
3389 * batadv_tt_local_client_is_roaming - tells whether the client is roaming
3390 * @bat_priv: the bat priv with all the soft interface information
Antonio Quartullic018ad32013-06-04 12:11:39 +02003391 * @addr: the mac address of the local client to query
3392 * @vid: VLAN identifier
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02003393 *
3394 * Returns true if the local client is known to be roaming (it is not served by
3395 * this node anymore) or not. If yes, the client is still present in the table
3396 * to keep the latter consistent with the node TTVN
3397 */
3398bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
Antonio Quartullic018ad32013-06-04 12:11:39 +02003399 uint8_t *addr, unsigned short vid)
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02003400{
3401 struct batadv_tt_local_entry *tt_local_entry;
3402 bool ret = false;
3403
Antonio Quartullic018ad32013-06-04 12:11:39 +02003404 tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02003405 if (!tt_local_entry)
3406 goto out;
3407
3408 ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM;
3409 batadv_tt_local_entry_free_ref(tt_local_entry);
3410out:
3411 return ret;
Antonio Quartulli7c1fd912012-09-23 22:38:34 +02003412}
3413
Antonio Quartulli30cfd022012-07-05 23:38:29 +02003414bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
3415 struct batadv_orig_node *orig_node,
Antonio Quartullic018ad32013-06-04 12:11:39 +02003416 const unsigned char *addr,
Antonio Quartulli16052782013-06-04 12:11:41 +02003417 unsigned short vid)
Antonio Quartulli30cfd022012-07-05 23:38:29 +02003418{
3419 bool ret = false;
3420
Antonio Quartulli16052782013-06-04 12:11:41 +02003421 if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid,
Antonio Quartulli30cfd022012-07-05 23:38:29 +02003422 BATADV_TT_CLIENT_TEMP,
3423 atomic_read(&orig_node->last_ttvn)))
3424 goto out;
3425
3426 batadv_dbg(BATADV_DBG_TT, bat_priv,
Antonio Quartulli16052782013-06-04 12:11:41 +02003427 "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n",
3428 addr, BATADV_PRINT_VID(vid), orig_node->orig);
Antonio Quartulli30cfd022012-07-05 23:38:29 +02003429 ret = true;
3430out:
3431 return ret;
3432}
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003433
3434/**
Marek Lindnera19d3d82013-05-27 15:33:25 +08003435 * batadv_tt_local_resize_to_mtu - resize the local translation table fit the
3436 * maximum packet size that can be transported through the mesh
3437 * @soft_iface: netdev struct of the mesh interface
3438 *
3439 * Remove entries older than 'timeout' and half timeout if more entries need
3440 * to be removed.
3441 */
3442void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface)
3443{
3444 struct batadv_priv *bat_priv = netdev_priv(soft_iface);
3445 int packet_size_max = atomic_read(&bat_priv->packet_size_max);
3446 int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2;
3447 bool reduced = false;
3448
3449 spin_lock_bh(&bat_priv->tt.commit_lock);
3450
3451 while (true) {
3452 table_size = batadv_tt_local_table_transmit_size(bat_priv);
3453 if (packet_size_max >= table_size)
3454 break;
3455
3456 batadv_tt_local_purge(bat_priv, timeout);
3457 batadv_tt_local_purge_pending_clients(bat_priv);
3458
3459 timeout /= 2;
3460 reduced = true;
3461 net_ratelimited_function(batadv_info, soft_iface,
3462 "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n",
3463 packet_size_max);
3464 }
3465
3466 /* commit these changes immediately, to avoid synchronization problem
3467 * with the TTVN
3468 */
3469 if (reduced)
3470 batadv_tt_local_commit_changes_nolock(bat_priv);
3471
3472 spin_unlock_bh(&bat_priv->tt.commit_lock);
3473}
3474
3475/**
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003476 * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container
3477 * @bat_priv: the bat priv with all the soft interface information
3478 * @orig: the orig_node of the ogm
3479 * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
3480 * @tvlv_value: tvlv buffer containing the gateway data
3481 * @tvlv_value_len: tvlv buffer length
3482 */
3483static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
3484 struct batadv_orig_node *orig,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003485 uint8_t flags, void *tvlv_value,
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003486 uint16_t tvlv_value_len)
3487{
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003488 struct batadv_tvlv_tt_vlan_data *tt_vlan;
3489 struct batadv_tvlv_tt_change *tt_change;
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003490 struct batadv_tvlv_tt_data *tt_data;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003491 uint16_t num_entries, num_vlan;
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003492
3493 if (tvlv_value_len < sizeof(*tt_data))
3494 return;
3495
3496 tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
3497 tvlv_value_len -= sizeof(*tt_data);
3498
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003499 num_vlan = ntohs(tt_data->num_vlan);
3500
3501 if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan)
3502 return;
3503
3504 tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1);
3505 tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan);
3506 tvlv_value_len -= sizeof(*tt_vlan) * num_vlan;
3507
Antonio Quartulli298e6e62013-05-28 13:14:27 +02003508 num_entries = batadv_tt_entries(tvlv_value_len);
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003509
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003510 batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change,
3511 num_entries, tt_data->ttvn);
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003512}
3513
3514/**
Marek Lindner335fbe02013-04-23 21:40:02 +08003515 * batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv
3516 * container
3517 * @bat_priv: the bat priv with all the soft interface information
3518 * @src: mac address of tt tvlv sender
3519 * @dst: mac address of tt tvlv recipient
3520 * @tvlv_value: tvlv buffer containing the tt data
3521 * @tvlv_value_len: tvlv buffer length
3522 *
3523 * Returns NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS
3524 * otherwise.
3525 */
3526static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
3527 uint8_t *src, uint8_t *dst,
3528 void *tvlv_value,
3529 uint16_t tvlv_value_len)
3530{
3531 struct batadv_tvlv_tt_data *tt_data;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003532 uint16_t tt_vlan_len, tt_num_entries;
Marek Lindner335fbe02013-04-23 21:40:02 +08003533 char tt_flag;
3534 bool ret;
3535
3536 if (tvlv_value_len < sizeof(*tt_data))
3537 return NET_RX_SUCCESS;
3538
3539 tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
3540 tvlv_value_len -= sizeof(*tt_data);
3541
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003542 tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data);
3543 tt_vlan_len *= ntohs(tt_data->num_vlan);
3544
3545 if (tvlv_value_len < tt_vlan_len)
3546 return NET_RX_SUCCESS;
3547
3548 tvlv_value_len -= tt_vlan_len;
3549 tt_num_entries = batadv_tt_entries(tvlv_value_len);
Marek Lindner335fbe02013-04-23 21:40:02 +08003550
3551 switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) {
3552 case BATADV_TT_REQUEST:
3553 batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX);
3554
3555 /* If this node cannot provide a TT response the tt_request is
3556 * forwarded
3557 */
3558 ret = batadv_send_tt_response(bat_priv, tt_data, src, dst);
3559 if (!ret) {
3560 if (tt_data->flags & BATADV_TT_FULL_TABLE)
3561 tt_flag = 'F';
3562 else
3563 tt_flag = '.';
3564
3565 batadv_dbg(BATADV_DBG_TT, bat_priv,
3566 "Routing TT_REQUEST to %pM [%c]\n",
3567 dst, tt_flag);
3568 /* tvlv API will re-route the packet */
3569 return NET_RX_DROP;
3570 }
3571 break;
3572 case BATADV_TT_RESPONSE:
3573 batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX);
3574
3575 if (batadv_is_my_mac(bat_priv, dst)) {
3576 batadv_handle_tt_response(bat_priv, tt_data,
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +02003577 src, tt_num_entries);
Marek Lindner335fbe02013-04-23 21:40:02 +08003578 return NET_RX_SUCCESS;
3579 }
3580
3581 if (tt_data->flags & BATADV_TT_FULL_TABLE)
3582 tt_flag = 'F';
3583 else
3584 tt_flag = '.';
3585
3586 batadv_dbg(BATADV_DBG_TT, bat_priv,
3587 "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag);
3588
3589 /* tvlv API will re-route the packet */
3590 return NET_RX_DROP;
3591 }
3592
3593 return NET_RX_SUCCESS;
3594}
3595
3596/**
Marek Lindner122edaa2013-04-23 21:40:03 +08003597 * batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container
3598 * @bat_priv: the bat priv with all the soft interface information
3599 * @src: mac address of tt tvlv sender
3600 * @dst: mac address of tt tvlv recipient
3601 * @tvlv_value: tvlv buffer containing the tt data
3602 * @tvlv_value_len: tvlv buffer length
3603 *
3604 * Returns NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS
3605 * otherwise.
3606 */
3607static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
3608 uint8_t *src, uint8_t *dst,
3609 void *tvlv_value,
3610 uint16_t tvlv_value_len)
3611{
3612 struct batadv_tvlv_roam_adv *roaming_adv;
3613 struct batadv_orig_node *orig_node = NULL;
3614
3615 /* If this node is not the intended recipient of the
3616 * roaming advertisement the packet is forwarded
3617 * (the tvlv API will re-route the packet).
3618 */
3619 if (!batadv_is_my_mac(bat_priv, dst))
3620 return NET_RX_DROP;
3621
Marek Lindner122edaa2013-04-23 21:40:03 +08003622 if (tvlv_value_len < sizeof(*roaming_adv))
3623 goto out;
3624
3625 orig_node = batadv_orig_hash_find(bat_priv, src);
3626 if (!orig_node)
3627 goto out;
3628
3629 batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX);
3630 roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value;
3631
3632 batadv_dbg(BATADV_DBG_TT, bat_priv,
3633 "Received ROAMING_ADV from %pM (client %pM)\n",
3634 src, roaming_adv->client);
3635
3636 batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client,
Antonio Quartullic018ad32013-06-04 12:11:39 +02003637 ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM,
Marek Lindner122edaa2013-04-23 21:40:03 +08003638 atomic_read(&orig_node->last_ttvn) + 1);
3639
3640out:
3641 if (orig_node)
3642 batadv_orig_node_free_ref(orig_node);
3643 return NET_RX_SUCCESS;
3644}
3645
3646/**
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003647 * batadv_tt_init - initialise the translation table internals
3648 * @bat_priv: the bat priv with all the soft interface information
3649 *
3650 * Return 0 on success or negative error number in case of failure.
3651 */
3652int batadv_tt_init(struct batadv_priv *bat_priv)
3653{
3654 int ret;
3655
Antonio Quartulli0eb015682013-10-13 02:50:20 +02003656 /* synchronized flags must be remote */
3657 BUILD_BUG_ON(!(BATADV_TT_SYNC_MASK & BATADV_TT_REMOTE_MASK));
3658
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003659 ret = batadv_tt_local_init(bat_priv);
3660 if (ret < 0)
3661 return ret;
3662
3663 ret = batadv_tt_global_init(bat_priv);
3664 if (ret < 0)
3665 return ret;
3666
3667 batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1,
Marek Lindner335fbe02013-04-23 21:40:02 +08003668 batadv_tt_tvlv_unicast_handler_v1,
3669 BATADV_TVLV_TT, 1, BATADV_NO_FLAGS);
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003670
Marek Lindner122edaa2013-04-23 21:40:03 +08003671 batadv_tvlv_handler_register(bat_priv, NULL,
3672 batadv_roam_tvlv_unicast_handler_v1,
3673 BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS);
3674
Marek Lindnere1bf0c12013-04-23 21:40:01 +08003675 INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge);
3676 queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
3677 msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
3678
3679 return 1;
3680}
Antonio Quartulli42cb0be2013-11-16 12:03:52 +01003681
3682/**
3683 * batadv_tt_global_is_isolated - check if a client is marked as isolated
3684 * @bat_priv: the bat priv with all the soft interface information
3685 * @addr: the mac address of the client
3686 * @vid: the identifier of the VLAN where this client is connected
3687 *
3688 * Returns true if the client is marked with the TT_CLIENT_ISOLA flag, false
3689 * otherwise
3690 */
3691bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
3692 const uint8_t *addr, unsigned short vid)
3693{
3694 struct batadv_tt_global_entry *tt;
3695 bool ret;
3696
3697 tt = batadv_tt_global_hash_find(bat_priv, addr, vid);
3698 if (!tt)
3699 return false;
3700
3701 ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA;
3702
3703 batadv_tt_global_entry_free_ref(tt);
3704
3705 return ret;
3706}