aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntonio Quartulli <ordex@autistici.org>2012-07-05 17:38:29 -0400
committerAntonio Quartulli <ordex@autistici.org>2012-08-23 08:20:22 -0400
commit30cfd02b60e1cb16f5effb0a01f826c5bb7e4c59 (patch)
treedf702e35ab213c98ae4090343e28c1afbd17e207
parentc67893d17a6bbd16328a1ee38ab0cb460511014a (diff)
batman-adv: detect not yet announced clients
With the current TT mechanism a new client joining the network is not immediately able to communicate with other hosts because its MAC address has not been announced yet. This situation holds until the first OGM containing its joining event will be spread over the mesh network. This behaviour can be acceptable in networks where the originator interval is a small value (e.g. 1sec) but if that value is set to an higher time (e.g. 5secs) the client could suffer from several malfunctions like DHCP client timeouts, etc. This patch adds an early detection mechanism that makes nodes in the network able to recognise "not yet announced clients" by means of the broadcast packets they emitted on connection (e.g. ARP or DHCP request). The added client will then be confirmed upon receiving the OGM claiming it or purged if such OGM is not received within a fixed amount of time. Signed-off-by: Antonio Quartulli <ordex@autistici.org>
-rw-r--r--net/batman-adv/main.h1
-rw-r--r--net/batman-adv/packet.h1
-rw-r--r--net/batman-adv/translation-table.c127
-rw-r--r--net/batman-adv/translation-table.h4
-rw-r--r--net/batman-adv/types.h1
5 files changed, 101 insertions, 33 deletions
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index 574fca1bd434..61a0cfd3ceb4 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -43,6 +43,7 @@
43#define BATADV_PURGE_TIMEOUT 200000 /* 200 seconds */ 43#define BATADV_PURGE_TIMEOUT 200000 /* 200 seconds */
44#define BATADV_TT_LOCAL_TIMEOUT 3600000 /* in milliseconds */ 44#define BATADV_TT_LOCAL_TIMEOUT 3600000 /* in milliseconds */
45#define BATADV_TT_CLIENT_ROAM_TIMEOUT 600000 /* in milliseconds */ 45#define BATADV_TT_CLIENT_ROAM_TIMEOUT 600000 /* in milliseconds */
46#define BATADV_TT_CLIENT_TEMP_TIMEOUT 600000 /* in milliseconds */
46/* sliding packet range of received originator messages in sequence numbers 47/* sliding packet range of received originator messages in sequence numbers
47 * (should be a multiple of our word size) 48 * (should be a multiple of our word size)
48 */ 49 */
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
index eb4593413b73..2d23a14c220e 100644
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@ -85,6 +85,7 @@ enum batadv_tt_client_flags {
85 BATADV_TT_CLIENT_DEL = BIT(0), 85 BATADV_TT_CLIENT_DEL = BIT(0),
86 BATADV_TT_CLIENT_ROAM = BIT(1), 86 BATADV_TT_CLIENT_ROAM = BIT(1),
87 BATADV_TT_CLIENT_WIFI = BIT(2), 87 BATADV_TT_CLIENT_WIFI = BIT(2),
88 BATADV_TT_CLIENT_TEMP = BIT(3),
88 BATADV_TT_CLIENT_NOPURGE = BIT(8), 89 BATADV_TT_CLIENT_NOPURGE = BIT(8),
89 BATADV_TT_CLIENT_NEW = BIT(9), 90 BATADV_TT_CLIENT_NEW = BIT(9),
90 BATADV_TT_CLIENT_PENDING = BIT(10), 91 BATADV_TT_CLIENT_PENDING = BIT(10),
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index cb429d181f4d..112edd371b2f 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -34,6 +34,10 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client,
34static void batadv_tt_purge(struct work_struct *work); 34static void batadv_tt_purge(struct work_struct *work);
35static void 35static void
36batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry); 36batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry);
37static void batadv_tt_global_del(struct batadv_priv *bat_priv,
38 struct batadv_orig_node *orig_node,
39 const unsigned char *addr,
40 const char *message, bool roaming);
37 41
38/* returns 1 if they are the same mac addr */ 42/* returns 1 if they are the same mac addr */
39static int batadv_compare_tt(const struct hlist_node *node, const void *data2) 43static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
@@ -268,6 +272,7 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
268 tt_local_entry->common.flags |= BATADV_TT_CLIENT_WIFI; 272 tt_local_entry->common.flags |= BATADV_TT_CLIENT_WIFI;
269 atomic_set(&tt_local_entry->common.refcount, 2); 273 atomic_set(&tt_local_entry->common.refcount, 2);
270 tt_local_entry->last_seen = jiffies; 274 tt_local_entry->last_seen = jiffies;
275 tt_local_entry->common.added_at = tt_local_entry->last_seen;
271 276
272 /* the batman interface mac address should never be purged */ 277 /* the batman interface mac address should never be purged */
273 if (batadv_compare_eth(addr, soft_iface->dev_addr)) 278 if (batadv_compare_eth(addr, soft_iface->dev_addr))
@@ -682,8 +687,13 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
682 struct batadv_tt_orig_list_entry *orig_entry; 687 struct batadv_tt_orig_list_entry *orig_entry;
683 688
684 orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node); 689 orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node);
685 if (orig_entry) 690 if (orig_entry) {
691 /* refresh the ttvn: the current value could be a bogus one that
692 * was added during a "temporary client detection"
693 */
694 orig_entry->ttvn = ttvn;
686 goto out; 695 goto out;
696 }
687 697
688 orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC); 698 orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC);
689 if (!orig_entry) 699 if (!orig_entry)
@@ -729,6 +739,7 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
729 common->flags = flags; 739 common->flags = flags;
730 tt_global_entry->roam_at = 0; 740 tt_global_entry->roam_at = 0;
731 atomic_set(&common->refcount, 2); 741 atomic_set(&common->refcount, 2);
742 common->added_at = jiffies;
732 743
733 INIT_HLIST_HEAD(&tt_global_entry->orig_list); 744 INIT_HLIST_HEAD(&tt_global_entry->orig_list);
734 spin_lock_init(&tt_global_entry->list_lock); 745 spin_lock_init(&tt_global_entry->list_lock);
@@ -744,7 +755,19 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
744 goto out_remove; 755 goto out_remove;
745 } 756 }
746 } else { 757 } else {
747 /* there is already a global entry, use this one. */ 758 /* If there is already a global entry, we can use this one for
759 * our processing.
760 * But if we are trying to add a temporary client we can exit
761 * directly because the temporary information should never
762 * override any already known client state (whatever it is)
763 */
764 if (flags & BATADV_TT_CLIENT_TEMP)
765 goto out;
766
767 /* if the client was temporary added before receiving the first
768 * OGM announcing it, we have to clear the TEMP flag
769 */
770 tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_TEMP;
748 771
749 /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only 772 /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
750 * one originator left in the list and we previously received a 773 * one originator left in the list and we previously received a
@@ -758,9 +781,8 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
758 tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM; 781 tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
759 tt_global_entry->roam_at = 0; 782 tt_global_entry->roam_at = 0;
760 } 783 }
761
762 } 784 }
763 /* add the new orig_entry (if needed) */ 785 /* add the new orig_entry (if needed) or update it */
764 batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); 786 batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn);
765 787
766 batadv_dbg(BATADV_DBG_TT, bat_priv, 788 batadv_dbg(BATADV_DBG_TT, bat_priv,
@@ -800,11 +822,12 @@ batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry,
800 hlist_for_each_entry_rcu(orig_entry, node, head, list) { 822 hlist_for_each_entry_rcu(orig_entry, node, head, list) {
801 flags = tt_common_entry->flags; 823 flags = tt_common_entry->flags;
802 last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); 824 last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
803 seq_printf(seq, " * %pM (%3u) via %pM (%3u) [%c%c]\n", 825 seq_printf(seq, " * %pM (%3u) via %pM (%3u) [%c%c%c]\n",
804 tt_global_entry->common.addr, orig_entry->ttvn, 826 tt_global_entry->common.addr, orig_entry->ttvn,
805 orig_entry->orig_node->orig, last_ttvn, 827 orig_entry->orig_node->orig, last_ttvn,
806 (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), 828 (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
807 (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.')); 829 (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
830 (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
808 } 831 }
809} 832}
810 833
@@ -1059,49 +1082,63 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
1059 orig_node->tt_initialised = false; 1082 orig_node->tt_initialised = false;
1060} 1083}
1061 1084
1062static void batadv_tt_global_roam_purge_list(struct batadv_priv *bat_priv, 1085static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
1063 struct hlist_head *head) 1086 char **msg)
1064{ 1087{
1065 struct batadv_tt_common_entry *tt_common_entry; 1088 bool purge = false;
1066 struct batadv_tt_global_entry *tt_global_entry; 1089 unsigned long roam_timeout = BATADV_TT_CLIENT_ROAM_TIMEOUT;
1067 struct hlist_node *node, *node_tmp; 1090 unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT;
1068 1091
1069 hlist_for_each_entry_safe(tt_common_entry, node, node_tmp, head, 1092 if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
1070 hash_entry) { 1093 batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
1071 tt_global_entry = container_of(tt_common_entry, 1094 purge = true;
1072 struct batadv_tt_global_entry, 1095 *msg = "Roaming timeout\n";
1073 common); 1096 }
1074 if (!(tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM))
1075 continue;
1076 if (!batadv_has_timed_out(tt_global_entry->roam_at,
1077 BATADV_TT_CLIENT_ROAM_TIMEOUT))
1078 continue;
1079
1080 batadv_dbg(BATADV_DBG_TT, bat_priv,
1081 "Deleting global tt entry (%pM): Roaming timeout\n",
1082 tt_global_entry->common.addr);
1083 1097
1084 hlist_del_rcu(node); 1098 if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
1085 batadv_tt_global_entry_free_ref(tt_global_entry); 1099 batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
1100 purge = true;
1101 *msg = "Temporary client timeout\n";
1086 } 1102 }
1103
1104 return purge;
1087} 1105}
1088 1106
1089static void batadv_tt_global_roam_purge(struct batadv_priv *bat_priv) 1107static void batadv_tt_global_purge(struct batadv_priv *bat_priv)
1090{ 1108{
1091 struct batadv_hashtable *hash = bat_priv->tt.global_hash; 1109 struct batadv_hashtable *hash = bat_priv->tt.global_hash;
1092 struct hlist_head *head; 1110 struct hlist_head *head;
1111 struct hlist_node *node, *node_tmp;
1093 spinlock_t *list_lock; /* protects write access to the hash lists */ 1112 spinlock_t *list_lock; /* protects write access to the hash lists */
1094 uint32_t i; 1113 uint32_t i;
1114 char *msg = NULL;
1115 struct batadv_tt_common_entry *tt_common;
1116 struct batadv_tt_global_entry *tt_global;
1095 1117
1096 for (i = 0; i < hash->size; i++) { 1118 for (i = 0; i < hash->size; i++) {
1097 head = &hash->table[i]; 1119 head = &hash->table[i];
1098 list_lock = &hash->list_locks[i]; 1120 list_lock = &hash->list_locks[i];
1099 1121
1100 spin_lock_bh(list_lock); 1122 spin_lock_bh(list_lock);
1101 batadv_tt_global_roam_purge_list(bat_priv, head); 1123 hlist_for_each_entry_safe(tt_common, node, node_tmp, head,
1124 hash_entry) {
1125 tt_global = container_of(tt_common,
1126 struct batadv_tt_global_entry,
1127 common);
1128
1129 if (!batadv_tt_global_to_purge(tt_global, &msg))
1130 continue;
1131
1132 batadv_dbg(BATADV_DBG_TT, bat_priv,
1133 "Deleting global tt entry (%pM): %s\n",
1134 tt_global->common.addr, msg);
1135
1136 hlist_del_rcu(node);
1137
1138 batadv_tt_global_entry_free_ref(tt_global);
1139 }
1102 spin_unlock_bh(list_lock); 1140 spin_unlock_bh(list_lock);
1103 } 1141 }
1104
1105} 1142}
1106 1143
1107static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) 1144static void batadv_tt_global_table_free(struct batadv_priv *bat_priv)
@@ -1239,6 +1276,12 @@ static uint16_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
1239 */ 1276 */
1240 if (tt_common->flags & BATADV_TT_CLIENT_ROAM) 1277 if (tt_common->flags & BATADV_TT_CLIENT_ROAM)
1241 continue; 1278 continue;
1279 /* Temporary clients have not been announced yet, so
1280 * they have to be skipped while computing the global
1281 * crc
1282 */
1283 if (tt_common->flags & BATADV_TT_CLIENT_TEMP)
1284 continue;
1242 1285
1243 /* find out if this global entry is announced by this 1286 /* find out if this global entry is announced by this
1244 * originator 1287 * originator
@@ -1392,7 +1435,8 @@ static int batadv_tt_global_valid(const void *entry_ptr,
1392 const struct batadv_tt_global_entry *tt_global_entry; 1435 const struct batadv_tt_global_entry *tt_global_entry;
1393 const struct batadv_orig_node *orig_node = data_ptr; 1436 const struct batadv_orig_node *orig_node = data_ptr;
1394 1437
1395 if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM) 1438 if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ||
1439 tt_common_entry->flags & BATADV_TT_CLIENT_TEMP)
1396 return 0; 1440 return 0;
1397 1441
1398 tt_global_entry = container_of(tt_common_entry, 1442 tt_global_entry = container_of(tt_common_entry,
@@ -2125,7 +2169,7 @@ static void batadv_tt_purge(struct work_struct *work)
2125 bat_priv = container_of(priv_tt, struct batadv_priv, tt); 2169 bat_priv = container_of(priv_tt, struct batadv_priv, tt);
2126 2170
2127 batadv_tt_local_purge(bat_priv); 2171 batadv_tt_local_purge(bat_priv);
2128 batadv_tt_global_roam_purge(bat_priv); 2172 batadv_tt_global_purge(bat_priv);
2129 batadv_tt_req_purge(bat_priv); 2173 batadv_tt_req_purge(bat_priv);
2130 batadv_tt_roam_purge(bat_priv); 2174 batadv_tt_roam_purge(bat_priv);
2131 2175
@@ -2399,3 +2443,22 @@ bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
2399out: 2443out:
2400 return ret; 2444 return ret;
2401} 2445}
2446
2447bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
2448 struct batadv_orig_node *orig_node,
2449 const unsigned char *addr)
2450{
2451 bool ret = false;
2452
2453 if (!batadv_tt_global_add(bat_priv, orig_node, addr,
2454 BATADV_TT_CLIENT_TEMP,
2455 atomic_read(&orig_node->last_ttvn)))
2456 goto out;
2457
2458 batadv_dbg(BATADV_DBG_TT, bat_priv,
2459 "Added temporary global client (addr: %pM orig: %pM)\n",
2460 addr, orig_node->orig);
2461 ret = true;
2462out:
2463 return ret;
2464}
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h
index ffa87355096b..811fffd4760c 100644
--- a/net/batman-adv/translation-table.h
+++ b/net/batman-adv/translation-table.h
@@ -59,6 +59,8 @@ int batadv_tt_append_diff(struct batadv_priv *bat_priv,
59 int packet_min_len); 59 int packet_min_len);
60bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, 60bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
61 uint8_t *addr); 61 uint8_t *addr);
62 62bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
63 struct batadv_orig_node *orig_node,
64 const unsigned char *addr);
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 97c4978dee69..2ed82caacdca 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -284,6 +284,7 @@ struct batadv_tt_common_entry {
284 uint8_t addr[ETH_ALEN]; 284 uint8_t addr[ETH_ALEN];
285 struct hlist_node hash_entry; 285 struct hlist_node hash_entry;
286 uint16_t flags; 286 uint16_t flags;
287 unsigned long added_at;
287 atomic_t refcount; 288 atomic_t refcount;
288 struct rcu_head rcu; 289 struct rcu_head rcu;
289}; 290};