diff options
Diffstat (limited to 'net/batman-adv/translation-table.c')
-rw-r--r-- | net/batman-adv/translation-table.c | 127 |
1 files changed, 95 insertions, 32 deletions
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, | |||
34 | static void batadv_tt_purge(struct work_struct *work); | 34 | static void batadv_tt_purge(struct work_struct *work); |
35 | static void | 35 | static void |
36 | batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry); | 36 | batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry); |
37 | static 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 */ |
39 | static int batadv_compare_tt(const struct hlist_node *node, const void *data2) | 43 | static 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 | ||
1062 | static void batadv_tt_global_roam_purge_list(struct batadv_priv *bat_priv, | 1085 | static 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 | ||
1089 | static void batadv_tt_global_roam_purge(struct batadv_priv *bat_priv) | 1107 | static 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 | ||
1107 | static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) | 1144 | static 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, | |||
2399 | out: | 2443 | out: |
2400 | return ret; | 2444 | return ret; |
2401 | } | 2445 | } |
2446 | |||
2447 | bool 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; | ||
2462 | out: | ||
2463 | return ret; | ||
2464 | } | ||