aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorAntonio Quartulli <ordex@autistici.org>2011-04-27 08:27:44 -0400
committerSven Eckelmann <sven@narfation.org>2011-06-20 05:37:24 -0400
commita73105b8d4c765d9ebfb664d0a66802127d8e4c7 (patch)
treeb4b11a4050109d8f042c7ac87a5a6d6d91b5d1d2 /net
parent3b27ffb00fbe9d9189715ea13ce8712e2f0cb0c5 (diff)
batman-adv: improved client announcement mechanism
The client announcement mechanism informs every mesh node in the network of any connected non-mesh client, in order to find the path towards that client from any given point in the mesh. The old implementation was based on the simple idea of appending a data buffer to each OGM containing all the client MAC addresses the node is serving. All other nodes can populate their global translation tables (table which links client MAC addresses to node addresses) using this MAC address buffer and linking it to the node's address contained in the OGM. A node that wants to contact a client has to lookup the node the client is connected to and its address in the global translation table. It is easy to understand that this implementation suffers from several issues: - big overhead (each and every OGM contains the entire list of connected clients) - high latencies for client route updates due to long OGM trip time and OGM losses The new implementation addresses these issues by appending client changes (new client joined or a client left) to the OGM instead of filling it with all the client addresses each time. In this way nodes can modify their global tables by means of "updates", thus reducing the overhead within the OGMs. To keep the entire network in sync each node maintains a translation table version number (ttvn) and a translation table checksum. These values are spread with the OGM to allow all the network participants to determine whether or not they need to update their translation table information. When a translation table lookup is performed in order to send a packet to a client attached to another node, the destination's ttvn is added to the payload packet. Forwarding nodes can compare the packet's ttvn with their destination's ttvn (this node could have a fresher information than the source) and re-route the packet if necessary. This greatly reduces the packet loss of clients roaming from one AP to the next. Signed-off-by: Antonio Quartulli <ordex@autistici.org> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Sven Eckelmann <sven@narfation.org>
Diffstat (limited to 'net')
-rw-r--r--net/batman-adv/Kconfig1
-rw-r--r--net/batman-adv/aggregation.c23
-rw-r--r--net/batman-adv/aggregation.h6
-rw-r--r--net/batman-adv/bat_sysfs.c2
-rw-r--r--net/batman-adv/hard-interface.c13
-rw-r--r--net/batman-adv/main.c13
-rw-r--r--net/batman-adv/main.h7
-rw-r--r--net/batman-adv/originator.c8
-rw-r--r--net/batman-adv/packet.h59
-rw-r--r--net/batman-adv/routing.c252
-rw-r--r--net/batman-adv/routing.h6
-rw-r--r--net/batman-adv/send.c87
-rw-r--r--net/batman-adv/send.h2
-rw-r--r--net/batman-adv/soft-interface.c11
-rw-r--r--net/batman-adv/translation-table.c1126
-rw-r--r--net/batman-adv/translation-table.h34
-rw-r--r--net/batman-adv/types.h33
-rw-r--r--net/batman-adv/unicast.c3
18 files changed, 1381 insertions, 305 deletions
diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig
index 6c051ad833eb..2b68d068eaf3 100644
--- a/net/batman-adv/Kconfig
+++ b/net/batman-adv/Kconfig
@@ -5,6 +5,7 @@
5config BATMAN_ADV 5config BATMAN_ADV
6 tristate "B.A.T.M.A.N. Advanced Meshing Protocol" 6 tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
7 depends on NET 7 depends on NET
8 select CRC16
8 default n 9 default n
9 ---help--- 10 ---help---
10 11
diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c
index 29c67405347b..c583e049f421 100644
--- a/net/batman-adv/aggregation.c
+++ b/net/batman-adv/aggregation.c
@@ -20,17 +20,12 @@
20 */ 20 */
21 21
22#include "main.h" 22#include "main.h"
23#include "translation-table.h"
23#include "aggregation.h" 24#include "aggregation.h"
24#include "send.h" 25#include "send.h"
25#include "routing.h" 26#include "routing.h"
26#include "hard-interface.h" 27#include "hard-interface.h"
27 28
28/* calculate the size of the tt information for a given packet */
29static int tt_len(const struct batman_packet *batman_packet)
30{
31 return batman_packet->num_tt * ETH_ALEN;
32}
33
34/* return true if new_packet can be aggregated with forw_packet */ 29/* return true if new_packet can be aggregated with forw_packet */
35static bool can_aggregate_with(const struct batman_packet *new_batman_packet, 30static bool can_aggregate_with(const struct batman_packet *new_batman_packet,
36 int packet_len, 31 int packet_len,
@@ -264,18 +259,20 @@ void receive_aggr_bat_packet(const struct ethhdr *ethhdr,
264 batman_packet = (struct batman_packet *)packet_buff; 259 batman_packet = (struct batman_packet *)packet_buff;
265 260
266 do { 261 do {
267 /* network to host order for our 32bit seqno, and the 262 /* network to host order for our 32bit seqno and the
268 orig_interval. */ 263 orig_interval */
269 batman_packet->seqno = ntohl(batman_packet->seqno); 264 batman_packet->seqno = ntohl(batman_packet->seqno);
265 batman_packet->tt_crc = ntohs(batman_packet->tt_crc);
270 266
271 tt_buff = packet_buff + buff_pos + BAT_PACKET_LEN; 267 tt_buff = packet_buff + buff_pos + BAT_PACKET_LEN;
272 receive_bat_packet(ethhdr, batman_packet,
273 tt_buff, tt_len(batman_packet),
274 if_incoming);
275 268
276 buff_pos += BAT_PACKET_LEN + tt_len(batman_packet); 269 receive_bat_packet(ethhdr, batman_packet, tt_buff, if_incoming);
270
271 buff_pos += BAT_PACKET_LEN +
272 tt_len(batman_packet->tt_num_changes);
273
277 batman_packet = (struct batman_packet *) 274 batman_packet = (struct batman_packet *)
278 (packet_buff + buff_pos); 275 (packet_buff + buff_pos);
279 } while (aggregated_packet(buff_pos, packet_len, 276 } while (aggregated_packet(buff_pos, packet_len,
280 batman_packet->num_tt)); 277 batman_packet->tt_num_changes));
281} 278}
diff --git a/net/batman-adv/aggregation.h b/net/batman-adv/aggregation.h
index 0547fd8ea3b9..216337bb841f 100644
--- a/net/batman-adv/aggregation.h
+++ b/net/batman-adv/aggregation.h
@@ -25,9 +25,11 @@
25#include "main.h" 25#include "main.h"
26 26
27/* is there another aggregated packet here? */ 27/* is there another aggregated packet here? */
28static inline int aggregated_packet(int buff_pos, int packet_len, int num_tt) 28static inline int aggregated_packet(int buff_pos, int packet_len,
29 int tt_num_changes)
29{ 30{
30 int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_tt * ETH_ALEN); 31 int next_buff_pos = buff_pos + BAT_PACKET_LEN + (tt_num_changes *
32 sizeof(struct tt_change));
31 33
32 return (next_buff_pos <= packet_len) && 34 return (next_buff_pos <= packet_len) &&
33 (next_buff_pos <= MAX_AGGREGATION_BYTES); 35 (next_buff_pos <= MAX_AGGREGATION_BYTES);
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c
index 924d5773da21..63738ec10511 100644
--- a/net/batman-adv/bat_sysfs.c
+++ b/net/batman-adv/bat_sysfs.c
@@ -375,7 +375,7 @@ BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE,
375static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth, 375static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth,
376 store_gw_bwidth); 376 store_gw_bwidth);
377#ifdef CONFIG_BATMAN_ADV_DEBUG 377#ifdef CONFIG_BATMAN_ADV_DEBUG
378BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL); 378BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 7, NULL);
379#endif 379#endif
380 380
381static struct bat_attribute *mesh_attrs[] = { 381static struct bat_attribute *mesh_attrs[] = {
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index b55e8616fc1e..d40426cc5e29 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -152,12 +152,6 @@ static void primary_if_select(struct bat_priv *bat_priv,
152 batman_packet->ttl = TTL; 152 batman_packet->ttl = TTL;
153 153
154 primary_if_update_addr(bat_priv); 154 primary_if_update_addr(bat_priv);
155
156 /***
157 * hacky trick to make sure that we send the TT information via
158 * our new primary interface
159 */
160 atomic_set(&bat_priv->tt_local_changed, 1);
161} 155}
162 156
163static bool hardif_is_iface_up(const struct hard_iface *hard_iface) 157static bool hardif_is_iface_up(const struct hard_iface *hard_iface)
@@ -340,7 +334,8 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
340 batman_packet->flags = NO_FLAGS; 334 batman_packet->flags = NO_FLAGS;
341 batman_packet->ttl = 2; 335 batman_packet->ttl = 2;
342 batman_packet->tq = TQ_MAX_VALUE; 336 batman_packet->tq = TQ_MAX_VALUE;
343 batman_packet->num_tt = 0; 337 batman_packet->tt_num_changes = 0;
338 batman_packet->ttvn = 0;
344 339
345 hard_iface->if_num = bat_priv->num_ifaces; 340 hard_iface->if_num = bat_priv->num_ifaces;
346 bat_priv->num_ifaces++; 341 bat_priv->num_ifaces++;
@@ -659,6 +654,10 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
659 case BAT_VIS: 654 case BAT_VIS:
660 ret = recv_vis_packet(skb, hard_iface); 655 ret = recv_vis_packet(skb, hard_iface);
661 break; 656 break;
657 /* Translation table query (request or response) */
658 case BAT_TT_QUERY:
659 ret = recv_tt_query(skb, hard_iface);
660 break;
662 default: 661 default:
663 ret = NET_RX_DROP; 662 ret = NET_RX_DROP;
664 } 663 }
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 2d6445e171d6..49a5e64b2d4f 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -86,6 +86,9 @@ int mesh_init(struct net_device *soft_iface)
86 spin_lock_init(&bat_priv->forw_bcast_list_lock); 86 spin_lock_init(&bat_priv->forw_bcast_list_lock);
87 spin_lock_init(&bat_priv->tt_lhash_lock); 87 spin_lock_init(&bat_priv->tt_lhash_lock);
88 spin_lock_init(&bat_priv->tt_ghash_lock); 88 spin_lock_init(&bat_priv->tt_ghash_lock);
89 spin_lock_init(&bat_priv->tt_changes_list_lock);
90 spin_lock_init(&bat_priv->tt_req_list_lock);
91 spin_lock_init(&bat_priv->tt_buff_lock);
89 spin_lock_init(&bat_priv->gw_list_lock); 92 spin_lock_init(&bat_priv->gw_list_lock);
90 spin_lock_init(&bat_priv->vis_hash_lock); 93 spin_lock_init(&bat_priv->vis_hash_lock);
91 spin_lock_init(&bat_priv->vis_list_lock); 94 spin_lock_init(&bat_priv->vis_list_lock);
@@ -96,14 +99,13 @@ int mesh_init(struct net_device *soft_iface)
96 INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); 99 INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
97 INIT_HLIST_HEAD(&bat_priv->gw_list); 100 INIT_HLIST_HEAD(&bat_priv->gw_list);
98 INIT_HLIST_HEAD(&bat_priv->softif_neigh_vids); 101 INIT_HLIST_HEAD(&bat_priv->softif_neigh_vids);
102 INIT_LIST_HEAD(&bat_priv->tt_changes_list);
103 INIT_LIST_HEAD(&bat_priv->tt_req_list);
99 104
100 if (originator_init(bat_priv) < 1) 105 if (originator_init(bat_priv) < 1)
101 goto err; 106 goto err;
102 107
103 if (tt_local_init(bat_priv) < 1) 108 if (tt_init(bat_priv) < 1)
104 goto err;
105
106 if (tt_global_init(bat_priv) < 1)
107 goto err; 109 goto err;
108 110
109 tt_local_add(soft_iface, soft_iface->dev_addr); 111 tt_local_add(soft_iface, soft_iface->dev_addr);
@@ -137,8 +139,7 @@ void mesh_free(struct net_device *soft_iface)
137 gw_node_purge(bat_priv); 139 gw_node_purge(bat_priv);
138 originator_free(bat_priv); 140 originator_free(bat_priv);
139 141
140 tt_local_free(bat_priv); 142 tt_free(bat_priv);
141 tt_global_free(bat_priv);
142 143
143 softif_neigh_purge(bat_priv); 144 softif_neigh_purge(bat_priv);
144 145
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index 714a2414d913..6f53a1de778c 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -46,11 +46,15 @@
46/* sliding packet range of received originator messages in squence numbers 46/* sliding packet range of received originator messages in squence numbers
47 * (should be a multiple of our word size) */ 47 * (should be a multiple of our word size) */
48#define TQ_LOCAL_WINDOW_SIZE 64 48#define TQ_LOCAL_WINDOW_SIZE 64
49#define TT_REQUEST_TIMEOUT 3 /* seconds we have to keep pending tt_req */
50
49#define TQ_GLOBAL_WINDOW_SIZE 5 51#define TQ_GLOBAL_WINDOW_SIZE 5
50#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1 52#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1
51#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1 53#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1
52#define TQ_TOTAL_BIDRECT_LIMIT 1 54#define TQ_TOTAL_BIDRECT_LIMIT 1
53 55
56#define TT_OGM_APPEND_MAX 3 /* number of OGMs sent with the last tt diff */
57
54#define NO_FLAGS 0 58#define NO_FLAGS 0
55 59
56#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE) 60#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
@@ -96,7 +100,8 @@ enum mesh_state {
96enum dbg_level { 100enum dbg_level {
97 DBG_BATMAN = 1 << 0, 101 DBG_BATMAN = 1 << 0,
98 DBG_ROUTES = 1 << 1, /* route added / changed / deleted */ 102 DBG_ROUTES = 1 << 1, /* route added / changed / deleted */
99 DBG_ALL = 3 103 DBG_TT = 1 << 2, /* translation table operations */
104 DBG_ALL = 7
100}; 105};
101 106
102 107
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 991a6e72a9d7..25e7e50eef25 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -145,6 +145,7 @@ static void orig_node_free_rcu(struct rcu_head *rcu)
145 tt_global_del_orig(orig_node->bat_priv, orig_node, 145 tt_global_del_orig(orig_node->bat_priv, orig_node,
146 "originator timed out"); 146 "originator timed out");
147 147
148 kfree(orig_node->tt_buff);
148 kfree(orig_node->bcast_own); 149 kfree(orig_node->bcast_own);
149 kfree(orig_node->bcast_own_sum); 150 kfree(orig_node->bcast_own_sum);
150 kfree(orig_node); 151 kfree(orig_node);
@@ -213,6 +214,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
213 spin_lock_init(&orig_node->ogm_cnt_lock); 214 spin_lock_init(&orig_node->ogm_cnt_lock);
214 spin_lock_init(&orig_node->bcast_seqno_lock); 215 spin_lock_init(&orig_node->bcast_seqno_lock);
215 spin_lock_init(&orig_node->neigh_list_lock); 216 spin_lock_init(&orig_node->neigh_list_lock);
217 spin_lock_init(&orig_node->tt_buff_lock);
216 218
217 /* extra reference for return */ 219 /* extra reference for return */
218 atomic_set(&orig_node->refcount, 2); 220 atomic_set(&orig_node->refcount, 2);
@@ -221,6 +223,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
221 memcpy(orig_node->orig, addr, ETH_ALEN); 223 memcpy(orig_node->orig, addr, ETH_ALEN);
222 orig_node->router = NULL; 224 orig_node->router = NULL;
223 orig_node->tt_buff = NULL; 225 orig_node->tt_buff = NULL;
226 orig_node->tt_buff_len = 0;
227 atomic_set(&orig_node->tt_size, 0);
224 orig_node->bcast_seqno_reset = jiffies - 1 228 orig_node->bcast_seqno_reset = jiffies - 1
225 - msecs_to_jiffies(RESET_PROTECTION_MS); 229 - msecs_to_jiffies(RESET_PROTECTION_MS);
226 orig_node->batman_seqno_reset = jiffies - 1 230 orig_node->batman_seqno_reset = jiffies - 1
@@ -330,9 +334,7 @@ static bool purge_orig_node(struct bat_priv *bat_priv,
330 if (purge_orig_neighbors(bat_priv, orig_node, 334 if (purge_orig_neighbors(bat_priv, orig_node,
331 &best_neigh_node)) { 335 &best_neigh_node)) {
332 update_routes(bat_priv, orig_node, 336 update_routes(bat_priv, orig_node,
333 best_neigh_node, 337 best_neigh_node);
334 orig_node->tt_buff,
335 orig_node->tt_buff_len);
336 } 338 }
337 } 339 }
338 340
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
index 6ddbfd830784..407dd2e84aff 100644
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@ -30,7 +30,8 @@ enum bat_packettype {
30 BAT_UNICAST = 0x03, 30 BAT_UNICAST = 0x03,
31 BAT_BCAST = 0x04, 31 BAT_BCAST = 0x04,
32 BAT_VIS = 0x05, 32 BAT_VIS = 0x05,
33 BAT_UNICAST_FRAG = 0x06 33 BAT_UNICAST_FRAG = 0x06,
34 BAT_TT_QUERY = 0x07
34}; 35};
35 36
36/* this file is included by batctl which needs these defines */ 37/* this file is included by batctl which needs these defines */
@@ -63,6 +64,25 @@ enum unicast_frag_flags {
63 UNI_FRAG_LARGETAIL = 1 << 1 64 UNI_FRAG_LARGETAIL = 1 << 1
64}; 65};
65 66
67/* TT_QUERY subtypes */
68#define TT_QUERY_TYPE_MASK 0x3
69
70enum tt_query_packettype {
71 TT_REQUEST = 0,
72 TT_RESPONSE = 1
73};
74
75/* TT_QUERY flags */
76enum tt_query_flags {
77 TT_FULL_TABLE = 1 << 2
78};
79
80/* TT_CHANGE flags */
81enum tt_change_flags {
82 TT_CHANGE_DEL = 0x01,
83 TT_CLIENT_ROAM = 0x02
84};
85
66struct batman_packet { 86struct batman_packet {
67 uint8_t packet_type; 87 uint8_t packet_type;
68 uint8_t version; /* batman version field */ 88 uint8_t version; /* batman version field */
@@ -73,8 +93,9 @@ struct batman_packet {
73 uint8_t prev_sender[6]; 93 uint8_t prev_sender[6];
74 uint8_t gw_flags; /* flags related to gateway class */ 94 uint8_t gw_flags; /* flags related to gateway class */
75 uint8_t tq; 95 uint8_t tq;
76 uint8_t num_tt; 96 uint8_t tt_num_changes;
77 uint8_t reserved; 97 uint8_t ttvn; /* translation table version number */
98 uint16_t tt_crc;
78} __packed; 99} __packed;
79 100
80#define BAT_PACKET_LEN sizeof(struct batman_packet) 101#define BAT_PACKET_LEN sizeof(struct batman_packet)
@@ -112,7 +133,7 @@ struct unicast_packet {
112 uint8_t packet_type; 133 uint8_t packet_type;
113 uint8_t version; /* batman version field */ 134 uint8_t version; /* batman version field */
114 uint8_t ttl; 135 uint8_t ttl;
115 uint8_t reserved; 136 uint8_t ttvn; /* destination translation table version number */
116 uint8_t dest[6]; 137 uint8_t dest[6];
117} __packed; 138} __packed;
118 139
@@ -120,7 +141,7 @@ struct unicast_frag_packet {
120 uint8_t packet_type; 141 uint8_t packet_type;
121 uint8_t version; /* batman version field */ 142 uint8_t version; /* batman version field */
122 uint8_t ttl; 143 uint8_t ttl;
123 uint8_t reserved; 144 uint8_t ttvn; /* destination translation table version number */
124 uint8_t dest[6]; 145 uint8_t dest[6];
125 uint8_t flags; 146 uint8_t flags;
126 uint8_t align; 147 uint8_t align;
@@ -150,4 +171,32 @@ struct vis_packet {
150 uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */ 171 uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
151} __packed; 172} __packed;
152 173
174struct tt_query_packet {
175 uint8_t packet_type;
176 uint8_t version; /* batman version field */
177 uint8_t ttl;
178 /* the flag field is a combination of:
179 * - TT_REQUEST or TT_RESPONSE
180 * - TT_FULL_TABLE */
181 uint8_t flags;
182 uint8_t dst[ETH_ALEN];
183 uint8_t src[ETH_ALEN];
184 /* the ttvn field is:
185 * if TT_REQUEST: ttvn that triggered the
186 * request
187 * if TT_RESPONSE: new ttvn for the src
188 * orig_node */
189 uint8_t ttvn;
190 /* tt_data field is:
191 * if TT_REQUEST: crc associated with the
192 * ttvn
193 * if TT_RESPONSE: table_size */
194 uint16_t tt_data;
195} __packed;
196
197struct tt_change {
198 uint8_t flags;
199 uint8_t addr[ETH_ALEN];
200} __packed;
201
153#endif /* _NET_BATMAN_ADV_PACKET_H_ */ 202#endif /* _NET_BATMAN_ADV_PACKET_H_ */
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index eb6fb7d2d368..8b0f8330b06d 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -64,27 +64,56 @@ void slide_own_bcast_window(struct hard_iface *hard_iface)
64 } 64 }
65} 65}
66 66
67static void update_TT(struct bat_priv *bat_priv, struct orig_node *orig_node, 67static void update_transtable(struct bat_priv *bat_priv,
68 const unsigned char *tt_buff, int tt_buff_len) 68 struct orig_node *orig_node,
69 const unsigned char *tt_buff,
70 uint8_t tt_num_changes, uint8_t ttvn,
71 uint16_t tt_crc)
69{ 72{
70 if ((tt_buff_len != orig_node->tt_buff_len) || 73 uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
71 ((tt_buff_len > 0) && 74 bool full_table = true;
72 (orig_node->tt_buff_len > 0) && 75
73 (memcmp(orig_node->tt_buff, tt_buff, tt_buff_len) != 0))) { 76 /* the ttvn increased by one -> we can apply the attached changes */
74 77 if (ttvn - orig_ttvn == 1) {
75 if (orig_node->tt_buff_len > 0) 78 /* the OGM could not contain the changes because they were too
76 tt_global_del_orig(bat_priv, orig_node, 79 * many to fit in one frame or because they have already been
77 "originator changed tt"); 80 * sent TT_OGM_APPEND_MAX times. In this case send a tt
78 81 * request */
79 if ((tt_buff_len > 0) && (tt_buff)) 82 if (!tt_num_changes) {
80 tt_global_add_orig(bat_priv, orig_node, 83 full_table = false;
81 tt_buff, tt_buff_len); 84 goto request_table;
85 }
86
87 tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
88 (struct tt_change *)tt_buff);
89
90 /* Even if we received the crc into the OGM, we prefer
91 * to recompute it to spot any possible inconsistency
92 * in the global table */
93 spin_lock_bh(&bat_priv->tt_ghash_lock);
94 orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
95 spin_unlock_bh(&bat_priv->tt_ghash_lock);
96 } else {
97 /* if we missed more than one change or our tables are not
98 * in sync anymore -> request fresh tt data */
99 if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) {
100request_table:
101 bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. "
102 "Need to retrieve the correct information "
103 "(ttvn: %u last_ttvn: %u crc: %u last_crc: "
104 "%u num_changes: %u)\n", orig_node->orig, ttvn,
105 orig_ttvn, tt_crc, orig_node->tt_crc,
106 tt_num_changes);
107 send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
108 full_table);
109 return;
110 }
82 } 111 }
83} 112}
84 113
85static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node, 114static void update_route(struct bat_priv *bat_priv,
86 struct neigh_node *neigh_node, 115 struct orig_node *orig_node,
87 const unsigned char *tt_buff, int tt_buff_len) 116 struct neigh_node *neigh_node)
88{ 117{
89 struct neigh_node *curr_router; 118 struct neigh_node *curr_router;
90 119
@@ -92,11 +121,10 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
92 121
93 /* route deleted */ 122 /* route deleted */
94 if ((curr_router) && (!neigh_node)) { 123 if ((curr_router) && (!neigh_node)) {
95
96 bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", 124 bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
97 orig_node->orig); 125 orig_node->orig);
98 tt_global_del_orig(bat_priv, orig_node, 126 tt_global_del_orig(bat_priv, orig_node,
99 "originator timed out"); 127 "Deleted route towards originator");
100 128
101 /* route added */ 129 /* route added */
102 } else if ((!curr_router) && (neigh_node)) { 130 } else if ((!curr_router) && (neigh_node)) {
@@ -104,9 +132,6 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
104 bat_dbg(DBG_ROUTES, bat_priv, 132 bat_dbg(DBG_ROUTES, bat_priv,
105 "Adding route towards: %pM (via %pM)\n", 133 "Adding route towards: %pM (via %pM)\n",
106 orig_node->orig, neigh_node->addr); 134 orig_node->orig, neigh_node->addr);
107 tt_global_add_orig(bat_priv, orig_node,
108 tt_buff, tt_buff_len);
109
110 /* route changed */ 135 /* route changed */
111 } else if (neigh_node && curr_router) { 136 } else if (neigh_node && curr_router) {
112 bat_dbg(DBG_ROUTES, bat_priv, 137 bat_dbg(DBG_ROUTES, bat_priv,
@@ -133,8 +158,7 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
133} 158}
134 159
135void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, 160void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
136 struct neigh_node *neigh_node, const unsigned char *tt_buff, 161 struct neigh_node *neigh_node)
137 int tt_buff_len)
138{ 162{
139 struct neigh_node *router = NULL; 163 struct neigh_node *router = NULL;
140 164
@@ -144,11 +168,7 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
144 router = orig_node_get_router(orig_node); 168 router = orig_node_get_router(orig_node);
145 169
146 if (router != neigh_node) 170 if (router != neigh_node)
147 update_route(bat_priv, orig_node, neigh_node, 171 update_route(bat_priv, orig_node, neigh_node);
148 tt_buff, tt_buff_len);
149 /* may be just TT changed */
150 else
151 update_TT(bat_priv, orig_node, tt_buff, tt_buff_len);
152 172
153out: 173out:
154 if (router) 174 if (router)
@@ -360,14 +380,12 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
360 const struct ethhdr *ethhdr, 380 const struct ethhdr *ethhdr,
361 const struct batman_packet *batman_packet, 381 const struct batman_packet *batman_packet,
362 struct hard_iface *if_incoming, 382 struct hard_iface *if_incoming,
363 const unsigned char *tt_buff, int tt_buff_len, 383 const unsigned char *tt_buff, int is_duplicate)
364 int is_duplicate)
365{ 384{
366 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; 385 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
367 struct neigh_node *router = NULL; 386 struct neigh_node *router = NULL;
368 struct orig_node *orig_node_tmp; 387 struct orig_node *orig_node_tmp;
369 struct hlist_node *node; 388 struct hlist_node *node;
370 int tmp_tt_buff_len;
371 uint8_t bcast_own_sum_orig, bcast_own_sum_neigh; 389 uint8_t bcast_own_sum_orig, bcast_own_sum_neigh;
372 390
373 bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): " 391 bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
@@ -432,9 +450,6 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
432 450
433 bonding_candidate_add(orig_node, neigh_node); 451 bonding_candidate_add(orig_node, neigh_node);
434 452
435 tmp_tt_buff_len = (tt_buff_len > batman_packet->num_tt * ETH_ALEN ?
436 batman_packet->num_tt * ETH_ALEN : tt_buff_len);
437
438 /* if this neighbor already is our next hop there is nothing 453 /* if this neighbor already is our next hop there is nothing
439 * to change */ 454 * to change */
440 router = orig_node_get_router(orig_node); 455 router = orig_node_get_router(orig_node);
@@ -464,15 +479,19 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
464 goto update_tt; 479 goto update_tt;
465 } 480 }
466 481
467 update_routes(bat_priv, orig_node, neigh_node, 482 update_routes(bat_priv, orig_node, neigh_node);
468 tt_buff, tmp_tt_buff_len);
469 goto update_gw;
470 483
471update_tt: 484update_tt:
472 update_routes(bat_priv, orig_node, router, 485 /* I have to check for transtable changes only if the OGM has been
473 tt_buff, tmp_tt_buff_len); 486 * sent through a primary interface */
487 if (((batman_packet->orig != ethhdr->h_source) &&
488 (batman_packet->ttl > 2)) ||
489 (batman_packet->flags & PRIMARIES_FIRST_HOP))
490 update_transtable(bat_priv, orig_node, tt_buff,
491 batman_packet->tt_num_changes,
492 batman_packet->ttvn,
493 batman_packet->tt_crc);
474 494
475update_gw:
476 if (orig_node->gw_flags != batman_packet->gw_flags) 495 if (orig_node->gw_flags != batman_packet->gw_flags)
477 gw_node_update(bat_priv, orig_node, batman_packet->gw_flags); 496 gw_node_update(bat_priv, orig_node, batman_packet->gw_flags);
478 497
@@ -594,7 +613,7 @@ out:
594 613
595void receive_bat_packet(const struct ethhdr *ethhdr, 614void receive_bat_packet(const struct ethhdr *ethhdr,
596 struct batman_packet *batman_packet, 615 struct batman_packet *batman_packet,
597 const unsigned char *tt_buff, int tt_buff_len, 616 const unsigned char *tt_buff,
598 struct hard_iface *if_incoming) 617 struct hard_iface *if_incoming)
599{ 618{
600 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 619 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
@@ -633,12 +652,14 @@ void receive_bat_packet(const struct ethhdr *ethhdr,
633 652
634 bat_dbg(DBG_BATMAN, bat_priv, 653 bat_dbg(DBG_BATMAN, bat_priv,
635 "Received BATMAN packet via NB: %pM, IF: %s [%pM] " 654 "Received BATMAN packet via NB: %pM, IF: %s [%pM] "
636 "(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, " 655 "(from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, "
637 "TTL %d, V %d, IDF %d)\n", 656 "crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
638 ethhdr->h_source, if_incoming->net_dev->name, 657 ethhdr->h_source, if_incoming->net_dev->name,
639 if_incoming->net_dev->dev_addr, batman_packet->orig, 658 if_incoming->net_dev->dev_addr, batman_packet->orig,
640 batman_packet->prev_sender, batman_packet->seqno, 659 batman_packet->prev_sender, batman_packet->seqno,
641 batman_packet->tq, batman_packet->ttl, batman_packet->version, 660 batman_packet->ttvn, batman_packet->tt_crc,
661 batman_packet->tt_num_changes, batman_packet->tq,
662 batman_packet->ttl, batman_packet->version,
642 has_directlink_flag); 663 has_directlink_flag);
643 664
644 rcu_read_lock(); 665 rcu_read_lock();
@@ -790,14 +811,14 @@ void receive_bat_packet(const struct ethhdr *ethhdr,
790 ((orig_node->last_real_seqno == batman_packet->seqno) && 811 ((orig_node->last_real_seqno == batman_packet->seqno) &&
791 (orig_node->last_ttl - 3 <= batman_packet->ttl)))) 812 (orig_node->last_ttl - 3 <= batman_packet->ttl))))
792 update_orig(bat_priv, orig_node, ethhdr, batman_packet, 813 update_orig(bat_priv, orig_node, ethhdr, batman_packet,
793 if_incoming, tt_buff, tt_buff_len, is_duplicate); 814 if_incoming, tt_buff, is_duplicate);
794 815
795 /* is single hop (direct) neighbor */ 816 /* is single hop (direct) neighbor */
796 if (is_single_hop_neigh) { 817 if (is_single_hop_neigh) {
797 818
798 /* mark direct link on incoming interface */ 819 /* mark direct link on incoming interface */
799 schedule_forward_packet(orig_node, ethhdr, batman_packet, 820 schedule_forward_packet(orig_node, ethhdr, batman_packet,
800 1, tt_buff_len, if_incoming); 821 1, if_incoming);
801 822
802 bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: " 823 bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
803 "rebroadcast neighbor packet with direct link flag\n"); 824 "rebroadcast neighbor packet with direct link flag\n");
@@ -820,7 +841,7 @@ void receive_bat_packet(const struct ethhdr *ethhdr,
820 bat_dbg(DBG_BATMAN, bat_priv, 841 bat_dbg(DBG_BATMAN, bat_priv,
821 "Forwarding packet: rebroadcast originator packet\n"); 842 "Forwarding packet: rebroadcast originator packet\n");
822 schedule_forward_packet(orig_node, ethhdr, batman_packet, 843 schedule_forward_packet(orig_node, ethhdr, batman_packet,
823 0, tt_buff_len, if_incoming); 844 0, if_incoming);
824 845
825out_neigh: 846out_neigh:
826 if ((orig_neigh_node) && (!is_single_hop_neigh)) 847 if ((orig_neigh_node) && (!is_single_hop_neigh))
@@ -1167,6 +1188,70 @@ static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
1167 return router; 1188 return router;
1168} 1189}
1169 1190
1191int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
1192{
1193 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
1194 struct tt_query_packet *tt_query;
1195 struct ethhdr *ethhdr;
1196
1197 /* drop packet if it has not necessary minimum size */
1198 if (unlikely(!pskb_may_pull(skb, sizeof(struct tt_query_packet))))
1199 goto out;
1200
1201 /* I could need to modify it */
1202 if (skb_cow(skb, sizeof(struct tt_query_packet)) < 0)
1203 goto out;
1204
1205 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1206
1207 /* packet with unicast indication but broadcast recipient */
1208 if (is_broadcast_ether_addr(ethhdr->h_dest))
1209 goto out;
1210
1211 /* packet with broadcast sender address */
1212 if (is_broadcast_ether_addr(ethhdr->h_source))
1213 goto out;
1214
1215 tt_query = (struct tt_query_packet *)skb->data;
1216
1217 tt_query->tt_data = ntohs(tt_query->tt_data);
1218
1219 switch (tt_query->flags & TT_QUERY_TYPE_MASK) {
1220 case TT_REQUEST:
1221 /* If we cannot provide an answer the tt_request is
1222 * forwarded */
1223 if (!send_tt_response(bat_priv, tt_query)) {
1224 bat_dbg(DBG_TT, bat_priv,
1225 "Routing TT_REQUEST to %pM [%c]\n",
1226 tt_query->dst,
1227 (tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
1228 tt_query->tt_data = htons(tt_query->tt_data);
1229 return route_unicast_packet(skb, recv_if);
1230 }
1231 break;
1232 case TT_RESPONSE:
1233 /* packet needs to be linearised to access the TT changes */
1234 if (skb_linearize(skb) < 0)
1235 goto out;
1236
1237 if (is_my_mac(tt_query->dst))
1238 handle_tt_response(bat_priv, tt_query);
1239 else {
1240 bat_dbg(DBG_TT, bat_priv,
1241 "Routing TT_RESPONSE to %pM [%c]\n",
1242 tt_query->dst,
1243 (tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
1244 tt_query->tt_data = htons(tt_query->tt_data);
1245 return route_unicast_packet(skb, recv_if);
1246 }
1247 break;
1248 }
1249
1250out:
1251 /* returning NET_RX_DROP will make the caller function kfree the skb */
1252 return NET_RX_DROP;
1253}
1254
1170/* find a suitable router for this originator, and use 1255/* find a suitable router for this originator, and use
1171 * bonding if possible. increases the found neighbors 1256 * bonding if possible. increases the found neighbors
1172 * refcount.*/ 1257 * refcount.*/
@@ -1353,14 +1438,82 @@ out:
1353 return ret; 1438 return ret;
1354} 1439}
1355 1440
1441static int check_unicast_ttvn(struct bat_priv *bat_priv,
1442 struct sk_buff *skb) {
1443 uint8_t curr_ttvn;
1444 struct orig_node *orig_node;
1445 struct ethhdr *ethhdr;
1446 struct hard_iface *primary_if;
1447 struct unicast_packet *unicast_packet;
1448
1449 /* I could need to modify it */
1450 if (skb_cow(skb, sizeof(struct unicast_packet)) < 0)
1451 return 0;
1452
1453 unicast_packet = (struct unicast_packet *)skb->data;
1454
1455 if (is_my_mac(unicast_packet->dest))
1456 curr_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1457 else {
1458 orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
1459
1460 if (!orig_node)
1461 return 0;
1462
1463 curr_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
1464 orig_node_free_ref(orig_node);
1465 }
1466
1467 /* Check whether I have to reroute the packet */
1468 if (seq_before(unicast_packet->ttvn, curr_ttvn)) {
1469 /* Linearize the skb before accessing it */
1470 if (skb_linearize(skb) < 0)
1471 return 0;
1472
1473 ethhdr = (struct ethhdr *)(skb->data +
1474 sizeof(struct unicast_packet));
1475
1476 orig_node = transtable_search(bat_priv, ethhdr->h_dest);
1477
1478 if (!orig_node) {
1479 if (!is_my_client(bat_priv, ethhdr->h_dest))
1480 return 0;
1481 primary_if = primary_if_get_selected(bat_priv);
1482 if (!primary_if)
1483 return 0;
1484 memcpy(unicast_packet->dest,
1485 primary_if->net_dev->dev_addr, ETH_ALEN);
1486 hardif_free_ref(primary_if);
1487 } else {
1488 memcpy(unicast_packet->dest, orig_node->orig,
1489 ETH_ALEN);
1490 curr_ttvn = (uint8_t)
1491 atomic_read(&orig_node->last_ttvn);
1492 orig_node_free_ref(orig_node);
1493 }
1494
1495 bat_dbg(DBG_ROUTES, bat_priv, "TTVN mismatch (old_ttvn %u "
1496 "new_ttvn %u)! Rerouting unicast packet (for %pM) to "
1497 "%pM\n", unicast_packet->ttvn, curr_ttvn,
1498 ethhdr->h_dest, unicast_packet->dest);
1499
1500 unicast_packet->ttvn = curr_ttvn;
1501 }
1502 return 1;
1503}
1504
1356int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) 1505int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
1357{ 1506{
1507 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
1358 struct unicast_packet *unicast_packet; 1508 struct unicast_packet *unicast_packet;
1359 int hdr_size = sizeof(*unicast_packet); 1509 int hdr_size = sizeof(*unicast_packet);
1360 1510
1361 if (check_unicast_packet(skb, hdr_size) < 0) 1511 if (check_unicast_packet(skb, hdr_size) < 0)
1362 return NET_RX_DROP; 1512 return NET_RX_DROP;
1363 1513
1514 if (!check_unicast_ttvn(bat_priv, skb))
1515 return NET_RX_DROP;
1516
1364 unicast_packet = (struct unicast_packet *)skb->data; 1517 unicast_packet = (struct unicast_packet *)skb->data;
1365 1518
1366 /* packet for me */ 1519 /* packet for me */
@@ -1383,6 +1536,9 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if)
1383 if (check_unicast_packet(skb, hdr_size) < 0) 1536 if (check_unicast_packet(skb, hdr_size) < 0)
1384 return NET_RX_DROP; 1537 return NET_RX_DROP;
1385 1538
1539 if (!check_unicast_ttvn(bat_priv, skb))
1540 return NET_RX_DROP;
1541
1386 unicast_packet = (struct unicast_frag_packet *)skb->data; 1542 unicast_packet = (struct unicast_frag_packet *)skb->data;
1387 1543
1388 /* packet for me */ 1544 /* packet for me */
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h
index 0ce03923ec05..e77d46440d2d 100644
--- a/net/batman-adv/routing.h
+++ b/net/batman-adv/routing.h
@@ -25,11 +25,10 @@
25void slide_own_bcast_window(struct hard_iface *hard_iface); 25void slide_own_bcast_window(struct hard_iface *hard_iface);
26void receive_bat_packet(const struct ethhdr *ethhdr, 26void receive_bat_packet(const struct ethhdr *ethhdr,
27 struct batman_packet *batman_packet, 27 struct batman_packet *batman_packet,
28 const unsigned char *tt_buff, int tt_buff_len, 28 const unsigned char *tt_buff,
29 struct hard_iface *if_incoming); 29 struct hard_iface *if_incoming);
30void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, 30void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
31 struct neigh_node *neigh_node, const unsigned char *tt_buff, 31 struct neigh_node *neigh_node);
32 int tt_buff_len);
33int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if); 32int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
34int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if); 33int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if);
35int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if); 34int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
@@ -37,6 +36,7 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if);
37int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if); 36int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
38int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if); 37int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if);
39int recv_bat_packet(struct sk_buff *skb, struct hard_iface *recv_if); 38int recv_bat_packet(struct sk_buff *skb, struct hard_iface *recv_if);
39int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if);
40struct neigh_node *find_router(struct bat_priv *bat_priv, 40struct neigh_node *find_router(struct bat_priv *bat_priv,
41 struct orig_node *orig_node, 41 struct orig_node *orig_node,
42 const struct hard_iface *recv_if); 42 const struct hard_iface *recv_if);
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index be0d581a62a9..6b1407570e44 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -120,7 +120,7 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
120 /* adjust all flags and log packets */ 120 /* adjust all flags and log packets */
121 while (aggregated_packet(buff_pos, 121 while (aggregated_packet(buff_pos,
122 forw_packet->packet_len, 122 forw_packet->packet_len,
123 batman_packet->num_tt)) { 123 batman_packet->tt_num_changes)) {
124 124
125 /* we might have aggregated direct link packets with an 125 /* we might have aggregated direct link packets with an
126 * ordinary base packet */ 126 * ordinary base packet */
@@ -135,17 +135,17 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
135 "Forwarding")); 135 "Forwarding"));
136 bat_dbg(DBG_BATMAN, bat_priv, 136 bat_dbg(DBG_BATMAN, bat_priv,
137 "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d," 137 "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d,"
138 " IDF %s) on interface %s [%pM]\n", 138 " IDF %s, hvn %d) on interface %s [%pM]\n",
139 fwd_str, (packet_num > 0 ? "aggregated " : ""), 139 fwd_str, (packet_num > 0 ? "aggregated " : ""),
140 batman_packet->orig, ntohl(batman_packet->seqno), 140 batman_packet->orig, ntohl(batman_packet->seqno),
141 batman_packet->tq, batman_packet->ttl, 141 batman_packet->tq, batman_packet->ttl,
142 (batman_packet->flags & DIRECTLINK ? 142 (batman_packet->flags & DIRECTLINK ?
143 "on" : "off"), 143 "on" : "off"),
144 hard_iface->net_dev->name, 144 batman_packet->ttvn, hard_iface->net_dev->name,
145 hard_iface->net_dev->dev_addr); 145 hard_iface->net_dev->dev_addr);
146 146
147 buff_pos += sizeof(*batman_packet) + 147 buff_pos += sizeof(*batman_packet) +
148 (batman_packet->num_tt * ETH_ALEN); 148 tt_len(batman_packet->tt_num_changes);
149 packet_num++; 149 packet_num++;
150 batman_packet = (struct batman_packet *) 150 batman_packet = (struct batman_packet *)
151 (forw_packet->skb->data + buff_pos); 151 (forw_packet->skb->data + buff_pos);
@@ -213,25 +213,18 @@ static void send_packet(struct forw_packet *forw_packet)
213 rcu_read_unlock(); 213 rcu_read_unlock();
214} 214}
215 215
216static void rebuild_batman_packet(struct bat_priv *bat_priv, 216static void realloc_packet_buffer(struct hard_iface *hard_iface,
217 struct hard_iface *hard_iface) 217 int new_len)
218{ 218{
219 int new_len;
220 unsigned char *new_buff; 219 unsigned char *new_buff;
221 struct batman_packet *batman_packet; 220 struct batman_packet *batman_packet;
222 221
223 new_len = sizeof(*batman_packet) + (bat_priv->num_local_tt * ETH_ALEN);
224 new_buff = kmalloc(new_len, GFP_ATOMIC); 222 new_buff = kmalloc(new_len, GFP_ATOMIC);
225 223
226 /* keep old buffer if kmalloc should fail */ 224 /* keep old buffer if kmalloc should fail */
227 if (new_buff) { 225 if (new_buff) {
228 memcpy(new_buff, hard_iface->packet_buff, 226 memcpy(new_buff, hard_iface->packet_buff,
229 sizeof(*batman_packet)); 227 sizeof(*batman_packet));
230 batman_packet = (struct batman_packet *)new_buff;
231
232 batman_packet->num_tt = tt_local_fill_buffer(bat_priv,
233 new_buff + sizeof(*batman_packet),
234 new_len - sizeof(*batman_packet));
235 228
236 kfree(hard_iface->packet_buff); 229 kfree(hard_iface->packet_buff);
237 hard_iface->packet_buff = new_buff; 230 hard_iface->packet_buff = new_buff;
@@ -239,6 +232,46 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv,
239 } 232 }
240} 233}
241 234
235/* when calling this function (hard_iface == primary_if) has to be true */
236static void prepare_packet_buffer(struct bat_priv *bat_priv,
237 struct hard_iface *hard_iface)
238{
239 int new_len;
240 struct batman_packet *batman_packet;
241
242 new_len = BAT_PACKET_LEN +
243 tt_len((uint8_t)atomic_read(&bat_priv->tt_local_changes));
244
245 /* if we have too many changes for one packet don't send any
246 * and wait for the tt table request which will be fragmented */
247 if (new_len > hard_iface->soft_iface->mtu)
248 new_len = BAT_PACKET_LEN;
249
250 realloc_packet_buffer(hard_iface, new_len);
251 batman_packet = (struct batman_packet *)hard_iface->packet_buff;
252
253 atomic_set(&bat_priv->tt_crc, tt_local_crc(bat_priv));
254
255 /* reset the sending counter */
256 atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX);
257
258 batman_packet->tt_num_changes = tt_changes_fill_buffer(bat_priv,
259 hard_iface->packet_buff + BAT_PACKET_LEN,
260 hard_iface->packet_len - BAT_PACKET_LEN);
261
262}
263
264static void reset_packet_buffer(struct bat_priv *bat_priv,
265 struct hard_iface *hard_iface)
266{
267 struct batman_packet *batman_packet;
268
269 realloc_packet_buffer(hard_iface, BAT_PACKET_LEN);
270
271 batman_packet = (struct batman_packet *)hard_iface->packet_buff;
272 batman_packet->tt_num_changes = 0;
273}
274
242void schedule_own_packet(struct hard_iface *hard_iface) 275void schedule_own_packet(struct hard_iface *hard_iface)
243{ 276{
244 struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); 277 struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
@@ -264,14 +297,22 @@ void schedule_own_packet(struct hard_iface *hard_iface)
264 if (hard_iface->if_status == IF_TO_BE_ACTIVATED) 297 if (hard_iface->if_status == IF_TO_BE_ACTIVATED)
265 hard_iface->if_status = IF_ACTIVE; 298 hard_iface->if_status = IF_ACTIVE;
266 299
267 /* if local tt has changed and interface is a primary interface */ 300 if (hard_iface == primary_if) {
268 if ((atomic_read(&bat_priv->tt_local_changed)) && 301 /* if at least one change happened */
269 (hard_iface == primary_if)) 302 if (atomic_read(&bat_priv->tt_local_changes) > 0) {
270 rebuild_batman_packet(bat_priv, hard_iface); 303 prepare_packet_buffer(bat_priv, hard_iface);
304 /* Increment the TTVN only once per OGM interval */
305 atomic_inc(&bat_priv->ttvn);
306 }
307
308 /* if the changes have been sent enough times */
309 if (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))
310 reset_packet_buffer(bat_priv, hard_iface);
311 }
271 312
272 /** 313 /**
273 * NOTE: packet_buff might just have been re-allocated in 314 * NOTE: packet_buff might just have been re-allocated in
274 * rebuild_batman_packet() 315 * prepare_packet_buffer() or in reset_packet_buffer()
275 */ 316 */
276 batman_packet = (struct batman_packet *)hard_iface->packet_buff; 317 batman_packet = (struct batman_packet *)hard_iface->packet_buff;
277 318
@@ -279,6 +320,9 @@ void schedule_own_packet(struct hard_iface *hard_iface)
279 batman_packet->seqno = 320 batman_packet->seqno =
280 htonl((uint32_t)atomic_read(&hard_iface->seqno)); 321 htonl((uint32_t)atomic_read(&hard_iface->seqno));
281 322
323 batman_packet->ttvn = atomic_read(&bat_priv->ttvn);
324 batman_packet->tt_crc = htons((uint16_t)atomic_read(&bat_priv->tt_crc));
325
282 if (vis_server == VIS_TYPE_SERVER_SYNC) 326 if (vis_server == VIS_TYPE_SERVER_SYNC)
283 batman_packet->flags |= VIS_SERVER; 327 batman_packet->flags |= VIS_SERVER;
284 else 328 else
@@ -307,13 +351,14 @@ void schedule_own_packet(struct hard_iface *hard_iface)
307void schedule_forward_packet(struct orig_node *orig_node, 351void schedule_forward_packet(struct orig_node *orig_node,
308 const struct ethhdr *ethhdr, 352 const struct ethhdr *ethhdr,
309 struct batman_packet *batman_packet, 353 struct batman_packet *batman_packet,
310 int directlink, int tt_buff_len, 354 int directlink,
311 struct hard_iface *if_incoming) 355 struct hard_iface *if_incoming)
312{ 356{
313 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 357 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
314 struct neigh_node *router; 358 struct neigh_node *router;
315 uint8_t in_tq, in_ttl, tq_avg = 0; 359 uint8_t in_tq, in_ttl, tq_avg = 0;
316 unsigned long send_time; 360 unsigned long send_time;
361 uint8_t tt_num_changes;
317 362
318 if (batman_packet->ttl <= 1) { 363 if (batman_packet->ttl <= 1) {
319 bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n"); 364 bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n");
@@ -324,6 +369,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
324 369
325 in_tq = batman_packet->tq; 370 in_tq = batman_packet->tq;
326 in_ttl = batman_packet->ttl; 371 in_ttl = batman_packet->ttl;
372 tt_num_changes = batman_packet->tt_num_changes;
327 373
328 batman_packet->ttl--; 374 batman_packet->ttl--;
329 memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN); 375 memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
@@ -356,6 +402,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
356 batman_packet->ttl); 402 batman_packet->ttl);
357 403
358 batman_packet->seqno = htonl(batman_packet->seqno); 404 batman_packet->seqno = htonl(batman_packet->seqno);
405 batman_packet->tt_crc = htons(batman_packet->tt_crc);
359 406
360 /* switch of primaries first hop flag when forwarding */ 407 /* switch of primaries first hop flag when forwarding */
361 batman_packet->flags &= ~PRIMARIES_FIRST_HOP; 408 batman_packet->flags &= ~PRIMARIES_FIRST_HOP;
@@ -367,7 +414,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
367 send_time = forward_send_time(); 414 send_time = forward_send_time();
368 add_bat_packet_to_list(bat_priv, 415 add_bat_packet_to_list(bat_priv,
369 (unsigned char *)batman_packet, 416 (unsigned char *)batman_packet,
370 sizeof(*batman_packet) + tt_buff_len, 417 sizeof(*batman_packet) + tt_len(tt_num_changes),
371 if_incoming, 0, send_time); 418 if_incoming, 0, send_time);
372} 419}
373 420
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h
index 6d9c14d75977..633224ab028a 100644
--- a/net/batman-adv/send.h
+++ b/net/batman-adv/send.h
@@ -28,7 +28,7 @@ void schedule_own_packet(struct hard_iface *hard_iface);
28void schedule_forward_packet(struct orig_node *orig_node, 28void schedule_forward_packet(struct orig_node *orig_node,
29 const struct ethhdr *ethhdr, 29 const struct ethhdr *ethhdr,
30 struct batman_packet *batman_packet, 30 struct batman_packet *batman_packet,
31 int directlink, int tt_buff_len, 31 int directlink,
32 struct hard_iface *if_outgoing); 32 struct hard_iface *if_outgoing);
33int add_bcast_packet_to_list(struct bat_priv *bat_priv, 33int add_bcast_packet_to_list(struct bat_priv *bat_priv,
34 const struct sk_buff *skb); 34 const struct sk_buff *skb);
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 69c002279e63..c288d937a154 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -534,7 +534,7 @@ static int interface_set_mac_addr(struct net_device *dev, void *p)
534 /* only modify transtable if it has been initialised before */ 534 /* only modify transtable if it has been initialised before */
535 if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) { 535 if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
536 tt_local_remove(bat_priv, dev->dev_addr, 536 tt_local_remove(bat_priv, dev->dev_addr,
537 "mac address changed"); 537 "mac address changed");
538 tt_local_add(dev, addr->sa_data); 538 tt_local_add(dev, addr->sa_data);
539 } 539 }
540 540
@@ -592,7 +592,7 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
592 if (curr_softif_neigh) 592 if (curr_softif_neigh)
593 goto dropped; 593 goto dropped;
594 594
595 /* TODO: check this for locks */ 595 /* Register the client MAC in the transtable */
596 tt_local_add(soft_iface, ethhdr->h_source); 596 tt_local_add(soft_iface, ethhdr->h_source);
597 597
598 if (is_multicast_ether_addr(ethhdr->h_dest)) { 598 if (is_multicast_ether_addr(ethhdr->h_dest)) {
@@ -830,7 +830,12 @@ struct net_device *softif_create(const char *name)
830 830
831 atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); 831 atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
832 atomic_set(&bat_priv->bcast_seqno, 1); 832 atomic_set(&bat_priv->bcast_seqno, 1);
833 atomic_set(&bat_priv->tt_local_changed, 0); 833 atomic_set(&bat_priv->ttvn, 0);
834 atomic_set(&bat_priv->tt_local_changes, 0);
835 atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
836
837 bat_priv->tt_buff = NULL;
838 bat_priv->tt_buff_len = 0;
834 839
835 bat_priv->primary_if = NULL; 840 bat_priv->primary_if = NULL;
836 bat_priv->num_ifaces = 0; 841 bat_priv->num_ifaces = 0;
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 561f76968d5e..597cd1a43058 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -23,13 +23,17 @@
23#include "translation-table.h" 23#include "translation-table.h"
24#include "soft-interface.h" 24#include "soft-interface.h"
25#include "hard-interface.h" 25#include "hard-interface.h"
26#include "send.h"
26#include "hash.h" 27#include "hash.h"
27#include "originator.h" 28#include "originator.h"
29#include "routing.h"
28 30
29static void tt_local_purge(struct work_struct *work); 31#include <linux/crc16.h>
30static void _tt_global_del_orig(struct bat_priv *bat_priv, 32
31 struct tt_global_entry *tt_global_entry, 33static void _tt_global_del(struct bat_priv *bat_priv,
32 const char *message); 34 struct tt_global_entry *tt_global_entry,
35 const char *message);
36static void tt_purge(struct work_struct *work);
33 37
34/* returns 1 if they are the same mac addr */ 38/* returns 1 if they are the same mac addr */
35static int compare_ltt(const struct hlist_node *node, const void *data2) 39static int compare_ltt(const struct hlist_node *node, const void *data2)
@@ -49,10 +53,11 @@ static int compare_gtt(const struct hlist_node *node, const void *data2)
49 return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); 53 return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
50} 54}
51 55
52static void tt_local_start_timer(struct bat_priv *bat_priv) 56static void tt_start_timer(struct bat_priv *bat_priv)
53{ 57{
54 INIT_DELAYED_WORK(&bat_priv->tt_work, tt_local_purge); 58 INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge);
55 queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work, 10 * HZ); 59 queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work,
60 msecs_to_jiffies(5000));
56} 61}
57 62
58static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv, 63static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
@@ -112,7 +117,42 @@ static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
112 return tt_global_entry_tmp; 117 return tt_global_entry_tmp;
113} 118}
114 119
115int tt_local_init(struct bat_priv *bat_priv) 120static bool is_out_of_time(unsigned long starting_time, unsigned long timeout)
121{
122 unsigned long deadline;
123 deadline = starting_time + msecs_to_jiffies(timeout);
124
125 return time_after(jiffies, deadline);
126}
127
128static void tt_local_event(struct bat_priv *bat_priv, uint8_t op,
129 const uint8_t *addr)
130{
131 struct tt_change_node *tt_change_node;
132
133 tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
134
135 if (!tt_change_node)
136 return;
137
138 tt_change_node->change.flags = op;
139 memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
140
141 spin_lock_bh(&bat_priv->tt_changes_list_lock);
142 /* track the change in the OGMinterval list */
143 list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list);
144 atomic_inc(&bat_priv->tt_local_changes);
145 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
146
147 atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
148}
149
150int tt_len(int changes_num)
151{
152 return changes_num * sizeof(struct tt_change);
153}
154
155static int tt_local_init(struct bat_priv *bat_priv)
116{ 156{
117 if (bat_priv->tt_local_hash) 157 if (bat_priv->tt_local_hash)
118 return 1; 158 return 1;
@@ -122,9 +162,6 @@ int tt_local_init(struct bat_priv *bat_priv)
122 if (!bat_priv->tt_local_hash) 162 if (!bat_priv->tt_local_hash)
123 return 0; 163 return 0;
124 164
125 atomic_set(&bat_priv->tt_local_changed, 0);
126 tt_local_start_timer(bat_priv);
127
128 return 1; 165 return 1;
129} 166}
130 167
@@ -133,40 +170,24 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
133 struct bat_priv *bat_priv = netdev_priv(soft_iface); 170 struct bat_priv *bat_priv = netdev_priv(soft_iface);
134 struct tt_local_entry *tt_local_entry; 171 struct tt_local_entry *tt_local_entry;
135 struct tt_global_entry *tt_global_entry; 172 struct tt_global_entry *tt_global_entry;
136 int required_bytes;
137 173
138 spin_lock_bh(&bat_priv->tt_lhash_lock); 174 spin_lock_bh(&bat_priv->tt_lhash_lock);
139 tt_local_entry = tt_local_hash_find(bat_priv, addr); 175 tt_local_entry = tt_local_hash_find(bat_priv, addr);
140 spin_unlock_bh(&bat_priv->tt_lhash_lock);
141 176
142 if (tt_local_entry) { 177 if (tt_local_entry) {
143 tt_local_entry->last_seen = jiffies; 178 tt_local_entry->last_seen = jiffies;
144 return; 179 goto unlock;
145 }
146
147 /* only announce as many hosts as possible in the batman-packet and
148 space in batman_packet->num_tt That also should give a limit to
149 MAC-flooding. */
150 required_bytes = (bat_priv->num_local_tt + 1) * ETH_ALEN;
151 required_bytes += BAT_PACKET_LEN;
152
153 if ((required_bytes > ETH_DATA_LEN) ||
154 (atomic_read(&bat_priv->aggregated_ogms) &&
155 required_bytes > MAX_AGGREGATION_BYTES) ||
156 (bat_priv->num_local_tt + 1 > 255)) {
157 bat_dbg(DBG_ROUTES, bat_priv,
158 "Can't add new local tt entry (%pM): "
159 "number of local tt entries exceeds packet size\n",
160 addr);
161 return;
162 } 180 }
163 181
164 bat_dbg(DBG_ROUTES, bat_priv,
165 "Creating new local tt entry: %pM\n", addr);
166
167 tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC); 182 tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC);
168 if (!tt_local_entry) 183 if (!tt_local_entry)
169 return; 184 goto unlock;
185
186 tt_local_event(bat_priv, NO_FLAGS, addr);
187
188 bat_dbg(DBG_TT, bat_priv,
189 "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
190 (uint8_t)atomic_read(&bat_priv->ttvn));
170 191
171 memcpy(tt_local_entry->addr, addr, ETH_ALEN); 192 memcpy(tt_local_entry->addr, addr, ETH_ALEN);
172 tt_local_entry->last_seen = jiffies; 193 tt_local_entry->last_seen = jiffies;
@@ -177,13 +198,9 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
177 else 198 else
178 tt_local_entry->never_purge = 0; 199 tt_local_entry->never_purge = 0;
179 200
180 spin_lock_bh(&bat_priv->tt_lhash_lock);
181
182 hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig, 201 hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
183 tt_local_entry, &tt_local_entry->hash_entry); 202 tt_local_entry, &tt_local_entry->hash_entry);
184 bat_priv->num_local_tt++; 203 atomic_inc(&bat_priv->num_local_tt);
185 atomic_set(&bat_priv->tt_local_changed, 1);
186
187 spin_unlock_bh(&bat_priv->tt_lhash_lock); 204 spin_unlock_bh(&bat_priv->tt_lhash_lock);
188 205
189 /* remove address from global hash if present */ 206 /* remove address from global hash if present */
@@ -192,46 +209,60 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
192 tt_global_entry = tt_global_hash_find(bat_priv, addr); 209 tt_global_entry = tt_global_hash_find(bat_priv, addr);
193 210
194 if (tt_global_entry) 211 if (tt_global_entry)
195 _tt_global_del_orig(bat_priv, tt_global_entry, 212 _tt_global_del(bat_priv, tt_global_entry,
196 "local tt received"); 213 "local tt received");
197 214
198 spin_unlock_bh(&bat_priv->tt_ghash_lock); 215 spin_unlock_bh(&bat_priv->tt_ghash_lock);
216 return;
217unlock:
218 spin_unlock_bh(&bat_priv->tt_lhash_lock);
199} 219}
200 220
201int tt_local_fill_buffer(struct bat_priv *bat_priv, 221int tt_changes_fill_buffer(struct bat_priv *bat_priv,
202 unsigned char *buff, int buff_len) 222 unsigned char *buff, int buff_len)
203{ 223{
204 struct hashtable_t *hash = bat_priv->tt_local_hash; 224 int count = 0, tot_changes = 0;
205 struct tt_local_entry *tt_local_entry; 225 struct tt_change_node *entry, *safe;
206 struct hlist_node *node;
207 struct hlist_head *head;
208 int i, count = 0;
209 226
210 spin_lock_bh(&bat_priv->tt_lhash_lock); 227 if (buff_len > 0)
228 tot_changes = buff_len / tt_len(1);
211 229
212 for (i = 0; i < hash->size; i++) { 230 spin_lock_bh(&bat_priv->tt_changes_list_lock);
213 head = &hash->table[i]; 231 atomic_set(&bat_priv->tt_local_changes, 0);
214
215 rcu_read_lock();
216 hlist_for_each_entry_rcu(tt_local_entry, node,
217 head, hash_entry) {
218 if (buff_len < (count + 1) * ETH_ALEN)
219 break;
220
221 memcpy(buff + (count * ETH_ALEN), tt_local_entry->addr,
222 ETH_ALEN);
223 232
233 list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
234 list) {
235 if (count < tot_changes) {
236 memcpy(buff + tt_len(count),
237 &entry->change, sizeof(struct tt_change));
224 count++; 238 count++;
225 } 239 }
226 rcu_read_unlock(); 240 list_del(&entry->list);
241 kfree(entry);
227 } 242 }
243 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
244
245 /* Keep the buffer for possible tt_request */
246 spin_lock_bh(&bat_priv->tt_buff_lock);
247 kfree(bat_priv->tt_buff);
248 bat_priv->tt_buff_len = 0;
249 bat_priv->tt_buff = NULL;
250 /* We check whether this new OGM has no changes due to size
251 * problems */
252 if (buff_len > 0) {
253 /**
254 * if kmalloc() fails we will reply with the full table
255 * instead of providing the diff
256 */
257 bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC);
258 if (bat_priv->tt_buff) {
259 memcpy(bat_priv->tt_buff, buff, buff_len);
260 bat_priv->tt_buff_len = buff_len;
261 }
262 }
263 spin_unlock_bh(&bat_priv->tt_buff_lock);
228 264
229 /* if we did not get all new local tts see you next time ;-) */ 265 return tot_changes;
230 if (count == bat_priv->num_local_tt)
231 atomic_set(&bat_priv->tt_local_changed, 0);
232
233 spin_unlock_bh(&bat_priv->tt_lhash_lock);
234 return count;
235} 266}
236 267
237int tt_local_seq_print_text(struct seq_file *seq, void *offset) 268int tt_local_seq_print_text(struct seq_file *seq, void *offset)
@@ -263,8 +294,8 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset)
263 } 294 }
264 295
265 seq_printf(seq, "Locally retrieved addresses (from %s) " 296 seq_printf(seq, "Locally retrieved addresses (from %s) "
266 "announced via TT:\n", 297 "announced via TT (TTVN: %u):\n",
267 net_dev->name); 298 net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn));
268 299
269 spin_lock_bh(&bat_priv->tt_lhash_lock); 300 spin_lock_bh(&bat_priv->tt_lhash_lock);
270 301
@@ -311,54 +342,51 @@ out:
311 return ret; 342 return ret;
312} 343}
313 344
314static void _tt_local_del(struct hlist_node *node, void *arg) 345static void tt_local_entry_free(struct hlist_node *node, void *arg)
315{ 346{
316 struct bat_priv *bat_priv = arg; 347 struct bat_priv *bat_priv = arg;
317 void *data = container_of(node, struct tt_local_entry, hash_entry); 348 void *data = container_of(node, struct tt_local_entry, hash_entry);
318 349
319 kfree(data); 350 kfree(data);
320 bat_priv->num_local_tt--; 351 atomic_dec(&bat_priv->num_local_tt);
321 atomic_set(&bat_priv->tt_local_changed, 1);
322} 352}
323 353
324static void tt_local_del(struct bat_priv *bat_priv, 354static void tt_local_del(struct bat_priv *bat_priv,
325 struct tt_local_entry *tt_local_entry, 355 struct tt_local_entry *tt_local_entry,
326 const char *message) 356 const char *message)
327{ 357{
328 bat_dbg(DBG_ROUTES, bat_priv, "Deleting local tt entry (%pM): %s\n", 358 bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry (%pM): %s\n",
329 tt_local_entry->addr, message); 359 tt_local_entry->addr, message);
330 360
361 atomic_dec(&bat_priv->num_local_tt);
362
331 hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig, 363 hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig,
332 tt_local_entry->addr); 364 tt_local_entry->addr);
333 _tt_local_del(&tt_local_entry->hash_entry, bat_priv); 365
366 tt_local_entry_free(&tt_local_entry->hash_entry, bat_priv);
334} 367}
335 368
336void tt_local_remove(struct bat_priv *bat_priv, 369void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
337 const uint8_t *addr, const char *message) 370 const char *message)
338{ 371{
339 struct tt_local_entry *tt_local_entry; 372 struct tt_local_entry *tt_local_entry;
340 373
341 spin_lock_bh(&bat_priv->tt_lhash_lock); 374 spin_lock_bh(&bat_priv->tt_lhash_lock);
342
343 tt_local_entry = tt_local_hash_find(bat_priv, addr); 375 tt_local_entry = tt_local_hash_find(bat_priv, addr);
344 376
345 if (tt_local_entry) 377 if (tt_local_entry) {
378 tt_local_event(bat_priv, TT_CHANGE_DEL, tt_local_entry->addr);
346 tt_local_del(bat_priv, tt_local_entry, message); 379 tt_local_del(bat_priv, tt_local_entry, message);
347 380 }
348 spin_unlock_bh(&bat_priv->tt_lhash_lock); 381 spin_unlock_bh(&bat_priv->tt_lhash_lock);
349} 382}
350 383
351static void tt_local_purge(struct work_struct *work) 384static void tt_local_purge(struct bat_priv *bat_priv)
352{ 385{
353 struct delayed_work *delayed_work =
354 container_of(work, struct delayed_work, work);
355 struct bat_priv *bat_priv =
356 container_of(delayed_work, struct bat_priv, tt_work);
357 struct hashtable_t *hash = bat_priv->tt_local_hash; 386 struct hashtable_t *hash = bat_priv->tt_local_hash;
358 struct tt_local_entry *tt_local_entry; 387 struct tt_local_entry *tt_local_entry;
359 struct hlist_node *node, *node_tmp; 388 struct hlist_node *node, *node_tmp;
360 struct hlist_head *head; 389 struct hlist_head *head;
361 unsigned long timeout;
362 int i; 390 int i;
363 391
364 spin_lock_bh(&bat_priv->tt_lhash_lock); 392 spin_lock_bh(&bat_priv->tt_lhash_lock);
@@ -371,32 +399,53 @@ static void tt_local_purge(struct work_struct *work)
371 if (tt_local_entry->never_purge) 399 if (tt_local_entry->never_purge)
372 continue; 400 continue;
373 401
374 timeout = tt_local_entry->last_seen; 402 if (!is_out_of_time(tt_local_entry->last_seen,
375 timeout += TT_LOCAL_TIMEOUT * HZ; 403 TT_LOCAL_TIMEOUT * 1000))
376
377 if (time_before(jiffies, timeout))
378 continue; 404 continue;
379 405
406 tt_local_event(bat_priv, TT_CHANGE_DEL,
407 tt_local_entry->addr);
380 tt_local_del(bat_priv, tt_local_entry, 408 tt_local_del(bat_priv, tt_local_entry,
381 "address timed out"); 409 "address timed out");
382 } 410 }
383 } 411 }
384 412
385 spin_unlock_bh(&bat_priv->tt_lhash_lock); 413 spin_unlock_bh(&bat_priv->tt_lhash_lock);
386 tt_local_start_timer(bat_priv);
387} 414}
388 415
389void tt_local_free(struct bat_priv *bat_priv) 416static void tt_local_table_free(struct bat_priv *bat_priv)
390{ 417{
418 struct hashtable_t *hash;
419 int i;
420 spinlock_t *list_lock; /* protects write access to the hash lists */
421 struct hlist_head *head;
422 struct hlist_node *node, *node_tmp;
423 struct tt_local_entry *tt_local_entry;
424
391 if (!bat_priv->tt_local_hash) 425 if (!bat_priv->tt_local_hash)
392 return; 426 return;
393 427
394 cancel_delayed_work_sync(&bat_priv->tt_work); 428 hash = bat_priv->tt_local_hash;
395 hash_delete(bat_priv->tt_local_hash, _tt_local_del, bat_priv); 429
430 for (i = 0; i < hash->size; i++) {
431 head = &hash->table[i];
432 list_lock = &hash->list_locks[i];
433
434 spin_lock_bh(list_lock);
435 hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
436 head, hash_entry) {
437 hlist_del_rcu(node);
438 kfree(tt_local_entry);
439 }
440 spin_unlock_bh(list_lock);
441 }
442
443 hash_destroy(hash);
444
396 bat_priv->tt_local_hash = NULL; 445 bat_priv->tt_local_hash = NULL;
397} 446}
398 447
399int tt_global_init(struct bat_priv *bat_priv) 448static int tt_global_init(struct bat_priv *bat_priv)
400{ 449{
401 if (bat_priv->tt_global_hash) 450 if (bat_priv->tt_global_hash)
402 return 1; 451 return 1;
@@ -409,73 +458,78 @@ int tt_global_init(struct bat_priv *bat_priv)
409 return 1; 458 return 1;
410} 459}
411 460
412void tt_global_add_orig(struct bat_priv *bat_priv, 461static void tt_changes_list_free(struct bat_priv *bat_priv)
413 struct orig_node *orig_node,
414 const unsigned char *tt_buff, int tt_buff_len)
415{ 462{
416 struct tt_global_entry *tt_global_entry; 463 struct tt_change_node *entry, *safe;
417 struct tt_local_entry *tt_local_entry;
418 int tt_buff_count = 0;
419 const unsigned char *tt_ptr;
420
421 while ((tt_buff_count + 1) * ETH_ALEN <= tt_buff_len) {
422 spin_lock_bh(&bat_priv->tt_ghash_lock);
423
424 tt_ptr = tt_buff + (tt_buff_count * ETH_ALEN);
425 tt_global_entry = tt_global_hash_find(bat_priv, tt_ptr);
426 464
427 if (!tt_global_entry) { 465 spin_lock_bh(&bat_priv->tt_changes_list_lock);
428 spin_unlock_bh(&bat_priv->tt_ghash_lock);
429 466
430 tt_global_entry = kmalloc(sizeof(*tt_global_entry), 467 list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
431 GFP_ATOMIC); 468 list) {
432 469 list_del(&entry->list);
433 if (!tt_global_entry) 470 kfree(entry);
434 break; 471 }
435
436 memcpy(tt_global_entry->addr, tt_ptr, ETH_ALEN);
437
438 bat_dbg(DBG_ROUTES, bat_priv,
439 "Creating new global tt entry: "
440 "%pM (via %pM)\n",
441 tt_global_entry->addr, orig_node->orig);
442 472
443 spin_lock_bh(&bat_priv->tt_ghash_lock); 473 atomic_set(&bat_priv->tt_local_changes, 0);
444 hash_add(bat_priv->tt_global_hash, compare_gtt, 474 spin_unlock_bh(&bat_priv->tt_changes_list_lock);
445 choose_orig, tt_global_entry, 475}
446 &tt_global_entry->hash_entry);
447 476
448 } 477/* caller must hold orig_node refcount */
478int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
479 const unsigned char *tt_addr, uint8_t ttvn)
480{
481 struct tt_global_entry *tt_global_entry;
482 struct tt_local_entry *tt_local_entry;
483 struct orig_node *orig_node_tmp;
449 484
485 spin_lock_bh(&bat_priv->tt_ghash_lock);
486 tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
487
488 if (!tt_global_entry) {
489 tt_global_entry =
490 kmalloc(sizeof(*tt_global_entry),
491 GFP_ATOMIC);
492 if (!tt_global_entry)
493 goto unlock;
494 memcpy(tt_global_entry->addr, tt_addr, ETH_ALEN);
495 /* Assign the new orig_node */
496 atomic_inc(&orig_node->refcount);
450 tt_global_entry->orig_node = orig_node; 497 tt_global_entry->orig_node = orig_node;
451 spin_unlock_bh(&bat_priv->tt_ghash_lock); 498 tt_global_entry->ttvn = ttvn;
452 499 atomic_inc(&orig_node->tt_size);
453 /* remove address from local hash if present */ 500 hash_add(bat_priv->tt_global_hash, compare_gtt,
454 spin_lock_bh(&bat_priv->tt_lhash_lock); 501 choose_orig, tt_global_entry,
455 502 &tt_global_entry->hash_entry);
456 tt_ptr = tt_buff + (tt_buff_count * ETH_ALEN); 503 } else {
457 tt_local_entry = tt_local_hash_find(bat_priv, tt_ptr); 504 if (tt_global_entry->orig_node != orig_node) {
458 505 atomic_dec(&tt_global_entry->orig_node->tt_size);
459 if (tt_local_entry) 506 orig_node_tmp = tt_global_entry->orig_node;
460 tt_local_del(bat_priv, tt_local_entry, 507 atomic_inc(&orig_node->refcount);
461 "global tt received"); 508 tt_global_entry->orig_node = orig_node;
509 tt_global_entry->ttvn = ttvn;
510 orig_node_free_ref(orig_node_tmp);
511 atomic_inc(&orig_node->tt_size);
512 }
513 }
462 514
463 spin_unlock_bh(&bat_priv->tt_lhash_lock); 515 spin_unlock_bh(&bat_priv->tt_ghash_lock);
464 516
465 tt_buff_count++; 517 bat_dbg(DBG_TT, bat_priv,
466 } 518 "Creating new global tt entry: %pM (via %pM)\n",
519 tt_global_entry->addr, orig_node->orig);
467 520
468 /* initialize, and overwrite if malloc succeeds */ 521 /* remove address from local hash if present */
469 orig_node->tt_buff = NULL; 522 spin_lock_bh(&bat_priv->tt_lhash_lock);
470 orig_node->tt_buff_len = 0; 523 tt_local_entry = tt_local_hash_find(bat_priv, tt_addr);
471 524
472 if (tt_buff_len > 0) { 525 if (tt_local_entry)
473 orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); 526 tt_local_del(bat_priv, tt_local_entry,
474 if (orig_node->tt_buff) { 527 "global tt received");
475 memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); 528 spin_unlock_bh(&bat_priv->tt_lhash_lock);
476 orig_node->tt_buff_len = tt_buff_len; 529 return 1;
477 } 530unlock:
478 } 531 spin_unlock_bh(&bat_priv->tt_ghash_lock);
532 return 0;
479} 533}
480 534
481int tt_global_seq_print_text(struct seq_file *seq, void *offset) 535int tt_global_seq_print_text(struct seq_file *seq, void *offset)
@@ -509,17 +563,20 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
509 seq_printf(seq, 563 seq_printf(seq,
510 "Globally announced TT entries received via the mesh %s\n", 564 "Globally announced TT entries received via the mesh %s\n",
511 net_dev->name); 565 net_dev->name);
566 seq_printf(seq, " %-13s %s %-15s %s\n",
567 "Client", "(TTVN)", "Originator", "(Curr TTVN)");
512 568
513 spin_lock_bh(&bat_priv->tt_ghash_lock); 569 spin_lock_bh(&bat_priv->tt_ghash_lock);
514 570
515 buf_size = 1; 571 buf_size = 1;
516 /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/ 572 /* Estimate length for: " * xx:xx:xx:xx:xx:xx (ttvn) via
573 * xx:xx:xx:xx:xx:xx (cur_ttvn)\n"*/
517 for (i = 0; i < hash->size; i++) { 574 for (i = 0; i < hash->size; i++) {
518 head = &hash->table[i]; 575 head = &hash->table[i];
519 576
520 rcu_read_lock(); 577 rcu_read_lock();
521 __hlist_for_each_rcu(node, head) 578 __hlist_for_each_rcu(node, head)
522 buf_size += 43; 579 buf_size += 59;
523 rcu_read_unlock(); 580 rcu_read_unlock();
524 } 581 }
525 582
@@ -538,10 +595,14 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
538 rcu_read_lock(); 595 rcu_read_lock();
539 hlist_for_each_entry_rcu(tt_global_entry, node, 596 hlist_for_each_entry_rcu(tt_global_entry, node,
540 head, hash_entry) { 597 head, hash_entry) {
541 pos += snprintf(buff + pos, 44, 598 pos += snprintf(buff + pos, 61,
542 " * %pM via %pM\n", 599 " * %pM (%3u) via %pM (%3u)\n",
543 tt_global_entry->addr, 600 tt_global_entry->addr,
544 tt_global_entry->orig_node->orig); 601 tt_global_entry->ttvn,
602 tt_global_entry->orig_node->orig,
603 (uint8_t) atomic_read(
604 &tt_global_entry->orig_node->
605 last_ttvn));
545 } 606 }
546 rcu_read_unlock(); 607 rcu_read_unlock();
547 } 608 }
@@ -556,64 +617,80 @@ out:
556 return ret; 617 return ret;
557} 618}
558 619
559static void _tt_global_del_orig(struct bat_priv *bat_priv, 620static void _tt_global_del(struct bat_priv *bat_priv,
560 struct tt_global_entry *tt_global_entry, 621 struct tt_global_entry *tt_global_entry,
561 const char *message) 622 const char *message)
562{ 623{
563 bat_dbg(DBG_ROUTES, bat_priv, 624 if (!tt_global_entry)
625 return;
626
627 bat_dbg(DBG_TT, bat_priv,
564 "Deleting global tt entry %pM (via %pM): %s\n", 628 "Deleting global tt entry %pM (via %pM): %s\n",
565 tt_global_entry->addr, tt_global_entry->orig_node->orig, 629 tt_global_entry->addr, tt_global_entry->orig_node->orig,
566 message); 630 message);
567 631
632 atomic_dec(&tt_global_entry->orig_node->tt_size);
568 hash_remove(bat_priv->tt_global_hash, compare_gtt, choose_orig, 633 hash_remove(bat_priv->tt_global_hash, compare_gtt, choose_orig,
569 tt_global_entry->addr); 634 tt_global_entry->addr);
570 kfree(tt_global_entry); 635 kfree(tt_global_entry);
571} 636}
572 637
638void tt_global_del(struct bat_priv *bat_priv,
639 struct orig_node *orig_node, const unsigned char *addr,
640 const char *message)
641{
642 struct tt_global_entry *tt_global_entry;
643
644 spin_lock_bh(&bat_priv->tt_ghash_lock);
645 tt_global_entry = tt_global_hash_find(bat_priv, addr);
646
647 if (tt_global_entry && tt_global_entry->orig_node == orig_node) {
648 atomic_dec(&orig_node->tt_size);
649 _tt_global_del(bat_priv, tt_global_entry, message);
650 }
651 spin_unlock_bh(&bat_priv->tt_ghash_lock);
652}
653
573void tt_global_del_orig(struct bat_priv *bat_priv, 654void tt_global_del_orig(struct bat_priv *bat_priv,
574 struct orig_node *orig_node, const char *message) 655 struct orig_node *orig_node, const char *message)
575{ 656{
576 struct tt_global_entry *tt_global_entry; 657 struct tt_global_entry *tt_global_entry;
577 int tt_buff_count = 0; 658 int i;
578 unsigned char *tt_ptr; 659 struct hashtable_t *hash = bat_priv->tt_global_hash;
660 struct hlist_node *node, *safe;
661 struct hlist_head *head;
579 662
580 if (orig_node->tt_buff_len == 0) 663 if (!bat_priv->tt_global_hash)
581 return; 664 return;
582 665
583 spin_lock_bh(&bat_priv->tt_ghash_lock); 666 spin_lock_bh(&bat_priv->tt_ghash_lock);
667 for (i = 0; i < hash->size; i++) {
668 head = &hash->table[i];
584 669
585 while ((tt_buff_count + 1) * ETH_ALEN <= orig_node->tt_buff_len) { 670 hlist_for_each_entry_safe(tt_global_entry, node, safe,
586 tt_ptr = orig_node->tt_buff + (tt_buff_count * ETH_ALEN); 671 head, hash_entry) {
587 tt_global_entry = tt_global_hash_find(bat_priv, tt_ptr); 672 if (tt_global_entry->orig_node == orig_node)
588 673 _tt_global_del(bat_priv, tt_global_entry,
589 if ((tt_global_entry) && 674 message);
590 (tt_global_entry->orig_node == orig_node)) 675 }
591 _tt_global_del_orig(bat_priv, tt_global_entry,
592 message);
593
594 tt_buff_count++;
595 } 676 }
677 atomic_set(&orig_node->tt_size, 0);
596 678
597 spin_unlock_bh(&bat_priv->tt_ghash_lock); 679 spin_unlock_bh(&bat_priv->tt_ghash_lock);
598
599 orig_node->tt_buff_len = 0;
600 kfree(orig_node->tt_buff);
601 orig_node->tt_buff = NULL;
602} 680}
603 681
604static void tt_global_del(struct hlist_node *node, void *arg) 682static void tt_global_entry_free(struct hlist_node *node, void *arg)
605{ 683{
606 void *data = container_of(node, struct tt_global_entry, hash_entry); 684 void *data = container_of(node, struct tt_global_entry, hash_entry);
607
608 kfree(data); 685 kfree(data);
609} 686}
610 687
611void tt_global_free(struct bat_priv *bat_priv) 688static void tt_global_table_free(struct bat_priv *bat_priv)
612{ 689{
613 if (!bat_priv->tt_global_hash) 690 if (!bat_priv->tt_global_hash)
614 return; 691 return;
615 692
616 hash_delete(bat_priv->tt_global_hash, tt_global_del, NULL); 693 hash_delete(bat_priv->tt_global_hash, tt_global_entry_free, NULL);
617 bat_priv->tt_global_hash = NULL; 694 bat_priv->tt_global_hash = NULL;
618} 695}
619 696
@@ -638,3 +715,686 @@ out:
638 spin_unlock_bh(&bat_priv->tt_ghash_lock); 715 spin_unlock_bh(&bat_priv->tt_ghash_lock);
639 return orig_node; 716 return orig_node;
640} 717}
718
719/* Calculates the checksum of the local table of a given orig_node */
720uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
721{
722 uint16_t total = 0, total_one;
723 struct hashtable_t *hash = bat_priv->tt_global_hash;
724 struct tt_global_entry *tt_global_entry;
725 struct hlist_node *node;
726 struct hlist_head *head;
727 int i, j;
728
729 for (i = 0; i < hash->size; i++) {
730 head = &hash->table[i];
731
732 rcu_read_lock();
733 hlist_for_each_entry_rcu(tt_global_entry, node,
734 head, hash_entry) {
735 if (compare_eth(tt_global_entry->orig_node,
736 orig_node)) {
737 total_one = 0;
738 for (j = 0; j < ETH_ALEN; j++)
739 total_one = crc16_byte(total_one,
740 tt_global_entry->addr[j]);
741 total ^= total_one;
742 }
743 }
744 rcu_read_unlock();
745 }
746
747 return total;
748}
749
750/* Calculates the checksum of the local table */
751uint16_t tt_local_crc(struct bat_priv *bat_priv)
752{
753 uint16_t total = 0, total_one;
754 struct hashtable_t *hash = bat_priv->tt_local_hash;
755 struct tt_local_entry *tt_local_entry;
756 struct hlist_node *node;
757 struct hlist_head *head;
758 int i, j;
759
760 for (i = 0; i < hash->size; i++) {
761 head = &hash->table[i];
762
763 rcu_read_lock();
764 hlist_for_each_entry_rcu(tt_local_entry, node,
765 head, hash_entry) {
766 total_one = 0;
767 for (j = 0; j < ETH_ALEN; j++)
768 total_one = crc16_byte(total_one,
769 tt_local_entry->addr[j]);
770 total ^= total_one;
771 }
772
773 rcu_read_unlock();
774 }
775
776 return total;
777}
778
779static void tt_req_list_free(struct bat_priv *bat_priv)
780{
781 struct tt_req_node *node, *safe;
782
783 spin_lock_bh(&bat_priv->tt_req_list_lock);
784
785 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
786 list_del(&node->list);
787 kfree(node);
788 }
789
790 spin_unlock_bh(&bat_priv->tt_req_list_lock);
791}
792
793void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
794 const unsigned char *tt_buff, uint8_t tt_num_changes)
795{
796 uint16_t tt_buff_len = tt_len(tt_num_changes);
797
798 /* Replace the old buffer only if I received something in the
799 * last OGM (the OGM could carry no changes) */
800 spin_lock_bh(&orig_node->tt_buff_lock);
801 if (tt_buff_len > 0) {
802 kfree(orig_node->tt_buff);
803 orig_node->tt_buff_len = 0;
804 orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
805 if (orig_node->tt_buff) {
806 memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
807 orig_node->tt_buff_len = tt_buff_len;
808 }
809 }
810 spin_unlock_bh(&orig_node->tt_buff_lock);
811}
812
813static void tt_req_purge(struct bat_priv *bat_priv)
814{
815 struct tt_req_node *node, *safe;
816
817 spin_lock_bh(&bat_priv->tt_req_list_lock);
818 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
819 if (is_out_of_time(node->issued_at,
820 TT_REQUEST_TIMEOUT * 1000)) {
821 list_del(&node->list);
822 kfree(node);
823 }
824 }
825 spin_unlock_bh(&bat_priv->tt_req_list_lock);
826}
827
828/* returns the pointer to the new tt_req_node struct if no request
829 * has already been issued for this orig_node, NULL otherwise */
830static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
831 struct orig_node *orig_node)
832{
833 struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
834
835 spin_lock_bh(&bat_priv->tt_req_list_lock);
836 list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) {
837 if (compare_eth(tt_req_node_tmp, orig_node) &&
838 !is_out_of_time(tt_req_node_tmp->issued_at,
839 TT_REQUEST_TIMEOUT * 1000))
840 goto unlock;
841 }
842
843 tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
844 if (!tt_req_node)
845 goto unlock;
846
847 memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
848 tt_req_node->issued_at = jiffies;
849
850 list_add(&tt_req_node->list, &bat_priv->tt_req_list);
851unlock:
852 spin_unlock_bh(&bat_priv->tt_req_list_lock);
853 return tt_req_node;
854}
855
856static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
857{
858 const struct tt_global_entry *tt_global_entry = entry_ptr;
859 const struct orig_node *orig_node = data_ptr;
860
861 return (tt_global_entry->orig_node == orig_node);
862}
863
864static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
865 struct hashtable_t *hash,
866 struct hard_iface *primary_if,
867 int (*valid_cb)(const void *,
868 const void *),
869 void *cb_data)
870{
871 struct tt_local_entry *tt_local_entry;
872 struct tt_query_packet *tt_response;
873 struct tt_change *tt_change;
874 struct hlist_node *node;
875 struct hlist_head *head;
876 struct sk_buff *skb = NULL;
877 uint16_t tt_tot, tt_count;
878 ssize_t tt_query_size = sizeof(struct tt_query_packet);
879 int i;
880
881 if (tt_query_size + tt_len > primary_if->soft_iface->mtu) {
882 tt_len = primary_if->soft_iface->mtu - tt_query_size;
883 tt_len -= tt_len % sizeof(struct tt_change);
884 }
885 tt_tot = tt_len / sizeof(struct tt_change);
886
887 skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN);
888 if (!skb)
889 goto out;
890
891 skb_reserve(skb, ETH_HLEN);
892 tt_response = (struct tt_query_packet *)skb_put(skb,
893 tt_query_size + tt_len);
894 tt_response->ttvn = ttvn;
895 tt_response->tt_data = htons(tt_tot);
896
897 tt_change = (struct tt_change *)(skb->data + tt_query_size);
898 tt_count = 0;
899
900 rcu_read_lock();
901 for (i = 0; i < hash->size; i++) {
902 head = &hash->table[i];
903
904 hlist_for_each_entry_rcu(tt_local_entry, node,
905 head, hash_entry) {
906 if (tt_count == tt_tot)
907 break;
908
909 if ((valid_cb) && (!valid_cb(tt_local_entry, cb_data)))
910 continue;
911
912 memcpy(tt_change->addr, tt_local_entry->addr, ETH_ALEN);
913 tt_change->flags = NO_FLAGS;
914
915 tt_count++;
916 tt_change++;
917 }
918 }
919 rcu_read_unlock();
920
921out:
922 return skb;
923}
924
925int send_tt_request(struct bat_priv *bat_priv, struct orig_node *dst_orig_node,
926 uint8_t ttvn, uint16_t tt_crc, bool full_table)
927{
928 struct sk_buff *skb = NULL;
929 struct tt_query_packet *tt_request;
930 struct neigh_node *neigh_node = NULL;
931 struct hard_iface *primary_if;
932 struct tt_req_node *tt_req_node = NULL;
933 int ret = 1;
934
935 primary_if = primary_if_get_selected(bat_priv);
936 if (!primary_if)
937 goto out;
938
939 /* The new tt_req will be issued only if I'm not waiting for a
940 * reply from the same orig_node yet */
941 tt_req_node = new_tt_req_node(bat_priv, dst_orig_node);
942 if (!tt_req_node)
943 goto out;
944
945 skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN);
946 if (!skb)
947 goto out;
948
949 skb_reserve(skb, ETH_HLEN);
950
951 tt_request = (struct tt_query_packet *)skb_put(skb,
952 sizeof(struct tt_query_packet));
953
954 tt_request->packet_type = BAT_TT_QUERY;
955 tt_request->version = COMPAT_VERSION;
956 memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN);
957 memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN);
958 tt_request->ttl = TTL;
959 tt_request->ttvn = ttvn;
960 tt_request->tt_data = tt_crc;
961 tt_request->flags = TT_REQUEST;
962
963 if (full_table)
964 tt_request->flags |= TT_FULL_TABLE;
965
966 neigh_node = orig_node_get_router(dst_orig_node);
967 if (!neigh_node)
968 goto out;
969
970 bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM "
971 "[%c]\n", dst_orig_node->orig, neigh_node->addr,
972 (full_table ? 'F' : '.'));
973
974 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
975 ret = 0;
976
977out:
978 if (neigh_node)
979 neigh_node_free_ref(neigh_node);
980 if (primary_if)
981 hardif_free_ref(primary_if);
982 if (ret)
983 kfree_skb(skb);
984 if (ret && tt_req_node) {
985 spin_lock_bh(&bat_priv->tt_req_list_lock);
986 list_del(&tt_req_node->list);
987 spin_unlock_bh(&bat_priv->tt_req_list_lock);
988 kfree(tt_req_node);
989 }
990 return ret;
991}
992
993static bool send_other_tt_response(struct bat_priv *bat_priv,
994 struct tt_query_packet *tt_request)
995{
996 struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL;
997 struct neigh_node *neigh_node = NULL;
998 struct hard_iface *primary_if = NULL;
999 uint8_t orig_ttvn, req_ttvn, ttvn;
1000 int ret = false;
1001 unsigned char *tt_buff;
1002 bool full_table;
1003 uint16_t tt_len, tt_tot;
1004 struct sk_buff *skb = NULL;
1005 struct tt_query_packet *tt_response;
1006
1007 bat_dbg(DBG_TT, bat_priv,
1008 "Received TT_REQUEST from %pM for "
1009 "ttvn: %u (%pM) [%c]\n", tt_request->src,
1010 tt_request->ttvn, tt_request->dst,
1011 (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1012
1013 /* Let's get the orig node of the REAL destination */
1014 req_dst_orig_node = get_orig_node(bat_priv, tt_request->dst);
1015 if (!req_dst_orig_node)
1016 goto out;
1017
1018 res_dst_orig_node = get_orig_node(bat_priv, tt_request->src);
1019 if (!res_dst_orig_node)
1020 goto out;
1021
1022 neigh_node = orig_node_get_router(res_dst_orig_node);
1023 if (!neigh_node)
1024 goto out;
1025
1026 primary_if = primary_if_get_selected(bat_priv);
1027 if (!primary_if)
1028 goto out;
1029
1030 orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1031 req_ttvn = tt_request->ttvn;
1032
1033 /* I have not the requested data */
1034 if (orig_ttvn != req_ttvn ||
1035 tt_request->tt_data != req_dst_orig_node->tt_crc)
1036 goto out;
1037
1038 /* If it has explicitly been requested the full table */
1039 if (tt_request->flags & TT_FULL_TABLE ||
1040 !req_dst_orig_node->tt_buff)
1041 full_table = true;
1042 else
1043 full_table = false;
1044
1045 /* In this version, fragmentation is not implemented, then
1046 * I'll send only one packet with as much TT entries as I can */
1047 if (!full_table) {
1048 spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
1049 tt_len = req_dst_orig_node->tt_buff_len;
1050 tt_tot = tt_len / sizeof(struct tt_change);
1051
1052 skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1053 tt_len + ETH_HLEN);
1054 if (!skb)
1055 goto unlock;
1056
1057 skb_reserve(skb, ETH_HLEN);
1058 tt_response = (struct tt_query_packet *)skb_put(skb,
1059 sizeof(struct tt_query_packet) + tt_len);
1060 tt_response->ttvn = req_ttvn;
1061 tt_response->tt_data = htons(tt_tot);
1062
1063 tt_buff = skb->data + sizeof(struct tt_query_packet);
1064 /* Copy the last orig_node's OGM buffer */
1065 memcpy(tt_buff, req_dst_orig_node->tt_buff,
1066 req_dst_orig_node->tt_buff_len);
1067
1068 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1069 } else {
1070 tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) *
1071 sizeof(struct tt_change);
1072 ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
1073
1074 skb = tt_response_fill_table(tt_len, ttvn,
1075 bat_priv->tt_global_hash,
1076 primary_if, tt_global_valid_entry,
1077 req_dst_orig_node);
1078 if (!skb)
1079 goto out;
1080
1081 tt_response = (struct tt_query_packet *)skb->data;
1082 }
1083
1084 tt_response->packet_type = BAT_TT_QUERY;
1085 tt_response->version = COMPAT_VERSION;
1086 tt_response->ttl = TTL;
1087 memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN);
1088 memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1089 tt_response->flags = TT_RESPONSE;
1090
1091 if (full_table)
1092 tt_response->flags |= TT_FULL_TABLE;
1093
1094 bat_dbg(DBG_TT, bat_priv,
1095 "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n",
1096 res_dst_orig_node->orig, neigh_node->addr,
1097 req_dst_orig_node->orig, req_ttvn);
1098
1099 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1100 ret = true;
1101 goto out;
1102
1103unlock:
1104 spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
1105
1106out:
1107 if (res_dst_orig_node)
1108 orig_node_free_ref(res_dst_orig_node);
1109 if (req_dst_orig_node)
1110 orig_node_free_ref(req_dst_orig_node);
1111 if (neigh_node)
1112 neigh_node_free_ref(neigh_node);
1113 if (primary_if)
1114 hardif_free_ref(primary_if);
1115 if (!ret)
1116 kfree_skb(skb);
1117 return ret;
1118
1119}
1120static bool send_my_tt_response(struct bat_priv *bat_priv,
1121 struct tt_query_packet *tt_request)
1122{
1123 struct orig_node *orig_node = NULL;
1124 struct neigh_node *neigh_node = NULL;
1125 struct hard_iface *primary_if = NULL;
1126 uint8_t my_ttvn, req_ttvn, ttvn;
1127 int ret = false;
1128 unsigned char *tt_buff;
1129 bool full_table;
1130 uint16_t tt_len, tt_tot;
1131 struct sk_buff *skb = NULL;
1132 struct tt_query_packet *tt_response;
1133
1134 bat_dbg(DBG_TT, bat_priv,
1135 "Received TT_REQUEST from %pM for "
1136 "ttvn: %u (me) [%c]\n", tt_request->src,
1137 tt_request->ttvn,
1138 (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
1139
1140
1141 my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1142 req_ttvn = tt_request->ttvn;
1143
1144 orig_node = get_orig_node(bat_priv, tt_request->src);
1145 if (!orig_node)
1146 goto out;
1147
1148 neigh_node = orig_node_get_router(orig_node);
1149 if (!neigh_node)
1150 goto out;
1151
1152 primary_if = primary_if_get_selected(bat_priv);
1153 if (!primary_if)
1154 goto out;
1155
1156 /* If the full table has been explicitly requested or the gap
1157 * is too big send the whole local translation table */
1158 if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn ||
1159 !bat_priv->tt_buff)
1160 full_table = true;
1161 else
1162 full_table = false;
1163
1164 /* In this version, fragmentation is not implemented, then
1165 * I'll send only one packet with as much TT entries as I can */
1166 if (!full_table) {
1167 spin_lock_bh(&bat_priv->tt_buff_lock);
1168 tt_len = bat_priv->tt_buff_len;
1169 tt_tot = tt_len / sizeof(struct tt_change);
1170
1171 skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
1172 tt_len + ETH_HLEN);
1173 if (!skb)
1174 goto unlock;
1175
1176 skb_reserve(skb, ETH_HLEN);
1177 tt_response = (struct tt_query_packet *)skb_put(skb,
1178 sizeof(struct tt_query_packet) + tt_len);
1179 tt_response->ttvn = req_ttvn;
1180 tt_response->tt_data = htons(tt_tot);
1181
1182 tt_buff = skb->data + sizeof(struct tt_query_packet);
1183 memcpy(tt_buff, bat_priv->tt_buff,
1184 bat_priv->tt_buff_len);
1185 spin_unlock_bh(&bat_priv->tt_buff_lock);
1186 } else {
1187 tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) *
1188 sizeof(struct tt_change);
1189 ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1190
1191 skb = tt_response_fill_table(tt_len, ttvn,
1192 bat_priv->tt_local_hash,
1193 primary_if, NULL, NULL);
1194 if (!skb)
1195 goto out;
1196
1197 tt_response = (struct tt_query_packet *)skb->data;
1198 }
1199
1200 tt_response->packet_type = BAT_TT_QUERY;
1201 tt_response->version = COMPAT_VERSION;
1202 tt_response->ttl = TTL;
1203 memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1204 memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
1205 tt_response->flags = TT_RESPONSE;
1206
1207 if (full_table)
1208 tt_response->flags |= TT_FULL_TABLE;
1209
1210 bat_dbg(DBG_TT, bat_priv,
1211 "Sending TT_RESPONSE to %pM via %pM [%c]\n",
1212 orig_node->orig, neigh_node->addr,
1213 (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1214
1215 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1216 ret = true;
1217 goto out;
1218
1219unlock:
1220 spin_unlock_bh(&bat_priv->tt_buff_lock);
1221out:
1222 if (orig_node)
1223 orig_node_free_ref(orig_node);
1224 if (neigh_node)
1225 neigh_node_free_ref(neigh_node);
1226 if (primary_if)
1227 hardif_free_ref(primary_if);
1228 if (!ret)
1229 kfree_skb(skb);
1230 /* This packet was for me, so it doesn't need to be re-routed */
1231 return true;
1232}
1233
1234bool send_tt_response(struct bat_priv *bat_priv,
1235 struct tt_query_packet *tt_request)
1236{
1237 if (is_my_mac(tt_request->dst))
1238 return send_my_tt_response(bat_priv, tt_request);
1239 else
1240 return send_other_tt_response(bat_priv, tt_request);
1241}
1242
1243static void _tt_update_changes(struct bat_priv *bat_priv,
1244 struct orig_node *orig_node,
1245 struct tt_change *tt_change,
1246 uint16_t tt_num_changes, uint8_t ttvn)
1247{
1248 int i;
1249
1250 for (i = 0; i < tt_num_changes; i++) {
1251 if ((tt_change + i)->flags & TT_CHANGE_DEL)
1252 tt_global_del(bat_priv, orig_node,
1253 (tt_change + i)->addr,
1254 "tt removed by changes");
1255 else
1256 if (!tt_global_add(bat_priv, orig_node,
1257 (tt_change + i)->addr, ttvn))
1258 /* In case of problem while storing a
1259 * global_entry, we stop the updating
1260 * procedure without committing the
1261 * ttvn change. This will avoid to send
1262 * corrupted data on tt_request
1263 */
1264 return;
1265 }
1266}
1267
1268static void tt_fill_gtable(struct bat_priv *bat_priv,
1269 struct tt_query_packet *tt_response)
1270{
1271 struct orig_node *orig_node = NULL;
1272
1273 orig_node = orig_hash_find(bat_priv, tt_response->src);
1274 if (!orig_node)
1275 goto out;
1276
1277 /* Purge the old table first.. */
1278 tt_global_del_orig(bat_priv, orig_node, "Received full table");
1279
1280 _tt_update_changes(bat_priv, orig_node,
1281 (struct tt_change *)(tt_response + 1),
1282 tt_response->tt_data, tt_response->ttvn);
1283
1284 spin_lock_bh(&orig_node->tt_buff_lock);
1285 kfree(orig_node->tt_buff);
1286 orig_node->tt_buff_len = 0;
1287 orig_node->tt_buff = NULL;
1288 spin_unlock_bh(&orig_node->tt_buff_lock);
1289
1290 atomic_set(&orig_node->last_ttvn, tt_response->ttvn);
1291
1292out:
1293 if (orig_node)
1294 orig_node_free_ref(orig_node);
1295}
1296
1297void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig_node,
1298 uint16_t tt_num_changes, uint8_t ttvn,
1299 struct tt_change *tt_change)
1300{
1301 _tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes,
1302 ttvn);
1303
1304 tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change,
1305 tt_num_changes);
1306 atomic_set(&orig_node->last_ttvn, ttvn);
1307}
1308
1309bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
1310{
1311 struct tt_local_entry *tt_local_entry;
1312
1313 spin_lock_bh(&bat_priv->tt_lhash_lock);
1314 tt_local_entry = tt_local_hash_find(bat_priv, addr);
1315 spin_unlock_bh(&bat_priv->tt_lhash_lock);
1316
1317 if (tt_local_entry)
1318 return true;
1319 return false;
1320}
1321
1322void handle_tt_response(struct bat_priv *bat_priv,
1323 struct tt_query_packet *tt_response)
1324{
1325 struct tt_req_node *node, *safe;
1326 struct orig_node *orig_node = NULL;
1327
1328 bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for "
1329 "ttvn %d t_size: %d [%c]\n",
1330 tt_response->src, tt_response->ttvn,
1331 tt_response->tt_data,
1332 (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
1333
1334 orig_node = orig_hash_find(bat_priv, tt_response->src);
1335 if (!orig_node)
1336 goto out;
1337
1338 if (tt_response->flags & TT_FULL_TABLE)
1339 tt_fill_gtable(bat_priv, tt_response);
1340 else
1341 tt_update_changes(bat_priv, orig_node, tt_response->tt_data,
1342 tt_response->ttvn,
1343 (struct tt_change *)(tt_response + 1));
1344
1345 /* Delete the tt_req_node from pending tt_requests list */
1346 spin_lock_bh(&bat_priv->tt_req_list_lock);
1347 list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
1348 if (!compare_eth(node->addr, tt_response->src))
1349 continue;
1350 list_del(&node->list);
1351 kfree(node);
1352 }
1353 spin_unlock_bh(&bat_priv->tt_req_list_lock);
1354
1355 /* Recalculate the CRC for this orig_node and store it */
1356 spin_lock_bh(&bat_priv->tt_ghash_lock);
1357 orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
1358 spin_unlock_bh(&bat_priv->tt_ghash_lock);
1359out:
1360 if (orig_node)
1361 orig_node_free_ref(orig_node);
1362}
1363
1364int tt_init(struct bat_priv *bat_priv)
1365{
1366 if (!tt_local_init(bat_priv))
1367 return 0;
1368
1369 if (!tt_global_init(bat_priv))
1370 return 0;
1371
1372 tt_start_timer(bat_priv);
1373
1374 return 1;
1375}
1376
1377void tt_free(struct bat_priv *bat_priv)
1378{
1379 cancel_delayed_work_sync(&bat_priv->tt_work);
1380
1381 tt_local_table_free(bat_priv);
1382 tt_global_table_free(bat_priv);
1383 tt_req_list_free(bat_priv);
1384 tt_changes_list_free(bat_priv);
1385
1386 kfree(bat_priv->tt_buff);
1387}
1388
1389static void tt_purge(struct work_struct *work)
1390{
1391 struct delayed_work *delayed_work =
1392 container_of(work, struct delayed_work, work);
1393 struct bat_priv *bat_priv =
1394 container_of(delayed_work, struct bat_priv, tt_work);
1395
1396 tt_local_purge(bat_priv);
1397 tt_req_purge(bat_priv);
1398
1399 tt_start_timer(bat_priv);
1400}
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h
index 0f2b9905cfc4..51f7e3060f6f 100644
--- a/net/batman-adv/translation-table.h
+++ b/net/batman-adv/translation-table.h
@@ -22,23 +22,43 @@
22#ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ 22#ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
23#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ 23#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
24 24
25int tt_local_init(struct bat_priv *bat_priv); 25int tt_len(int changes_num);
26int tt_changes_fill_buffer(struct bat_priv *bat_priv,
27 unsigned char *buff, int buff_len);
28int tt_init(struct bat_priv *bat_priv);
26void tt_local_add(struct net_device *soft_iface, const uint8_t *addr); 29void tt_local_add(struct net_device *soft_iface, const uint8_t *addr);
27void tt_local_remove(struct bat_priv *bat_priv, 30void tt_local_remove(struct bat_priv *bat_priv,
28 const uint8_t *addr, const char *message); 31 const uint8_t *addr, const char *message);
29int tt_local_fill_buffer(struct bat_priv *bat_priv,
30 unsigned char *buff, int buff_len);
31int tt_local_seq_print_text(struct seq_file *seq, void *offset); 32int tt_local_seq_print_text(struct seq_file *seq, void *offset);
32void tt_local_free(struct bat_priv *bat_priv);
33int tt_global_init(struct bat_priv *bat_priv);
34void tt_global_add_orig(struct bat_priv *bat_priv, 33void tt_global_add_orig(struct bat_priv *bat_priv,
35 struct orig_node *orig_node, 34 struct orig_node *orig_node,
36 const unsigned char *tt_buff, int tt_buff_len); 35 const unsigned char *tt_buff, int tt_buff_len);
36int tt_global_add(struct bat_priv *bat_priv,
37 struct orig_node *orig_node, const unsigned char *addr,
38 uint8_t ttvn);
37int tt_global_seq_print_text(struct seq_file *seq, void *offset); 39int tt_global_seq_print_text(struct seq_file *seq, void *offset);
38void tt_global_del_orig(struct bat_priv *bat_priv, 40void tt_global_del_orig(struct bat_priv *bat_priv,
39 struct orig_node *orig_node, const char *message); 41 struct orig_node *orig_node, const char *message);
40void tt_global_free(struct bat_priv *bat_priv); 42void tt_global_del(struct bat_priv *bat_priv,
43 struct orig_node *orig_node, const unsigned char *addr,
44 const char *message);
41struct orig_node *transtable_search(struct bat_priv *bat_priv, 45struct orig_node *transtable_search(struct bat_priv *bat_priv,
42 const uint8_t *addr); 46 const uint8_t *addr);
47void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
48 const unsigned char *tt_buff, uint8_t tt_num_changes);
49uint16_t tt_local_crc(struct bat_priv *bat_priv);
50uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node);
51void tt_free(struct bat_priv *bat_priv);
52int send_tt_request(struct bat_priv *bat_priv,
53 struct orig_node *dst_orig_node, uint8_t hvn,
54 uint16_t tt_crc, bool full_table);
55bool send_tt_response(struct bat_priv *bat_priv,
56 struct tt_query_packet *tt_request);
57void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig_node,
58 uint16_t tt_num_changes, uint8_t ttvn,
59 struct tt_change *tt_change);
60bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr);
61void handle_tt_response(struct bat_priv *bat_priv,
62 struct tt_query_packet *tt_response);
43 63
44#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ 64#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 65b32223d104..3b642a9e086e 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -75,8 +75,12 @@ struct orig_node {
75 unsigned long batman_seqno_reset; 75 unsigned long batman_seqno_reset;
76 uint8_t gw_flags; 76 uint8_t gw_flags;
77 uint8_t flags; 77 uint8_t flags;
78 atomic_t last_ttvn; /* last seen translation table version number */
79 uint16_t tt_crc;
78 unsigned char *tt_buff; 80 unsigned char *tt_buff;
79 int16_t tt_buff_len; 81 int16_t tt_buff_len;
82 spinlock_t tt_buff_lock; /* protects tt_buff */
83 atomic_t tt_size;
80 uint32_t last_real_seqno; 84 uint32_t last_real_seqno;
81 uint8_t last_ttl; 85 uint8_t last_ttl;
82 unsigned long bcast_bits[NUM_WORDS]; 86 unsigned long bcast_bits[NUM_WORDS];
@@ -94,6 +98,7 @@ struct orig_node {
94 spinlock_t ogm_cnt_lock; 98 spinlock_t ogm_cnt_lock;
95 /* bcast_seqno_lock protects bcast_bits, last_bcast_seqno */ 99 /* bcast_seqno_lock protects bcast_bits, last_bcast_seqno */
96 spinlock_t bcast_seqno_lock; 100 spinlock_t bcast_seqno_lock;
101 spinlock_t tt_list_lock; /* protects tt_list */
97 atomic_t bond_candidates; 102 atomic_t bond_candidates;
98 struct list_head bond_list; 103 struct list_head bond_list;
99}; 104};
@@ -145,6 +150,9 @@ struct bat_priv {
145 atomic_t bcast_seqno; 150 atomic_t bcast_seqno;
146 atomic_t bcast_queue_left; 151 atomic_t bcast_queue_left;
147 atomic_t batman_queue_left; 152 atomic_t batman_queue_left;
153 atomic_t ttvn; /* tranlation table version number */
154 atomic_t tt_ogm_append_cnt;
155 atomic_t tt_local_changes; /* changes registered in a OGM interval */
148 char num_ifaces; 156 char num_ifaces;
149 struct debug_log *debug_log; 157 struct debug_log *debug_log;
150 struct kobject *mesh_obj; 158 struct kobject *mesh_obj;
@@ -153,22 +161,30 @@ struct bat_priv {
153 struct hlist_head forw_bcast_list; 161 struct hlist_head forw_bcast_list;
154 struct hlist_head gw_list; 162 struct hlist_head gw_list;
155 struct hlist_head softif_neigh_vids; 163 struct hlist_head softif_neigh_vids;
164 struct list_head tt_changes_list; /* tracks changes in a OGM int */
156 struct list_head vis_send_list; 165 struct list_head vis_send_list;
157 struct hashtable_t *orig_hash; 166 struct hashtable_t *orig_hash;
158 struct hashtable_t *tt_local_hash; 167 struct hashtable_t *tt_local_hash;
159 struct hashtable_t *tt_global_hash; 168 struct hashtable_t *tt_global_hash;
169 struct list_head tt_req_list; /* list of pending tt_requests */
160 struct hashtable_t *vis_hash; 170 struct hashtable_t *vis_hash;
161 spinlock_t forw_bat_list_lock; /* protects forw_bat_list */ 171 spinlock_t forw_bat_list_lock; /* protects forw_bat_list */
162 spinlock_t forw_bcast_list_lock; /* protects */ 172 spinlock_t forw_bcast_list_lock; /* protects */
173 spinlock_t tt_changes_list_lock; /* protects tt_changes */
163 spinlock_t tt_lhash_lock; /* protects tt_local_hash */ 174 spinlock_t tt_lhash_lock; /* protects tt_local_hash */
164 spinlock_t tt_ghash_lock; /* protects tt_global_hash */ 175 spinlock_t tt_ghash_lock; /* protects tt_global_hash */
176 spinlock_t tt_req_list_lock; /* protects tt_req_list */
165 spinlock_t gw_list_lock; /* protects gw_list and curr_gw */ 177 spinlock_t gw_list_lock; /* protects gw_list and curr_gw */
166 spinlock_t vis_hash_lock; /* protects vis_hash */ 178 spinlock_t vis_hash_lock; /* protects vis_hash */
167 spinlock_t vis_list_lock; /* protects vis_info::recv_list */ 179 spinlock_t vis_list_lock; /* protects vis_info::recv_list */
168 spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */ 180 spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */
169 spinlock_t softif_neigh_vid_lock; /* protects soft-interface vid list */ 181 spinlock_t softif_neigh_vid_lock; /* protects soft-interface vid list */
170 int16_t num_local_tt; 182 atomic_t num_local_tt;
171 atomic_t tt_local_changed; 183 /* Checksum of the local table, recomputed before sending a new OGM */
184 atomic_t tt_crc;
185 unsigned char *tt_buff;
186 int16_t tt_buff_len;
187 spinlock_t tt_buff_lock; /* protects tt_buff */
172 struct delayed_work tt_work; 188 struct delayed_work tt_work;
173 struct delayed_work orig_work; 189 struct delayed_work orig_work;
174 struct delayed_work vis_work; 190 struct delayed_work vis_work;
@@ -202,9 +218,22 @@ struct tt_local_entry {
202struct tt_global_entry { 218struct tt_global_entry {
203 uint8_t addr[ETH_ALEN]; 219 uint8_t addr[ETH_ALEN];
204 struct orig_node *orig_node; 220 struct orig_node *orig_node;
221 uint8_t ttvn;
222 /* entry in the global table */
205 struct hlist_node hash_entry; 223 struct hlist_node hash_entry;
206}; 224};
207 225
226struct tt_change_node {
227 struct list_head list;
228 struct tt_change change;
229};
230
231struct tt_req_node {
232 uint8_t addr[ETH_ALEN];
233 unsigned long issued_at;
234 struct list_head list;
235};
236
208/** 237/**
209 * forw_packet - structure for forw_list maintaining packets to be 238 * forw_packet - structure for forw_list maintaining packets to be
210 * send/forwarded 239 * send/forwarded
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index 6eabf42f8822..32b125fb3d3b 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -325,6 +325,9 @@ find_router:
325 unicast_packet->ttl = TTL; 325 unicast_packet->ttl = TTL;
326 /* copy the destination for faster routing */ 326 /* copy the destination for faster routing */
327 memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); 327 memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
328 /* set the destination tt version number */
329 unicast_packet->ttvn =
330 (uint8_t)atomic_read(&orig_node->last_ttvn);
328 331
329 if (atomic_read(&bat_priv->fragmentation) && 332 if (atomic_read(&bat_priv->fragmentation) &&
330 data_len + sizeof(*unicast_packet) > 333 data_len + sizeof(*unicast_packet) >