Loading net/batman-adv/originator.c +2 −0 Original line number Diff line number Diff line Loading @@ -223,6 +223,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr) orig_node->bat_priv = bat_priv; memcpy(orig_node->orig, addr, ETH_ALEN); orig_node->router = NULL; orig_node->tt_crc = 0; atomic_set(&orig_node->last_ttvn, 0); orig_node->tt_buff = NULL; orig_node->tt_buff_len = 0; atomic_set(&orig_node->tt_size, 0); Loading net/batman-adv/packet.h +3 −1 Original line number Diff line number Diff line Loading @@ -84,7 +84,9 @@ enum tt_query_flags { enum tt_client_flags { TT_CLIENT_DEL = 1 << 0, TT_CLIENT_ROAM = 1 << 1, TT_CLIENT_NOPURGE = 1 << 8 TT_CLIENT_NOPURGE = 1 << 8, TT_CLIENT_NEW = 1 << 9, TT_CLIENT_PENDING = 1 << 10 }; struct batman_packet { Loading net/batman-adv/routing.c +12 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,18 @@ static void update_transtable(struct bat_priv *bat_priv, * to recompute it to spot any possible inconsistency * in the global table */ orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); /* The ttvn alone is not enough to guarantee consistency * because a single value could repesent different states * (due to the wrap around). Thus a node has to check whether * the resulting table (after applying the changes) is still * consistent or not. E.g. a node could disconnect while its * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case * checking the CRC value is mandatory to detect the * inconsistency */ if (orig_node->tt_crc != tt_crc) goto request_table; /* Roaming phase is over: tables are in sync again. I can * unset the flag */ orig_node->tt_poss_change = false; Loading net/batman-adv/send.c +1 −3 Original line number Diff line number Diff line Loading @@ -309,10 +309,8 @@ void schedule_own_packet(struct hard_iface *hard_iface) if (hard_iface == primary_if) { /* if at least one change happened */ if (atomic_read(&bat_priv->tt_local_changes) > 0) { tt_commit_changes(bat_priv); prepare_packet_buffer(bat_priv, hard_iface); /* Increment the TTVN only once per OGM interval */ atomic_inc(&bat_priv->ttvn); bat_priv->tt_poss_change = false; } /* if the changes have been sent enough times */ Loading net/batman-adv/translation-table.c +128 −28 Original line number Diff line number Diff line Loading @@ -215,11 +215,14 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr) tt_local_event(bat_priv, addr, tt_local_entry->flags); /* The local entry has to be marked as NEW to avoid to send it in * a full table response going out before the next ttvn increment * (consistency check) */ tt_local_entry->flags |= TT_CLIENT_NEW; hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig, tt_local_entry, &tt_local_entry->hash_entry); atomic_inc(&bat_priv->num_local_tt); /* remove address from global hash if present */ tt_global_entry = tt_global_hash_find(bat_priv, addr); Loading @@ -227,8 +230,9 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr) if (tt_global_entry) { /* This node is probably going to update its tt table */ tt_global_entry->orig_node->tt_poss_change = true; _tt_global_del(bat_priv, tt_global_entry, "local tt received"); /* The global entry has to be marked as PENDING and has to be * kept for consistency purpose */ tt_global_entry->flags |= TT_CLIENT_PENDING; send_roam_adv(bat_priv, tt_global_entry->addr, tt_global_entry->orig_node); } Loading Loading @@ -358,19 +362,17 @@ out: return ret; } static void tt_local_del(struct bat_priv *bat_priv, static void tt_local_set_pending(struct bat_priv *bat_priv, struct tt_local_entry *tt_local_entry, const char *message) uint16_t flags) { bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry (%pM): %s\n", tt_local_entry->addr, message); atomic_dec(&bat_priv->num_local_tt); hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig, tt_local_entry->addr); tt_local_event(bat_priv, tt_local_entry->addr, tt_local_entry->flags | flags); tt_local_entry_free_ref(tt_local_entry); /* The local client has to be merked as "pending to be removed" but has * to be kept in the table in order to send it in an full tables * response issued before the net ttvn increment (consistency check) */ tt_local_entry->flags |= TT_CLIENT_PENDING; } void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, Loading @@ -379,14 +381,14 @@ void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, struct tt_local_entry *tt_local_entry = NULL; tt_local_entry = tt_local_hash_find(bat_priv, addr); if (!tt_local_entry) goto out; tt_local_event(bat_priv, tt_local_entry->addr, tt_local_entry->flags | TT_CLIENT_DEL | tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL | (roaming ? TT_CLIENT_ROAM : NO_FLAGS)); tt_local_del(bat_priv, tt_local_entry, message); bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: " "%s\n", tt_local_entry->addr, message); out: if (tt_local_entry) tt_local_entry_free_ref(tt_local_entry); Loading @@ -411,18 +413,19 @@ static void tt_local_purge(struct bat_priv *bat_priv) if (tt_local_entry->flags & TT_CLIENT_NOPURGE) continue; /* entry already marked for deletion */ if (tt_local_entry->flags & TT_CLIENT_PENDING) continue; if (!is_out_of_time(tt_local_entry->last_seen, TT_LOCAL_TIMEOUT * 1000)) continue; tt_local_event(bat_priv, tt_local_entry->addr, tt_local_entry->flags | TT_CLIENT_DEL); atomic_dec(&bat_priv->num_local_tt); bat_dbg(DBG_TT, bat_priv, "Deleting local " "tt entry (%pM): timed out\n", tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL); bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) " "pending to be removed: timed out\n", tt_local_entry->addr); hlist_del_rcu(node); tt_local_entry_free_ref(tt_local_entry); } spin_unlock_bh(list_lock); } Loading Loading @@ -785,6 +788,11 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv, if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) goto free_tt; /* A global client marked as PENDING has already moved from that * originator */ if (tt_global_entry->flags & TT_CLIENT_PENDING) goto free_tt; orig_node = tt_global_entry->orig_node; free_tt: Loading Loading @@ -846,6 +854,10 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv) rcu_read_lock(); hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) { /* not yet committed clients have not to be taken into * account while computing the CRC */ if (tt_local_entry->flags & TT_CLIENT_NEW) continue; total_one = 0; for (j = 0; j < ETH_ALEN; j++) total_one = crc16_byte(total_one, Loading Loading @@ -935,6 +947,16 @@ unlock: return tt_req_node; } /* data_ptr is useless here, but has to be kept to respect the prototype */ static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr) { const struct tt_local_entry *tt_local_entry = entry_ptr; if (tt_local_entry->flags & TT_CLIENT_NEW) return 0; return 1; } static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) { const struct tt_global_entry *tt_global_entry = entry_ptr; Loading Loading @@ -1275,7 +1297,8 @@ static bool send_my_tt_response(struct bat_priv *bat_priv, skb = tt_response_fill_table(tt_len, ttvn, bat_priv->tt_local_hash, primary_if, NULL, NULL); primary_if, tt_local_valid_entry, NULL); if (!skb) goto out; Loading Loading @@ -1400,6 +1423,10 @@ bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr) tt_local_entry = tt_local_hash_find(bat_priv, addr); if (!tt_local_entry) goto out; /* Check if the client has been logically deleted (but is kept for * consistency purpose) */ if (tt_local_entry->flags & TT_CLIENT_PENDING) goto out; ret = true; out: if (tt_local_entry) Loading Loading @@ -1620,3 +1647,76 @@ void tt_free(struct bat_priv *bat_priv) kfree(bat_priv->tt_buff); } /* This function will reset the specified flags from all the entries in * the given hash table and will increment num_local_tt for each involved * entry */ static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags) { int i; struct hashtable_t *hash = bat_priv->tt_local_hash; struct hlist_head *head; struct hlist_node *node; struct tt_local_entry *tt_local_entry; if (!hash) return; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; rcu_read_lock(); hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) { tt_local_entry->flags &= ~flags; atomic_inc(&bat_priv->num_local_tt); } rcu_read_unlock(); } } /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */ static void tt_local_purge_pending_clients(struct bat_priv *bat_priv) { struct hashtable_t *hash = bat_priv->tt_local_hash; struct tt_local_entry *tt_local_entry; struct hlist_node *node, *node_tmp; struct hlist_head *head; spinlock_t *list_lock; /* protects write access to the hash lists */ int i; if (!hash) return; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; list_lock = &hash->list_locks[i]; spin_lock_bh(list_lock); hlist_for_each_entry_safe(tt_local_entry, node, node_tmp, head, hash_entry) { if (!(tt_local_entry->flags & TT_CLIENT_PENDING)) continue; bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry " "(%pM): pending\n", tt_local_entry->addr); atomic_dec(&bat_priv->num_local_tt); hlist_del_rcu(node); tt_local_entry_free_ref(tt_local_entry); } spin_unlock_bh(list_lock); } } void tt_commit_changes(struct bat_priv *bat_priv) { tt_local_reset_flags(bat_priv, TT_CLIENT_NEW); tt_local_purge_pending_clients(bat_priv); /* Increment the TTVN only once per OGM interval */ atomic_inc(&bat_priv->ttvn); bat_priv->tt_poss_change = false; } Loading
net/batman-adv/originator.c +2 −0 Original line number Diff line number Diff line Loading @@ -223,6 +223,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr) orig_node->bat_priv = bat_priv; memcpy(orig_node->orig, addr, ETH_ALEN); orig_node->router = NULL; orig_node->tt_crc = 0; atomic_set(&orig_node->last_ttvn, 0); orig_node->tt_buff = NULL; orig_node->tt_buff_len = 0; atomic_set(&orig_node->tt_size, 0); Loading
net/batman-adv/packet.h +3 −1 Original line number Diff line number Diff line Loading @@ -84,7 +84,9 @@ enum tt_query_flags { enum tt_client_flags { TT_CLIENT_DEL = 1 << 0, TT_CLIENT_ROAM = 1 << 1, TT_CLIENT_NOPURGE = 1 << 8 TT_CLIENT_NOPURGE = 1 << 8, TT_CLIENT_NEW = 1 << 9, TT_CLIENT_PENDING = 1 << 10 }; struct batman_packet { Loading
net/batman-adv/routing.c +12 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,18 @@ static void update_transtable(struct bat_priv *bat_priv, * to recompute it to spot any possible inconsistency * in the global table */ orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); /* The ttvn alone is not enough to guarantee consistency * because a single value could repesent different states * (due to the wrap around). Thus a node has to check whether * the resulting table (after applying the changes) is still * consistent or not. E.g. a node could disconnect while its * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case * checking the CRC value is mandatory to detect the * inconsistency */ if (orig_node->tt_crc != tt_crc) goto request_table; /* Roaming phase is over: tables are in sync again. I can * unset the flag */ orig_node->tt_poss_change = false; Loading
net/batman-adv/send.c +1 −3 Original line number Diff line number Diff line Loading @@ -309,10 +309,8 @@ void schedule_own_packet(struct hard_iface *hard_iface) if (hard_iface == primary_if) { /* if at least one change happened */ if (atomic_read(&bat_priv->tt_local_changes) > 0) { tt_commit_changes(bat_priv); prepare_packet_buffer(bat_priv, hard_iface); /* Increment the TTVN only once per OGM interval */ atomic_inc(&bat_priv->ttvn); bat_priv->tt_poss_change = false; } /* if the changes have been sent enough times */ Loading
net/batman-adv/translation-table.c +128 −28 Original line number Diff line number Diff line Loading @@ -215,11 +215,14 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr) tt_local_event(bat_priv, addr, tt_local_entry->flags); /* The local entry has to be marked as NEW to avoid to send it in * a full table response going out before the next ttvn increment * (consistency check) */ tt_local_entry->flags |= TT_CLIENT_NEW; hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig, tt_local_entry, &tt_local_entry->hash_entry); atomic_inc(&bat_priv->num_local_tt); /* remove address from global hash if present */ tt_global_entry = tt_global_hash_find(bat_priv, addr); Loading @@ -227,8 +230,9 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr) if (tt_global_entry) { /* This node is probably going to update its tt table */ tt_global_entry->orig_node->tt_poss_change = true; _tt_global_del(bat_priv, tt_global_entry, "local tt received"); /* The global entry has to be marked as PENDING and has to be * kept for consistency purpose */ tt_global_entry->flags |= TT_CLIENT_PENDING; send_roam_adv(bat_priv, tt_global_entry->addr, tt_global_entry->orig_node); } Loading Loading @@ -358,19 +362,17 @@ out: return ret; } static void tt_local_del(struct bat_priv *bat_priv, static void tt_local_set_pending(struct bat_priv *bat_priv, struct tt_local_entry *tt_local_entry, const char *message) uint16_t flags) { bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry (%pM): %s\n", tt_local_entry->addr, message); atomic_dec(&bat_priv->num_local_tt); hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig, tt_local_entry->addr); tt_local_event(bat_priv, tt_local_entry->addr, tt_local_entry->flags | flags); tt_local_entry_free_ref(tt_local_entry); /* The local client has to be merked as "pending to be removed" but has * to be kept in the table in order to send it in an full tables * response issued before the net ttvn increment (consistency check) */ tt_local_entry->flags |= TT_CLIENT_PENDING; } void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, Loading @@ -379,14 +381,14 @@ void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, struct tt_local_entry *tt_local_entry = NULL; tt_local_entry = tt_local_hash_find(bat_priv, addr); if (!tt_local_entry) goto out; tt_local_event(bat_priv, tt_local_entry->addr, tt_local_entry->flags | TT_CLIENT_DEL | tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL | (roaming ? TT_CLIENT_ROAM : NO_FLAGS)); tt_local_del(bat_priv, tt_local_entry, message); bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: " "%s\n", tt_local_entry->addr, message); out: if (tt_local_entry) tt_local_entry_free_ref(tt_local_entry); Loading @@ -411,18 +413,19 @@ static void tt_local_purge(struct bat_priv *bat_priv) if (tt_local_entry->flags & TT_CLIENT_NOPURGE) continue; /* entry already marked for deletion */ if (tt_local_entry->flags & TT_CLIENT_PENDING) continue; if (!is_out_of_time(tt_local_entry->last_seen, TT_LOCAL_TIMEOUT * 1000)) continue; tt_local_event(bat_priv, tt_local_entry->addr, tt_local_entry->flags | TT_CLIENT_DEL); atomic_dec(&bat_priv->num_local_tt); bat_dbg(DBG_TT, bat_priv, "Deleting local " "tt entry (%pM): timed out\n", tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL); bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) " "pending to be removed: timed out\n", tt_local_entry->addr); hlist_del_rcu(node); tt_local_entry_free_ref(tt_local_entry); } spin_unlock_bh(list_lock); } Loading Loading @@ -785,6 +788,11 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv, if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) goto free_tt; /* A global client marked as PENDING has already moved from that * originator */ if (tt_global_entry->flags & TT_CLIENT_PENDING) goto free_tt; orig_node = tt_global_entry->orig_node; free_tt: Loading Loading @@ -846,6 +854,10 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv) rcu_read_lock(); hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) { /* not yet committed clients have not to be taken into * account while computing the CRC */ if (tt_local_entry->flags & TT_CLIENT_NEW) continue; total_one = 0; for (j = 0; j < ETH_ALEN; j++) total_one = crc16_byte(total_one, Loading Loading @@ -935,6 +947,16 @@ unlock: return tt_req_node; } /* data_ptr is useless here, but has to be kept to respect the prototype */ static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr) { const struct tt_local_entry *tt_local_entry = entry_ptr; if (tt_local_entry->flags & TT_CLIENT_NEW) return 0; return 1; } static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) { const struct tt_global_entry *tt_global_entry = entry_ptr; Loading Loading @@ -1275,7 +1297,8 @@ static bool send_my_tt_response(struct bat_priv *bat_priv, skb = tt_response_fill_table(tt_len, ttvn, bat_priv->tt_local_hash, primary_if, NULL, NULL); primary_if, tt_local_valid_entry, NULL); if (!skb) goto out; Loading Loading @@ -1400,6 +1423,10 @@ bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr) tt_local_entry = tt_local_hash_find(bat_priv, addr); if (!tt_local_entry) goto out; /* Check if the client has been logically deleted (but is kept for * consistency purpose) */ if (tt_local_entry->flags & TT_CLIENT_PENDING) goto out; ret = true; out: if (tt_local_entry) Loading Loading @@ -1620,3 +1647,76 @@ void tt_free(struct bat_priv *bat_priv) kfree(bat_priv->tt_buff); } /* This function will reset the specified flags from all the entries in * the given hash table and will increment num_local_tt for each involved * entry */ static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags) { int i; struct hashtable_t *hash = bat_priv->tt_local_hash; struct hlist_head *head; struct hlist_node *node; struct tt_local_entry *tt_local_entry; if (!hash) return; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; rcu_read_lock(); hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) { tt_local_entry->flags &= ~flags; atomic_inc(&bat_priv->num_local_tt); } rcu_read_unlock(); } } /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */ static void tt_local_purge_pending_clients(struct bat_priv *bat_priv) { struct hashtable_t *hash = bat_priv->tt_local_hash; struct tt_local_entry *tt_local_entry; struct hlist_node *node, *node_tmp; struct hlist_head *head; spinlock_t *list_lock; /* protects write access to the hash lists */ int i; if (!hash) return; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; list_lock = &hash->list_locks[i]; spin_lock_bh(list_lock); hlist_for_each_entry_safe(tt_local_entry, node, node_tmp, head, hash_entry) { if (!(tt_local_entry->flags & TT_CLIENT_PENDING)) continue; bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry " "(%pM): pending\n", tt_local_entry->addr); atomic_dec(&bat_priv->num_local_tt); hlist_del_rcu(node); tt_local_entry_free_ref(tt_local_entry); } spin_unlock_bh(list_lock); } } void tt_commit_changes(struct bat_priv *bat_priv) { tt_local_reset_flags(bat_priv, TT_CLIENT_NEW); tt_local_purge_pending_clients(bat_priv); /* Increment the TTVN only once per OGM interval */ atomic_inc(&bat_priv->ttvn); bat_priv->tt_poss_change = false; }