aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv
diff options
context:
space:
mode:
Diffstat (limited to 'net/batman-adv')
-rw-r--r--net/batman-adv/hard-interface.c4
-rw-r--r--net/batman-adv/main.c2
-rw-r--r--net/batman-adv/main.h6
-rw-r--r--net/batman-adv/originator.c1
-rw-r--r--net/batman-adv/packet.h13
-rw-r--r--net/batman-adv/routing.c61
-rw-r--r--net/batman-adv/routing.h1
-rw-r--r--net/batman-adv/send.c1
-rw-r--r--net/batman-adv/soft-interface.c3
-rw-r--r--net/batman-adv/translation-table.c241
-rw-r--r--net/batman-adv/translation-table.h8
-rw-r--r--net/batman-adv/types.h26
12 files changed, 334 insertions, 33 deletions
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index d40426cc5e29..55b5def08d5a 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -658,6 +658,10 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
658 case BAT_TT_QUERY: 658 case BAT_TT_QUERY:
659 ret = recv_tt_query(skb, hard_iface); 659 ret = recv_tt_query(skb, hard_iface);
660 break; 660 break;
661 /* Roaming advertisement */
662 case BAT_ROAM_ADV:
663 ret = recv_roam_adv(skb, hard_iface);
664 break;
661 default: 665 default:
662 ret = NET_RX_DROP; 666 ret = NET_RX_DROP;
663 } 667 }
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 49a5e64b2d4f..3318ee27fe23 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -88,6 +88,7 @@ int mesh_init(struct net_device *soft_iface)
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); 89 spin_lock_init(&bat_priv->tt_changes_list_lock);
90 spin_lock_init(&bat_priv->tt_req_list_lock); 90 spin_lock_init(&bat_priv->tt_req_list_lock);
91 spin_lock_init(&bat_priv->tt_roam_list_lock);
91 spin_lock_init(&bat_priv->tt_buff_lock); 92 spin_lock_init(&bat_priv->tt_buff_lock);
92 spin_lock_init(&bat_priv->gw_list_lock); 93 spin_lock_init(&bat_priv->gw_list_lock);
93 spin_lock_init(&bat_priv->vis_hash_lock); 94 spin_lock_init(&bat_priv->vis_hash_lock);
@@ -101,6 +102,7 @@ int mesh_init(struct net_device *soft_iface)
101 INIT_HLIST_HEAD(&bat_priv->softif_neigh_vids); 102 INIT_HLIST_HEAD(&bat_priv->softif_neigh_vids);
102 INIT_LIST_HEAD(&bat_priv->tt_changes_list); 103 INIT_LIST_HEAD(&bat_priv->tt_changes_list);
103 INIT_LIST_HEAD(&bat_priv->tt_req_list); 104 INIT_LIST_HEAD(&bat_priv->tt_req_list);
105 INIT_LIST_HEAD(&bat_priv->tt_roam_list);
104 106
105 if (originator_init(bat_priv) < 1) 107 if (originator_init(bat_priv) < 1)
106 goto err; 108 goto err;
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index 6f53a1de778c..8eae05e4dc1b 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -42,7 +42,7 @@
42 * -> TODO: check influence on TQ_LOCAL_WINDOW_SIZE */ 42 * -> TODO: check influence on TQ_LOCAL_WINDOW_SIZE */
43#define PURGE_TIMEOUT 200 43#define PURGE_TIMEOUT 200
44#define TT_LOCAL_TIMEOUT 3600 /* in seconds */ 44#define TT_LOCAL_TIMEOUT 3600 /* in seconds */
45 45#define TT_CLIENT_ROAM_TIMEOUT 600
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
@@ -55,6 +55,10 @@
55 55
56#define TT_OGM_APPEND_MAX 3 /* number of OGMs sent with the last tt diff */ 56#define TT_OGM_APPEND_MAX 3 /* number of OGMs sent with the last tt diff */
57 57
58#define ROAMING_MAX_TIME 20 /* Time in which a client can roam at most
59 * ROAMING_MAX_COUNT times */
60#define ROAMING_MAX_COUNT 5
61
58#define NO_FLAGS 0 62#define NO_FLAGS 0
59 63
60#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE) 64#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 25e7e50eef25..338b3c597e4a 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -219,6 +219,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
219 /* extra reference for return */ 219 /* extra reference for return */
220 atomic_set(&orig_node->refcount, 2); 220 atomic_set(&orig_node->refcount, 2);
221 221
222 orig_node->tt_poss_change = false;
222 orig_node->bat_priv = bat_priv; 223 orig_node->bat_priv = bat_priv;
223 memcpy(orig_node->orig, addr, ETH_ALEN); 224 memcpy(orig_node->orig, addr, ETH_ALEN);
224 orig_node->router = NULL; 225 orig_node->router = NULL;
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
index 407dd2e84aff..c5f081dfc6d1 100644
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@ -31,7 +31,8 @@ enum bat_packettype {
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 BAT_TT_QUERY = 0x07,
35 BAT_ROAM_ADV = 0x08
35}; 36};
36 37
37/* this file is included by batctl which needs these defines */ 38/* this file is included by batctl which needs these defines */
@@ -194,6 +195,16 @@ struct tt_query_packet {
194 uint16_t tt_data; 195 uint16_t tt_data;
195} __packed; 196} __packed;
196 197
198struct roam_adv_packet {
199 uint8_t packet_type;
200 uint8_t version;
201 uint8_t ttl;
202 uint8_t reserved;
203 uint8_t dst[ETH_ALEN];
204 uint8_t src[ETH_ALEN];
205 uint8_t client[ETH_ALEN];
206} __packed;
207
197struct tt_change { 208struct tt_change {
198 uint8_t flags; 209 uint8_t flags;
199 uint8_t addr[ETH_ALEN]; 210 uint8_t addr[ETH_ALEN];
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 8b0f8330b06d..05d50ca3c4db 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -93,6 +93,9 @@ static void update_transtable(struct bat_priv *bat_priv,
93 spin_lock_bh(&bat_priv->tt_ghash_lock); 93 spin_lock_bh(&bat_priv->tt_ghash_lock);
94 orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); 94 orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
95 spin_unlock_bh(&bat_priv->tt_ghash_lock); 95 spin_unlock_bh(&bat_priv->tt_ghash_lock);
96 /* Roaming phase is over: tables are in sync again. I can
97 * unset the flag */
98 orig_node->tt_poss_change = false;
96 } else { 99 } else {
97 /* if we missed more than one change or our tables are not 100 /* if we missed more than one change or our tables are not
98 * in sync anymore -> request fresh tt data */ 101 * in sync anymore -> request fresh tt data */
@@ -1252,6 +1255,54 @@ out:
1252 return NET_RX_DROP; 1255 return NET_RX_DROP;
1253} 1256}
1254 1257
1258int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
1259{
1260 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
1261 struct roam_adv_packet *roam_adv_packet;
1262 struct orig_node *orig_node;
1263 struct ethhdr *ethhdr;
1264
1265 /* drop packet if it has not necessary minimum size */
1266 if (unlikely(!pskb_may_pull(skb, sizeof(struct roam_adv_packet))))
1267 goto out;
1268
1269 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1270
1271 /* packet with unicast indication but broadcast recipient */
1272 if (is_broadcast_ether_addr(ethhdr->h_dest))
1273 goto out;
1274
1275 /* packet with broadcast sender address */
1276 if (is_broadcast_ether_addr(ethhdr->h_source))
1277 goto out;
1278
1279 roam_adv_packet = (struct roam_adv_packet *)skb->data;
1280
1281 if (!is_my_mac(roam_adv_packet->dst))
1282 return route_unicast_packet(skb, recv_if);
1283
1284 orig_node = orig_hash_find(bat_priv, roam_adv_packet->src);
1285 if (!orig_node)
1286 goto out;
1287
1288 bat_dbg(DBG_TT, bat_priv, "Received ROAMING_ADV from %pM "
1289 "(client %pM)\n", roam_adv_packet->src,
1290 roam_adv_packet->client);
1291
1292 tt_global_add(bat_priv, orig_node, roam_adv_packet->client,
1293 atomic_read(&orig_node->last_ttvn) + 1, true);
1294
1295 /* Roaming phase starts: I have new information but the ttvn has not
1296 * been incremented yet. This flag will make me check all the incoming
1297 * packets for the correct destination. */
1298 bat_priv->tt_poss_change = true;
1299
1300 orig_node_free_ref(orig_node);
1301out:
1302 /* returning NET_RX_DROP will make the caller function kfree the skb */
1303 return NET_RX_DROP;
1304}
1305
1255/* find a suitable router for this originator, and use 1306/* find a suitable router for this originator, and use
1256 * bonding if possible. increases the found neighbors 1307 * bonding if possible. increases the found neighbors
1257 * refcount.*/ 1308 * refcount.*/
@@ -1445,6 +1496,7 @@ static int check_unicast_ttvn(struct bat_priv *bat_priv,
1445 struct ethhdr *ethhdr; 1496 struct ethhdr *ethhdr;
1446 struct hard_iface *primary_if; 1497 struct hard_iface *primary_if;
1447 struct unicast_packet *unicast_packet; 1498 struct unicast_packet *unicast_packet;
1499 bool tt_poss_change;
1448 1500
1449 /* I could need to modify it */ 1501 /* I could need to modify it */
1450 if (skb_cow(skb, sizeof(struct unicast_packet)) < 0) 1502 if (skb_cow(skb, sizeof(struct unicast_packet)) < 0)
@@ -1452,27 +1504,28 @@ static int check_unicast_ttvn(struct bat_priv *bat_priv,
1452 1504
1453 unicast_packet = (struct unicast_packet *)skb->data; 1505 unicast_packet = (struct unicast_packet *)skb->data;
1454 1506
1455 if (is_my_mac(unicast_packet->dest)) 1507 if (is_my_mac(unicast_packet->dest)) {
1508 tt_poss_change = bat_priv->tt_poss_change;
1456 curr_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); 1509 curr_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1457 else { 1510 } else {
1458 orig_node = orig_hash_find(bat_priv, unicast_packet->dest); 1511 orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
1459 1512
1460 if (!orig_node) 1513 if (!orig_node)
1461 return 0; 1514 return 0;
1462 1515
1463 curr_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); 1516 curr_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
1517 tt_poss_change = orig_node->tt_poss_change;
1464 orig_node_free_ref(orig_node); 1518 orig_node_free_ref(orig_node);
1465 } 1519 }
1466 1520
1467 /* Check whether I have to reroute the packet */ 1521 /* Check whether I have to reroute the packet */
1468 if (seq_before(unicast_packet->ttvn, curr_ttvn)) { 1522 if (seq_before(unicast_packet->ttvn, curr_ttvn) || tt_poss_change) {
1469 /* Linearize the skb before accessing it */ 1523 /* Linearize the skb before accessing it */
1470 if (skb_linearize(skb) < 0) 1524 if (skb_linearize(skb) < 0)
1471 return 0; 1525 return 0;
1472 1526
1473 ethhdr = (struct ethhdr *)(skb->data + 1527 ethhdr = (struct ethhdr *)(skb->data +
1474 sizeof(struct unicast_packet)); 1528 sizeof(struct unicast_packet));
1475
1476 orig_node = transtable_search(bat_priv, ethhdr->h_dest); 1529 orig_node = transtable_search(bat_priv, ethhdr->h_dest);
1477 1530
1478 if (!orig_node) { 1531 if (!orig_node) {
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h
index e77d46440d2d..fb14e9579b19 100644
--- a/net/batman-adv/routing.h
+++ b/net/batman-adv/routing.h
@@ -37,6 +37,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
37int 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);
38int 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); 39int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if);
40int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if);
40struct neigh_node *find_router(struct bat_priv *bat_priv, 41struct neigh_node *find_router(struct bat_priv *bat_priv,
41 struct orig_node *orig_node, 42 struct orig_node *orig_node,
42 const struct hard_iface *recv_if); 43 const struct hard_iface *recv_if);
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index 6b1407570e44..7a2f0823f1c2 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -303,6 +303,7 @@ void schedule_own_packet(struct hard_iface *hard_iface)
303 prepare_packet_buffer(bat_priv, hard_iface); 303 prepare_packet_buffer(bat_priv, hard_iface);
304 /* Increment the TTVN only once per OGM interval */ 304 /* Increment the TTVN only once per OGM interval */
305 atomic_inc(&bat_priv->ttvn); 305 atomic_inc(&bat_priv->ttvn);
306 bat_priv->tt_poss_change = false;
306 } 307 }
307 308
308 /* if the changes have been sent enough times */ 309 /* if the changes have been sent enough times */
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index c288d937a154..3371ece680a2 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", false);
538 tt_local_add(dev, addr->sa_data); 538 tt_local_add(dev, addr->sa_data);
539 } 539 }
540 540
@@ -836,6 +836,7 @@ struct net_device *softif_create(const char *name)
836 836
837 bat_priv->tt_buff = NULL; 837 bat_priv->tt_buff = NULL;
838 bat_priv->tt_buff_len = 0; 838 bat_priv->tt_buff_len = 0;
839 bat_priv->tt_poss_change = false;
839 840
840 bat_priv->primary_if = NULL; 841 bat_priv->primary_if = NULL;
841 bat_priv->num_ifaces = 0; 842 bat_priv->num_ifaces = 0;
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 597cd1a43058..d516d8591cfc 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -126,7 +126,7 @@ static bool is_out_of_time(unsigned long starting_time, unsigned long timeout)
126} 126}
127 127
128static void tt_local_event(struct bat_priv *bat_priv, uint8_t op, 128static void tt_local_event(struct bat_priv *bat_priv, uint8_t op,
129 const uint8_t *addr) 129 const uint8_t *addr, uint8_t roaming)
130{ 130{
131 struct tt_change_node *tt_change_node; 131 struct tt_change_node *tt_change_node;
132 132
@@ -136,6 +136,9 @@ static void tt_local_event(struct bat_priv *bat_priv, uint8_t op,
136 return; 136 return;
137 137
138 tt_change_node->change.flags = op; 138 tt_change_node->change.flags = op;
139 if (roaming)
140 tt_change_node->change.flags |= TT_CLIENT_ROAM;
141
139 memcpy(tt_change_node->change.addr, addr, ETH_ALEN); 142 memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
140 143
141 spin_lock_bh(&bat_priv->tt_changes_list_lock); 144 spin_lock_bh(&bat_priv->tt_changes_list_lock);
@@ -170,6 +173,7 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
170 struct bat_priv *bat_priv = netdev_priv(soft_iface); 173 struct bat_priv *bat_priv = netdev_priv(soft_iface);
171 struct tt_local_entry *tt_local_entry; 174 struct tt_local_entry *tt_local_entry;
172 struct tt_global_entry *tt_global_entry; 175 struct tt_global_entry *tt_global_entry;
176 uint8_t roam_addr[ETH_ALEN];
173 177
174 spin_lock_bh(&bat_priv->tt_lhash_lock); 178 spin_lock_bh(&bat_priv->tt_lhash_lock);
175 tt_local_entry = tt_local_hash_find(bat_priv, addr); 179 tt_local_entry = tt_local_hash_find(bat_priv, addr);
@@ -183,7 +187,7 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
183 if (!tt_local_entry) 187 if (!tt_local_entry)
184 goto unlock; 188 goto unlock;
185 189
186 tt_local_event(bat_priv, NO_FLAGS, addr); 190 tt_local_event(bat_priv, NO_FLAGS, addr, false);
187 191
188 bat_dbg(DBG_TT, bat_priv, 192 bat_dbg(DBG_TT, bat_priv,
189 "Creating new local tt entry: %pM (ttvn: %d)\n", addr, 193 "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
@@ -208,11 +212,19 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
208 212
209 tt_global_entry = tt_global_hash_find(bat_priv, addr); 213 tt_global_entry = tt_global_hash_find(bat_priv, addr);
210 214
211 if (tt_global_entry) 215 /* Check whether it is a roaming! */
216 if (tt_global_entry) {
217 memcpy(roam_addr, tt_global_entry->addr, ETH_ALEN);
218 /* This node is probably going to update its tt table */
219 tt_global_entry->orig_node->tt_poss_change = true;
212 _tt_global_del(bat_priv, tt_global_entry, 220 _tt_global_del(bat_priv, tt_global_entry,
213 "local tt received"); 221 "local tt received");
222 spin_unlock_bh(&bat_priv->tt_ghash_lock);
223 send_roam_adv(bat_priv, tt_global_entry->addr,
224 tt_global_entry->orig_node);
225 } else
226 spin_unlock_bh(&bat_priv->tt_ghash_lock);
214 227
215 spin_unlock_bh(&bat_priv->tt_ghash_lock);
216 return; 228 return;
217unlock: 229unlock:
218 spin_unlock_bh(&bat_priv->tt_lhash_lock); 230 spin_unlock_bh(&bat_priv->tt_lhash_lock);
@@ -367,7 +379,7 @@ static void tt_local_del(struct bat_priv *bat_priv,
367} 379}
368 380
369void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, 381void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
370 const char *message) 382 const char *message, bool roaming)
371{ 383{
372 struct tt_local_entry *tt_local_entry; 384 struct tt_local_entry *tt_local_entry;
373 385
@@ -375,7 +387,8 @@ void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
375 tt_local_entry = tt_local_hash_find(bat_priv, addr); 387 tt_local_entry = tt_local_hash_find(bat_priv, addr);
376 388
377 if (tt_local_entry) { 389 if (tt_local_entry) {
378 tt_local_event(bat_priv, TT_CHANGE_DEL, tt_local_entry->addr); 390 tt_local_event(bat_priv, TT_CHANGE_DEL, tt_local_entry->addr,
391 roaming);
379 tt_local_del(bat_priv, tt_local_entry, message); 392 tt_local_del(bat_priv, tt_local_entry, message);
380 } 393 }
381 spin_unlock_bh(&bat_priv->tt_lhash_lock); 394 spin_unlock_bh(&bat_priv->tt_lhash_lock);
@@ -404,7 +417,7 @@ static void tt_local_purge(struct bat_priv *bat_priv)
404 continue; 417 continue;
405 418
406 tt_local_event(bat_priv, TT_CHANGE_DEL, 419 tt_local_event(bat_priv, TT_CHANGE_DEL,
407 tt_local_entry->addr); 420 tt_local_entry->addr, false);
408 tt_local_del(bat_priv, tt_local_entry, 421 tt_local_del(bat_priv, tt_local_entry,
409 "address timed out"); 422 "address timed out");
410 } 423 }
@@ -476,7 +489,7 @@ static void tt_changes_list_free(struct bat_priv *bat_priv)
476 489
477/* caller must hold orig_node refcount */ 490/* caller must hold orig_node refcount */
478int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, 491int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
479 const unsigned char *tt_addr, uint8_t ttvn) 492 const unsigned char *tt_addr, uint8_t ttvn, bool roaming)
480{ 493{
481 struct tt_global_entry *tt_global_entry; 494 struct tt_global_entry *tt_global_entry;
482 struct tt_local_entry *tt_local_entry; 495 struct tt_local_entry *tt_local_entry;
@@ -496,6 +509,8 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
496 atomic_inc(&orig_node->refcount); 509 atomic_inc(&orig_node->refcount);
497 tt_global_entry->orig_node = orig_node; 510 tt_global_entry->orig_node = orig_node;
498 tt_global_entry->ttvn = ttvn; 511 tt_global_entry->ttvn = ttvn;
512 tt_global_entry->flags = NO_FLAGS;
513 tt_global_entry->roam_at = 0;
499 atomic_inc(&orig_node->tt_size); 514 atomic_inc(&orig_node->tt_size);
500 hash_add(bat_priv->tt_global_hash, compare_gtt, 515 hash_add(bat_priv->tt_global_hash, compare_gtt,
501 choose_orig, tt_global_entry, 516 choose_orig, tt_global_entry,
@@ -506,10 +521,12 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
506 orig_node_tmp = tt_global_entry->orig_node; 521 orig_node_tmp = tt_global_entry->orig_node;
507 atomic_inc(&orig_node->refcount); 522 atomic_inc(&orig_node->refcount);
508 tt_global_entry->orig_node = orig_node; 523 tt_global_entry->orig_node = orig_node;
509 tt_global_entry->ttvn = ttvn;
510 orig_node_free_ref(orig_node_tmp); 524 orig_node_free_ref(orig_node_tmp);
511 atomic_inc(&orig_node->tt_size); 525 atomic_inc(&orig_node->tt_size);
512 } 526 }
527 tt_global_entry->ttvn = ttvn;
528 tt_global_entry->flags = NO_FLAGS;
529 tt_global_entry->roam_at = 0;
513 } 530 }
514 531
515 spin_unlock_bh(&bat_priv->tt_ghash_lock); 532 spin_unlock_bh(&bat_priv->tt_ghash_lock);
@@ -523,8 +540,9 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
523 tt_local_entry = tt_local_hash_find(bat_priv, tt_addr); 540 tt_local_entry = tt_local_hash_find(bat_priv, tt_addr);
524 541
525 if (tt_local_entry) 542 if (tt_local_entry)
526 tt_local_del(bat_priv, tt_local_entry, 543 tt_local_remove(bat_priv, tt_global_entry->addr,
527 "global tt received"); 544 "global tt received", roaming);
545
528 spin_unlock_bh(&bat_priv->tt_lhash_lock); 546 spin_unlock_bh(&bat_priv->tt_lhash_lock);
529 return 1; 547 return 1;
530unlock: 548unlock:
@@ -637,7 +655,7 @@ static void _tt_global_del(struct bat_priv *bat_priv,
637 655
638void tt_global_del(struct bat_priv *bat_priv, 656void tt_global_del(struct bat_priv *bat_priv,
639 struct orig_node *orig_node, const unsigned char *addr, 657 struct orig_node *orig_node, const unsigned char *addr,
640 const char *message) 658 const char *message, bool roaming)
641{ 659{
642 struct tt_global_entry *tt_global_entry; 660 struct tt_global_entry *tt_global_entry;
643 661
@@ -645,9 +663,15 @@ void tt_global_del(struct bat_priv *bat_priv,
645 tt_global_entry = tt_global_hash_find(bat_priv, addr); 663 tt_global_entry = tt_global_hash_find(bat_priv, addr);
646 664
647 if (tt_global_entry && tt_global_entry->orig_node == orig_node) { 665 if (tt_global_entry && tt_global_entry->orig_node == orig_node) {
666 if (roaming) {
667 tt_global_entry->flags |= TT_CLIENT_ROAM;
668 tt_global_entry->roam_at = jiffies;
669 goto out;
670 }
648 atomic_dec(&orig_node->tt_size); 671 atomic_dec(&orig_node->tt_size);
649 _tt_global_del(bat_priv, tt_global_entry, message); 672 _tt_global_del(bat_priv, tt_global_entry, message);
650 } 673 }
674out:
651 spin_unlock_bh(&bat_priv->tt_ghash_lock); 675 spin_unlock_bh(&bat_priv->tt_ghash_lock);
652} 676}
653 677
@@ -685,6 +709,35 @@ static void tt_global_entry_free(struct hlist_node *node, void *arg)
685 kfree(data); 709 kfree(data);
686} 710}
687 711
712static void tt_global_roam_purge(struct bat_priv *bat_priv)
713{
714 struct hashtable_t *hash = bat_priv->tt_global_hash;
715 struct tt_global_entry *tt_global_entry;
716 struct hlist_node *node, *node_tmp;
717 struct hlist_head *head;
718 int i;
719
720 spin_lock_bh(&bat_priv->tt_ghash_lock);
721
722 for (i = 0; i < hash->size; i++) {
723 head = &hash->table[i];
724
725 hlist_for_each_entry_safe(tt_global_entry, node, node_tmp,
726 head, hash_entry) {
727 if (!(tt_global_entry->flags & TT_CLIENT_ROAM))
728 continue;
729 if (!is_out_of_time(tt_global_entry->roam_at,
730 TT_CLIENT_ROAM_TIMEOUT * 1000))
731 continue;
732
733 _tt_global_del(bat_priv, tt_global_entry,
734 "Roaming timeout");
735 }
736 }
737
738 spin_unlock_bh(&bat_priv->tt_ghash_lock);
739}
740
688static void tt_global_table_free(struct bat_priv *bat_priv) 741static void tt_global_table_free(struct bat_priv *bat_priv)
689{ 742{
690 if (!bat_priv->tt_global_hash) 743 if (!bat_priv->tt_global_hash)
@@ -734,6 +787,12 @@ uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
734 head, hash_entry) { 787 head, hash_entry) {
735 if (compare_eth(tt_global_entry->orig_node, 788 if (compare_eth(tt_global_entry->orig_node,
736 orig_node)) { 789 orig_node)) {
790 /* Roaming clients are in the global table for
791 * consistency only. They don't have to be
792 * taken into account while computing the
793 * global crc */
794 if (tt_global_entry->flags & TT_CLIENT_ROAM)
795 continue;
737 total_one = 0; 796 total_one = 0;
738 for (j = 0; j < ETH_ALEN; j++) 797 for (j = 0; j < ETH_ALEN; j++)
739 total_one = crc16_byte(total_one, 798 total_one = crc16_byte(total_one,
@@ -858,6 +917,9 @@ static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
858 const struct tt_global_entry *tt_global_entry = entry_ptr; 917 const struct tt_global_entry *tt_global_entry = entry_ptr;
859 const struct orig_node *orig_node = data_ptr; 918 const struct orig_node *orig_node = data_ptr;
860 919
920 if (tt_global_entry->flags & TT_CLIENT_ROAM)
921 return 0;
922
861 return (tt_global_entry->orig_node == orig_node); 923 return (tt_global_entry->orig_node == orig_node);
862} 924}
863 925
@@ -1251,10 +1313,11 @@ static void _tt_update_changes(struct bat_priv *bat_priv,
1251 if ((tt_change + i)->flags & TT_CHANGE_DEL) 1313 if ((tt_change + i)->flags & TT_CHANGE_DEL)
1252 tt_global_del(bat_priv, orig_node, 1314 tt_global_del(bat_priv, orig_node,
1253 (tt_change + i)->addr, 1315 (tt_change + i)->addr,
1254 "tt removed by changes"); 1316 "tt removed by changes",
1317 (tt_change + i)->flags & TT_CLIENT_ROAM);
1255 else 1318 else
1256 if (!tt_global_add(bat_priv, orig_node, 1319 if (!tt_global_add(bat_priv, orig_node,
1257 (tt_change + i)->addr, ttvn)) 1320 (tt_change + i)->addr, ttvn, false))
1258 /* In case of problem while storing a 1321 /* In case of problem while storing a
1259 * global_entry, we stop the updating 1322 * global_entry, we stop the updating
1260 * procedure without committing the 1323 * procedure without committing the
@@ -1356,6 +1419,9 @@ void handle_tt_response(struct bat_priv *bat_priv,
1356 spin_lock_bh(&bat_priv->tt_ghash_lock); 1419 spin_lock_bh(&bat_priv->tt_ghash_lock);
1357 orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); 1420 orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
1358 spin_unlock_bh(&bat_priv->tt_ghash_lock); 1421 spin_unlock_bh(&bat_priv->tt_ghash_lock);
1422 /* Roaming phase is over: tables are in sync again. I can
1423 * unset the flag */
1424 orig_node->tt_poss_change = false;
1359out: 1425out:
1360 if (orig_node) 1426 if (orig_node)
1361 orig_node_free_ref(orig_node); 1427 orig_node_free_ref(orig_node);
@@ -1374,16 +1440,134 @@ int tt_init(struct bat_priv *bat_priv)
1374 return 1; 1440 return 1;
1375} 1441}
1376 1442
1377void tt_free(struct bat_priv *bat_priv) 1443static void tt_roam_list_free(struct bat_priv *bat_priv)
1378{ 1444{
1379 cancel_delayed_work_sync(&bat_priv->tt_work); 1445 struct tt_roam_node *node, *safe;
1380 1446
1381 tt_local_table_free(bat_priv); 1447 spin_lock_bh(&bat_priv->tt_roam_list_lock);
1382 tt_global_table_free(bat_priv);
1383 tt_req_list_free(bat_priv);
1384 tt_changes_list_free(bat_priv);
1385 1448
1386 kfree(bat_priv->tt_buff); 1449 list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1450 list_del(&node->list);
1451 kfree(node);
1452 }
1453
1454 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1455}
1456
1457static void tt_roam_purge(struct bat_priv *bat_priv)
1458{
1459 struct tt_roam_node *node, *safe;
1460
1461 spin_lock_bh(&bat_priv->tt_roam_list_lock);
1462 list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
1463 if (!is_out_of_time(node->first_time,
1464 ROAMING_MAX_TIME * 1000))
1465 continue;
1466
1467 list_del(&node->list);
1468 kfree(node);
1469 }
1470 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1471}
1472
1473/* This function checks whether the client already reached the
1474 * maximum number of possible roaming phases. In this case the ROAMING_ADV
1475 * will not be sent.
1476 *
1477 * returns true if the ROAMING_ADV can be sent, false otherwise */
1478static bool tt_check_roam_count(struct bat_priv *bat_priv,
1479 uint8_t *client)
1480{
1481 struct tt_roam_node *tt_roam_node;
1482 bool ret = false;
1483
1484 spin_lock_bh(&bat_priv->tt_roam_list_lock);
1485 /* The new tt_req will be issued only if I'm not waiting for a
1486 * reply from the same orig_node yet */
1487 list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) {
1488 if (!compare_eth(tt_roam_node->addr, client))
1489 continue;
1490
1491 if (is_out_of_time(tt_roam_node->first_time,
1492 ROAMING_MAX_TIME * 1000))
1493 continue;
1494
1495 if (!atomic_dec_not_zero(&tt_roam_node->counter))
1496 /* Sorry, you roamed too many times! */
1497 goto unlock;
1498 ret = true;
1499 break;
1500 }
1501
1502 if (!ret) {
1503 tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
1504 if (!tt_roam_node)
1505 goto unlock;
1506
1507 tt_roam_node->first_time = jiffies;
1508 atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1);
1509 memcpy(tt_roam_node->addr, client, ETH_ALEN);
1510
1511 list_add(&tt_roam_node->list, &bat_priv->tt_roam_list);
1512 ret = true;
1513 }
1514
1515unlock:
1516 spin_unlock_bh(&bat_priv->tt_roam_list_lock);
1517 return ret;
1518}
1519
1520void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
1521 struct orig_node *orig_node)
1522{
1523 struct neigh_node *neigh_node = NULL;
1524 struct sk_buff *skb = NULL;
1525 struct roam_adv_packet *roam_adv_packet;
1526 int ret = 1;
1527 struct hard_iface *primary_if;
1528
1529 /* before going on we have to check whether the client has
1530 * already roamed to us too many times */
1531 if (!tt_check_roam_count(bat_priv, client))
1532 goto out;
1533
1534 skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
1535 if (!skb)
1536 goto out;
1537
1538 skb_reserve(skb, ETH_HLEN);
1539
1540 roam_adv_packet = (struct roam_adv_packet *)skb_put(skb,
1541 sizeof(struct roam_adv_packet));
1542
1543 roam_adv_packet->packet_type = BAT_ROAM_ADV;
1544 roam_adv_packet->version = COMPAT_VERSION;
1545 roam_adv_packet->ttl = TTL;
1546 primary_if = primary_if_get_selected(bat_priv);
1547 if (!primary_if)
1548 goto out;
1549 memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
1550 hardif_free_ref(primary_if);
1551 memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN);
1552 memcpy(roam_adv_packet->client, client, ETH_ALEN);
1553
1554 neigh_node = orig_node_get_router(orig_node);
1555 if (!neigh_node)
1556 goto out;
1557
1558 bat_dbg(DBG_TT, bat_priv,
1559 "Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
1560 orig_node->orig, client, neigh_node->addr);
1561
1562 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
1563 ret = 0;
1564
1565out:
1566 if (neigh_node)
1567 neigh_node_free_ref(neigh_node);
1568 if (ret)
1569 kfree_skb(skb);
1570 return;
1387} 1571}
1388 1572
1389static void tt_purge(struct work_struct *work) 1573static void tt_purge(struct work_struct *work)
@@ -1394,7 +1578,22 @@ static void tt_purge(struct work_struct *work)
1394 container_of(delayed_work, struct bat_priv, tt_work); 1578 container_of(delayed_work, struct bat_priv, tt_work);
1395 1579
1396 tt_local_purge(bat_priv); 1580 tt_local_purge(bat_priv);
1581 tt_global_roam_purge(bat_priv);
1397 tt_req_purge(bat_priv); 1582 tt_req_purge(bat_priv);
1583 tt_roam_purge(bat_priv);
1398 1584
1399 tt_start_timer(bat_priv); 1585 tt_start_timer(bat_priv);
1400} 1586}
1587
1588void tt_free(struct bat_priv *bat_priv)
1589{
1590 cancel_delayed_work_sync(&bat_priv->tt_work);
1591
1592 tt_local_table_free(bat_priv);
1593 tt_global_table_free(bat_priv);
1594 tt_req_list_free(bat_priv);
1595 tt_changes_list_free(bat_priv);
1596 tt_roam_list_free(bat_priv);
1597
1598 kfree(bat_priv->tt_buff);
1599}
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h
index 51f7e3060f6f..1cd2d39529fe 100644
--- a/net/batman-adv/translation-table.h
+++ b/net/batman-adv/translation-table.h
@@ -28,20 +28,20 @@ int tt_changes_fill_buffer(struct bat_priv *bat_priv,
28int tt_init(struct bat_priv *bat_priv); 28int tt_init(struct bat_priv *bat_priv);
29void 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);
30void tt_local_remove(struct bat_priv *bat_priv, 30void tt_local_remove(struct bat_priv *bat_priv,
31 const uint8_t *addr, const char *message); 31 const uint8_t *addr, const char *message, bool roaming);
32int tt_local_seq_print_text(struct seq_file *seq, void *offset); 32int tt_local_seq_print_text(struct seq_file *seq, void *offset);
33void tt_global_add_orig(struct bat_priv *bat_priv, 33void tt_global_add_orig(struct bat_priv *bat_priv,
34 struct orig_node *orig_node, 34 struct orig_node *orig_node,
35 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, 36int tt_global_add(struct bat_priv *bat_priv,
37 struct orig_node *orig_node, const unsigned char *addr, 37 struct orig_node *orig_node, const unsigned char *addr,
38 uint8_t ttvn); 38 uint8_t ttvn, bool roaming);
39int tt_global_seq_print_text(struct seq_file *seq, void *offset); 39int tt_global_seq_print_text(struct seq_file *seq, void *offset);
40void tt_global_del_orig(struct bat_priv *bat_priv, 40void tt_global_del_orig(struct bat_priv *bat_priv,
41 struct orig_node *orig_node, const char *message); 41 struct orig_node *orig_node, const char *message);
42void tt_global_del(struct bat_priv *bat_priv, 42void tt_global_del(struct bat_priv *bat_priv,
43 struct orig_node *orig_node, const unsigned char *addr, 43 struct orig_node *orig_node, const unsigned char *addr,
44 const char *message); 44 const char *message, bool roaming);
45struct orig_node *transtable_search(struct bat_priv *bat_priv, 45struct orig_node *transtable_search(struct bat_priv *bat_priv,
46 const uint8_t *addr); 46 const uint8_t *addr);
47void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node, 47void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
@@ -60,5 +60,7 @@ void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig_node,
60bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr); 60bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr);
61void handle_tt_response(struct bat_priv *bat_priv, 61void handle_tt_response(struct bat_priv *bat_priv,
62 struct tt_query_packet *tt_response); 62 struct tt_query_packet *tt_response);
63void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
64 struct orig_node *orig_node);
63 65
64#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ 66#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 3b642a9e086e..9c84fa9f0968 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -81,6 +81,12 @@ struct orig_node {
81 int16_t tt_buff_len; 81 int16_t tt_buff_len;
82 spinlock_t tt_buff_lock; /* protects tt_buff */ 82 spinlock_t tt_buff_lock; /* protects tt_buff */
83 atomic_t tt_size; 83 atomic_t tt_size;
84 /* The tt_poss_change flag is used to detect an ongoing roaming phase.
85 * If true, then I sent a Roaming_adv to this orig_node and I have to
86 * inspect every packet directed to it to check whether it is still
87 * the true destination or not. This flag will be reset to false as
88 * soon as I receive a new TTVN from this orig_node */
89 bool tt_poss_change;
84 uint32_t last_real_seqno; 90 uint32_t last_real_seqno;
85 uint8_t last_ttl; 91 uint8_t last_ttl;
86 unsigned long bcast_bits[NUM_WORDS]; 92 unsigned long bcast_bits[NUM_WORDS];
@@ -153,6 +159,12 @@ struct bat_priv {
153 atomic_t ttvn; /* tranlation table version number */ 159 atomic_t ttvn; /* tranlation table version number */
154 atomic_t tt_ogm_append_cnt; 160 atomic_t tt_ogm_append_cnt;
155 atomic_t tt_local_changes; /* changes registered in a OGM interval */ 161 atomic_t tt_local_changes; /* changes registered in a OGM interval */
162 /* The tt_poss_change flag is used to detect an ongoing roaming phase.
163 * If true, then I received a Roaming_adv and I have to inspect every
164 * packet directed to me to check whether I am still the true
165 * destination or not. This flag will be reset to false as soon as I
166 * increase my TTVN */
167 bool tt_poss_change;
156 char num_ifaces; 168 char num_ifaces;
157 struct debug_log *debug_log; 169 struct debug_log *debug_log;
158 struct kobject *mesh_obj; 170 struct kobject *mesh_obj;
@@ -167,6 +179,7 @@ struct bat_priv {
167 struct hashtable_t *tt_local_hash; 179 struct hashtable_t *tt_local_hash;
168 struct hashtable_t *tt_global_hash; 180 struct hashtable_t *tt_global_hash;
169 struct list_head tt_req_list; /* list of pending tt_requests */ 181 struct list_head tt_req_list; /* list of pending tt_requests */
182 struct list_head tt_roam_list;
170 struct hashtable_t *vis_hash; 183 struct hashtable_t *vis_hash;
171 spinlock_t forw_bat_list_lock; /* protects forw_bat_list */ 184 spinlock_t forw_bat_list_lock; /* protects forw_bat_list */
172 spinlock_t forw_bcast_list_lock; /* protects */ 185 spinlock_t forw_bcast_list_lock; /* protects */
@@ -174,6 +187,7 @@ struct bat_priv {
174 spinlock_t tt_lhash_lock; /* protects tt_local_hash */ 187 spinlock_t tt_lhash_lock; /* protects tt_local_hash */
175 spinlock_t tt_ghash_lock; /* protects tt_global_hash */ 188 spinlock_t tt_ghash_lock; /* protects tt_global_hash */
176 spinlock_t tt_req_list_lock; /* protects tt_req_list */ 189 spinlock_t tt_req_list_lock; /* protects tt_req_list */
190 spinlock_t tt_roam_list_lock; /* protects tt_roam_list */
177 spinlock_t gw_list_lock; /* protects gw_list and curr_gw */ 191 spinlock_t gw_list_lock; /* protects gw_list and curr_gw */
178 spinlock_t vis_hash_lock; /* protects vis_hash */ 192 spinlock_t vis_hash_lock; /* protects vis_hash */
179 spinlock_t vis_list_lock; /* protects vis_info::recv_list */ 193 spinlock_t vis_list_lock; /* protects vis_info::recv_list */
@@ -219,8 +233,9 @@ struct tt_global_entry {
219 uint8_t addr[ETH_ALEN]; 233 uint8_t addr[ETH_ALEN];
220 struct orig_node *orig_node; 234 struct orig_node *orig_node;
221 uint8_t ttvn; 235 uint8_t ttvn;
222 /* entry in the global table */ 236 uint8_t flags; /* only TT_GLOBAL_ROAM is used */
223 struct hlist_node hash_entry; 237 unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */
238 struct hlist_node hash_entry; /* entry in the global table */
224}; 239};
225 240
226struct tt_change_node { 241struct tt_change_node {
@@ -234,6 +249,13 @@ struct tt_req_node {
234 struct list_head list; 249 struct list_head list;
235}; 250};
236 251
252struct tt_roam_node {
253 uint8_t addr[ETH_ALEN];
254 atomic_t counter;
255 unsigned long first_time;
256 struct list_head list;
257};
258
237/** 259/**
238 * forw_packet - structure for forw_list maintaining packets to be 260 * forw_packet - structure for forw_list maintaining packets to be
239 * send/forwarded 261 * send/forwarded