Commit c7c6575f authored by David S. Miller's avatar David S. Miller

Merge branch 'batman-adv/next' of git://git.open-mesh.org/linux-merge

parents 0850f0f5 b5a1eeef
...@@ -200,15 +200,16 @@ abled during run time. Following log_levels are defined: ...@@ -200,15 +200,16 @@ abled during run time. Following log_levels are defined:
0 - All debug output disabled 0 - All debug output disabled
1 - Enable messages related to routing / flooding / broadcasting 1 - Enable messages related to routing / flooding / broadcasting
2 - Enable route or tt entry added / changed / deleted 2 - Enable messages related to route added / changed / deleted
3 - Enable all messages 4 - Enable messages related to translation table operations
7 - Enable all messages
The debug output can be changed at runtime using the file The debug output can be changed at runtime using the file
/sys/class/net/bat0/mesh/log_level. e.g. /sys/class/net/bat0/mesh/log_level. e.g.
# echo 2 > /sys/class/net/bat0/mesh/log_level # echo 2 > /sys/class/net/bat0/mesh/log_level
will enable debug messages for when routes or TTs change. will enable debug messages for when routes change.
BATCTL BATCTL
......
...@@ -695,7 +695,7 @@ bool gw_out_of_range(struct bat_priv *bat_priv, ...@@ -695,7 +695,7 @@ bool gw_out_of_range(struct bat_priv *bat_priv,
} }
neigh_old = find_router(bat_priv, orig_dst_node, NULL); neigh_old = find_router(bat_priv, orig_dst_node, NULL);
if (!!neigh_old) if (!neigh_old)
goto out; goto out;
if (curr_tq_avg - neigh_old->tq_avg > GW_THRESHOLD) if (curr_tq_avg - neigh_old->tq_avg > GW_THRESHOLD)
......
...@@ -136,10 +136,9 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf, ...@@ -136,10 +136,9 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf,
spin_unlock_bh(&socket_client->lock); spin_unlock_bh(&socket_client->lock);
error = __copy_to_user(buf, &socket_packet->icmp_packet, packet_len = min(count, socket_packet->icmp_len);
socket_packet->icmp_len); error = copy_to_user(buf, &socket_packet->icmp_packet, packet_len);
packet_len = socket_packet->icmp_len;
kfree(socket_packet); kfree(socket_packet);
if (error) if (error)
...@@ -187,12 +186,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, ...@@ -187,12 +186,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
skb_reserve(skb, sizeof(struct ethhdr)); skb_reserve(skb, sizeof(struct ethhdr));
icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len); icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len);
if (!access_ok(VERIFY_READ, buff, packet_len)) { if (copy_from_user(icmp_packet, buff, packet_len)) {
len = -EFAULT;
goto free_skb;
}
if (__copy_from_user(icmp_packet, buff, packet_len)) {
len = -EFAULT; len = -EFAULT;
goto free_skb; goto free_skb;
} }
...@@ -217,7 +211,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, ...@@ -217,7 +211,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
if (icmp_packet->version != COMPAT_VERSION) { if (icmp_packet->version != COMPAT_VERSION) {
icmp_packet->msg_type = PARAMETER_PROBLEM; icmp_packet->msg_type = PARAMETER_PROBLEM;
icmp_packet->ttl = COMPAT_VERSION; icmp_packet->version = COMPAT_VERSION;
bat_socket_add_packet(socket_client, icmp_packet, packet_len); bat_socket_add_packet(socket_client, icmp_packet, packet_len);
goto free_skb; goto free_skb;
} }
......
...@@ -627,8 +627,7 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if) ...@@ -627,8 +627,7 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
/* Ensure we have all the claimed data */ /* Ensure we have all the claimed data */
if (unlikely(skb_headlen(skb) < if (unlikely(skb_headlen(skb) <
sizeof(struct tt_query_packet) + sizeof(struct tt_query_packet) + tt_len))
tt_len))
goto out; goto out;
handle_tt_response(bat_priv, tt_query); handle_tt_response(bat_priv, tt_query);
......
...@@ -874,7 +874,7 @@ struct net_device *softif_create(const char *name) ...@@ -874,7 +874,7 @@ struct net_device *softif_create(const char *name)
unreg_sysfs: unreg_sysfs:
sysfs_del_meshif(soft_iface); sysfs_del_meshif(soft_iface);
unreg_soft_iface: unreg_soft_iface:
unregister_netdev(soft_iface); unregister_netdevice(soft_iface);
return NULL; return NULL;
free_soft_iface: free_soft_iface:
......
...@@ -36,18 +36,9 @@ static void _tt_global_del(struct bat_priv *bat_priv, ...@@ -36,18 +36,9 @@ static void _tt_global_del(struct bat_priv *bat_priv,
static void tt_purge(struct work_struct *work); static void tt_purge(struct work_struct *work);
/* returns 1 if they are the same mac addr */ /* returns 1 if they are the same mac addr */
static int compare_ltt(const struct hlist_node *node, const void *data2) static int compare_tt(const struct hlist_node *node, const void *data2)
{ {
const void *data1 = container_of(node, struct tt_local_entry, const void *data1 = container_of(node, struct tt_common_entry,
hash_entry);
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
}
/* returns 1 if they are the same mac addr */
static int compare_gtt(const struct hlist_node *node, const void *data2)
{
const void *data1 = container_of(node, struct tt_global_entry,
hash_entry); hash_entry);
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
...@@ -60,13 +51,12 @@ static void tt_start_timer(struct bat_priv *bat_priv) ...@@ -60,13 +51,12 @@ static void tt_start_timer(struct bat_priv *bat_priv)
msecs_to_jiffies(5000)); msecs_to_jiffies(5000));
} }
static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv, static struct tt_common_entry *tt_hash_find(struct hashtable_t *hash,
const void *data) const void *data)
{ {
struct hashtable_t *hash = bat_priv->tt_local_hash;
struct hlist_head *head; struct hlist_head *head;
struct hlist_node *node; struct hlist_node *node;
struct tt_local_entry *tt_local_entry, *tt_local_entry_tmp = NULL; struct tt_common_entry *tt_common_entry, *tt_common_entry_tmp = NULL;
uint32_t index; uint32_t index;
if (!hash) if (!hash)
...@@ -76,51 +66,46 @@ static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv, ...@@ -76,51 +66,46 @@ static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
head = &hash->table[index]; head = &hash->table[index];
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) { hlist_for_each_entry_rcu(tt_common_entry, node, head, hash_entry) {
if (!compare_eth(tt_local_entry, data)) if (!compare_eth(tt_common_entry, data))
continue; continue;
if (!atomic_inc_not_zero(&tt_local_entry->refcount)) if (!atomic_inc_not_zero(&tt_common_entry->refcount))
continue; continue;
tt_local_entry_tmp = tt_local_entry; tt_common_entry_tmp = tt_common_entry;
break; break;
} }
rcu_read_unlock(); rcu_read_unlock();
return tt_local_entry_tmp; return tt_common_entry_tmp;
} }
static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv, static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
const void *data) const void *data)
{ {
struct hashtable_t *hash = bat_priv->tt_global_hash; struct tt_common_entry *tt_common_entry;
struct hlist_head *head; struct tt_local_entry *tt_local_entry = NULL;
struct hlist_node *node;
struct tt_global_entry *tt_global_entry;
struct tt_global_entry *tt_global_entry_tmp = NULL;
uint32_t index;
if (!hash)
return NULL;
index = choose_orig(data, hash->size);
head = &hash->table[index];
rcu_read_lock(); tt_common_entry = tt_hash_find(bat_priv->tt_local_hash, data);
hlist_for_each_entry_rcu(tt_global_entry, node, head, hash_entry) { if (tt_common_entry)
if (!compare_eth(tt_global_entry, data)) tt_local_entry = container_of(tt_common_entry,
continue; struct tt_local_entry, common);
return tt_local_entry;
}
if (!atomic_inc_not_zero(&tt_global_entry->refcount)) static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
continue; const void *data)
{
struct tt_common_entry *tt_common_entry;
struct tt_global_entry *tt_global_entry = NULL;
tt_global_entry_tmp = tt_global_entry; tt_common_entry = tt_hash_find(bat_priv->tt_global_hash, data);
break; if (tt_common_entry)
} tt_global_entry = container_of(tt_common_entry,
rcu_read_unlock(); struct tt_global_entry, common);
return tt_global_entry;
return tt_global_entry_tmp;
} }
static bool is_out_of_time(unsigned long starting_time, unsigned long timeout) static bool is_out_of_time(unsigned long starting_time, unsigned long timeout)
...@@ -133,15 +118,18 @@ static bool is_out_of_time(unsigned long starting_time, unsigned long timeout) ...@@ -133,15 +118,18 @@ static bool is_out_of_time(unsigned long starting_time, unsigned long timeout)
static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry) static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
{ {
if (atomic_dec_and_test(&tt_local_entry->refcount)) if (atomic_dec_and_test(&tt_local_entry->common.refcount))
kfree_rcu(tt_local_entry, rcu); kfree_rcu(tt_local_entry, common.rcu);
} }
static void tt_global_entry_free_rcu(struct rcu_head *rcu) static void tt_global_entry_free_rcu(struct rcu_head *rcu)
{ {
struct tt_common_entry *tt_common_entry;
struct tt_global_entry *tt_global_entry; struct tt_global_entry *tt_global_entry;
tt_global_entry = container_of(rcu, struct tt_global_entry, rcu); tt_common_entry = container_of(rcu, struct tt_common_entry, rcu);
tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
common);
if (tt_global_entry->orig_node) if (tt_global_entry->orig_node)
orig_node_free_ref(tt_global_entry->orig_node); orig_node_free_ref(tt_global_entry->orig_node);
...@@ -151,8 +139,9 @@ static void tt_global_entry_free_rcu(struct rcu_head *rcu) ...@@ -151,8 +139,9 @@ static void tt_global_entry_free_rcu(struct rcu_head *rcu)
static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry) static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
{ {
if (atomic_dec_and_test(&tt_global_entry->refcount)) if (atomic_dec_and_test(&tt_global_entry->common.refcount))
call_rcu(&tt_global_entry->rcu, tt_global_entry_free_rcu); call_rcu(&tt_global_entry->common.rcu,
tt_global_entry_free_rcu);
} }
static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr, static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
...@@ -201,6 +190,7 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr, ...@@ -201,6 +190,7 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
struct bat_priv *bat_priv = netdev_priv(soft_iface); struct bat_priv *bat_priv = netdev_priv(soft_iface);
struct tt_local_entry *tt_local_entry = NULL; struct tt_local_entry *tt_local_entry = NULL;
struct tt_global_entry *tt_global_entry = NULL; struct tt_global_entry *tt_global_entry = NULL;
int hash_added;
tt_local_entry = tt_local_hash_find(bat_priv, addr); tt_local_entry = tt_local_hash_find(bat_priv, addr);
...@@ -217,26 +207,33 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr, ...@@ -217,26 +207,33 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
"Creating new local tt entry: %pM (ttvn: %d)\n", addr, "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
(uint8_t)atomic_read(&bat_priv->ttvn)); (uint8_t)atomic_read(&bat_priv->ttvn));
memcpy(tt_local_entry->addr, addr, ETH_ALEN); memcpy(tt_local_entry->common.addr, addr, ETH_ALEN);
tt_local_entry->last_seen = jiffies; tt_local_entry->common.flags = NO_FLAGS;
tt_local_entry->flags = NO_FLAGS;
if (is_wifi_iface(ifindex)) if (is_wifi_iface(ifindex))
tt_local_entry->flags |= TT_CLIENT_WIFI; tt_local_entry->common.flags |= TT_CLIENT_WIFI;
atomic_set(&tt_local_entry->refcount, 2); atomic_set(&tt_local_entry->common.refcount, 2);
tt_local_entry->last_seen = jiffies;
/* the batman interface mac address should never be purged */ /* the batman interface mac address should never be purged */
if (compare_eth(addr, soft_iface->dev_addr)) if (compare_eth(addr, soft_iface->dev_addr))
tt_local_entry->flags |= TT_CLIENT_NOPURGE; tt_local_entry->common.flags |= TT_CLIENT_NOPURGE;
tt_local_event(bat_priv, addr, tt_local_entry->flags); hash_added = hash_add(bat_priv->tt_local_hash, compare_tt, choose_orig,
&tt_local_entry->common,
&tt_local_entry->common.hash_entry);
if (unlikely(hash_added != 0)) {
/* remove the reference for the hash */
tt_local_entry_free_ref(tt_local_entry);
goto out;
}
tt_local_event(bat_priv, addr, tt_local_entry->common.flags);
/* The local entry has to be marked as NEW to avoid to send it in /* 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 * a full table response going out before the next ttvn increment
* (consistency check) */ * (consistency check) */
tt_local_entry->flags |= TT_CLIENT_NEW; tt_local_entry->common.flags |= TT_CLIENT_NEW;
hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
tt_local_entry, &tt_local_entry->hash_entry);
/* remove address from global hash if present */ /* remove address from global hash if present */
tt_global_entry = tt_global_hash_find(bat_priv, addr); tt_global_entry = tt_global_hash_find(bat_priv, addr);
...@@ -247,8 +244,8 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr, ...@@ -247,8 +244,8 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
tt_global_entry->orig_node->tt_poss_change = true; tt_global_entry->orig_node->tt_poss_change = true;
/* The global entry has to be marked as PENDING and has to be /* The global entry has to be marked as PENDING and has to be
* kept for consistency purpose */ * kept for consistency purpose */
tt_global_entry->flags |= TT_CLIENT_PENDING; tt_global_entry->common.flags |= TT_CLIENT_PENDING;
send_roam_adv(bat_priv, tt_global_entry->addr, send_roam_adv(bat_priv, tt_global_entry->common.addr,
tt_global_entry->orig_node); tt_global_entry->orig_node);
} }
out: out:
...@@ -310,7 +307,7 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset) ...@@ -310,7 +307,7 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset)
struct net_device *net_dev = (struct net_device *)seq->private; struct net_device *net_dev = (struct net_device *)seq->private;
struct bat_priv *bat_priv = netdev_priv(net_dev); struct bat_priv *bat_priv = netdev_priv(net_dev);
struct hashtable_t *hash = bat_priv->tt_local_hash; struct hashtable_t *hash = bat_priv->tt_local_hash;
struct tt_local_entry *tt_local_entry; struct tt_common_entry *tt_common_entry;
struct hard_iface *primary_if; struct hard_iface *primary_if;
struct hlist_node *node; struct hlist_node *node;
struct hlist_head *head; struct hlist_head *head;
...@@ -340,19 +337,19 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset) ...@@ -340,19 +337,19 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset)
head = &hash->table[i]; head = &hash->table[i];
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(tt_local_entry, node, hlist_for_each_entry_rcu(tt_common_entry, node,
head, hash_entry) { head, hash_entry) {
seq_printf(seq, " * %pM [%c%c%c%c%c]\n", seq_printf(seq, " * %pM [%c%c%c%c%c]\n",
tt_local_entry->addr, tt_common_entry->addr,
(tt_local_entry->flags & (tt_common_entry->flags &
TT_CLIENT_ROAM ? 'R' : '.'), TT_CLIENT_ROAM ? 'R' : '.'),
(tt_local_entry->flags & (tt_common_entry->flags &
TT_CLIENT_NOPURGE ? 'P' : '.'), TT_CLIENT_NOPURGE ? 'P' : '.'),
(tt_local_entry->flags & (tt_common_entry->flags &
TT_CLIENT_NEW ? 'N' : '.'), TT_CLIENT_NEW ? 'N' : '.'),
(tt_local_entry->flags & (tt_common_entry->flags &
TT_CLIENT_PENDING ? 'X' : '.'), TT_CLIENT_PENDING ? 'X' : '.'),
(tt_local_entry->flags & (tt_common_entry->flags &
TT_CLIENT_WIFI ? 'W' : '.')); TT_CLIENT_WIFI ? 'W' : '.'));
} }
rcu_read_unlock(); rcu_read_unlock();
...@@ -367,13 +364,13 @@ static void tt_local_set_pending(struct bat_priv *bat_priv, ...@@ -367,13 +364,13 @@ static void tt_local_set_pending(struct bat_priv *bat_priv,
struct tt_local_entry *tt_local_entry, struct tt_local_entry *tt_local_entry,
uint16_t flags) uint16_t flags)
{ {
tt_local_event(bat_priv, tt_local_entry->addr, tt_local_event(bat_priv, tt_local_entry->common.addr,
tt_local_entry->flags | flags); tt_local_entry->common.flags | flags);
/* The local client has to be marked as "pending to be removed" but has /* The local client has to be marked as "pending to be removed" but has
* to be kept in the table in order to send it in a full table * to be kept in the table in order to send it in a full table
* response issued before the net ttvn increment (consistency check) */ * response issued before the net ttvn increment (consistency check) */
tt_local_entry->flags |= TT_CLIENT_PENDING; tt_local_entry->common.flags |= TT_CLIENT_PENDING;
} }
void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
...@@ -389,7 +386,7 @@ void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, ...@@ -389,7 +386,7 @@ void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
(roaming ? TT_CLIENT_ROAM : NO_FLAGS)); (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: " bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
"%s\n", tt_local_entry->addr, message); "%s\n", tt_local_entry->common.addr, message);
out: out:
if (tt_local_entry) if (tt_local_entry)
tt_local_entry_free_ref(tt_local_entry); tt_local_entry_free_ref(tt_local_entry);
...@@ -399,6 +396,7 @@ static void tt_local_purge(struct bat_priv *bat_priv) ...@@ -399,6 +396,7 @@ static void tt_local_purge(struct bat_priv *bat_priv)
{ {
struct hashtable_t *hash = bat_priv->tt_local_hash; struct hashtable_t *hash = bat_priv->tt_local_hash;
struct tt_local_entry *tt_local_entry; struct tt_local_entry *tt_local_entry;
struct tt_common_entry *tt_common_entry;
struct hlist_node *node, *node_tmp; struct hlist_node *node, *node_tmp;
struct hlist_head *head; struct hlist_head *head;
spinlock_t *list_lock; /* protects write access to the hash lists */ spinlock_t *list_lock; /* protects write access to the hash lists */
...@@ -409,13 +407,16 @@ static void tt_local_purge(struct bat_priv *bat_priv) ...@@ -409,13 +407,16 @@ static void tt_local_purge(struct bat_priv *bat_priv)
list_lock = &hash->list_locks[i]; list_lock = &hash->list_locks[i];
spin_lock_bh(list_lock); spin_lock_bh(list_lock);
hlist_for_each_entry_safe(tt_local_entry, node, node_tmp, hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
head, hash_entry) { head, hash_entry) {
if (tt_local_entry->flags & TT_CLIENT_NOPURGE) tt_local_entry = container_of(tt_common_entry,
struct tt_local_entry,
common);
if (tt_local_entry->common.flags & TT_CLIENT_NOPURGE)
continue; continue;
/* entry already marked for deletion */ /* entry already marked for deletion */
if (tt_local_entry->flags & TT_CLIENT_PENDING) if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
continue; continue;
if (!is_out_of_time(tt_local_entry->last_seen, if (!is_out_of_time(tt_local_entry->last_seen,
...@@ -426,7 +427,7 @@ static void tt_local_purge(struct bat_priv *bat_priv) ...@@ -426,7 +427,7 @@ static void tt_local_purge(struct bat_priv *bat_priv)
TT_CLIENT_DEL); TT_CLIENT_DEL);
bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) " bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) "
"pending to be removed: timed out\n", "pending to be removed: timed out\n",
tt_local_entry->addr); tt_local_entry->common.addr);
} }
spin_unlock_bh(list_lock); spin_unlock_bh(list_lock);
} }
...@@ -437,6 +438,7 @@ static void tt_local_table_free(struct bat_priv *bat_priv) ...@@ -437,6 +438,7 @@ static void tt_local_table_free(struct bat_priv *bat_priv)
{ {
struct hashtable_t *hash; struct hashtable_t *hash;
spinlock_t *list_lock; /* protects write access to the hash lists */ spinlock_t *list_lock; /* protects write access to the hash lists */
struct tt_common_entry *tt_common_entry;
struct tt_local_entry *tt_local_entry; struct tt_local_entry *tt_local_entry;
struct hlist_node *node, *node_tmp; struct hlist_node *node, *node_tmp;
struct hlist_head *head; struct hlist_head *head;
...@@ -452,9 +454,12 @@ static void tt_local_table_free(struct bat_priv *bat_priv) ...@@ -452,9 +454,12 @@ static void tt_local_table_free(struct bat_priv *bat_priv)
list_lock = &hash->list_locks[i]; list_lock = &hash->list_locks[i];
spin_lock_bh(list_lock); spin_lock_bh(list_lock);
hlist_for_each_entry_safe(tt_local_entry, node, node_tmp, hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
head, hash_entry) { head, hash_entry) {
hlist_del_rcu(node); hlist_del_rcu(node);
tt_local_entry = container_of(tt_common_entry,
struct tt_local_entry,
common);
tt_local_entry_free_ref(tt_local_entry); tt_local_entry_free_ref(tt_local_entry);
} }
spin_unlock_bh(list_lock); spin_unlock_bh(list_lock);
...@@ -502,6 +507,7 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, ...@@ -502,6 +507,7 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
struct tt_global_entry *tt_global_entry; struct tt_global_entry *tt_global_entry;
struct orig_node *orig_node_tmp; struct orig_node *orig_node_tmp;
int ret = 0; int ret = 0;
int hash_added;
tt_global_entry = tt_global_hash_find(bat_priv, tt_addr); tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
...@@ -512,18 +518,24 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, ...@@ -512,18 +518,24 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
if (!tt_global_entry) if (!tt_global_entry)
goto out; goto out;
memcpy(tt_global_entry->addr, tt_addr, ETH_ALEN); memcpy(tt_global_entry->common.addr, tt_addr, ETH_ALEN);
tt_global_entry->common.flags = NO_FLAGS;
atomic_set(&tt_global_entry->common.refcount, 2);
/* Assign the new orig_node */ /* Assign the new orig_node */
atomic_inc(&orig_node->refcount); atomic_inc(&orig_node->refcount);
tt_global_entry->orig_node = orig_node; tt_global_entry->orig_node = orig_node;
tt_global_entry->ttvn = ttvn; tt_global_entry->ttvn = ttvn;
tt_global_entry->flags = NO_FLAGS;
tt_global_entry->roam_at = 0; tt_global_entry->roam_at = 0;
atomic_set(&tt_global_entry->refcount, 2);
hash_add(bat_priv->tt_global_hash, compare_gtt, hash_added = hash_add(bat_priv->tt_global_hash, compare_tt,
choose_orig, tt_global_entry, choose_orig, &tt_global_entry->common,
&tt_global_entry->hash_entry); &tt_global_entry->common.hash_entry);
if (unlikely(hash_added != 0)) {
/* remove the reference for the hash */
tt_global_entry_free_ref(tt_global_entry);
goto out_remove;
}
atomic_inc(&orig_node->tt_size); atomic_inc(&orig_node->tt_size);
} else { } else {
if (tt_global_entry->orig_node != orig_node) { if (tt_global_entry->orig_node != orig_node) {
...@@ -534,20 +546,21 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, ...@@ -534,20 +546,21 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
orig_node_free_ref(orig_node_tmp); orig_node_free_ref(orig_node_tmp);
atomic_inc(&orig_node->tt_size); atomic_inc(&orig_node->tt_size);
} }
tt_global_entry->common.flags = NO_FLAGS;
tt_global_entry->ttvn = ttvn; tt_global_entry->ttvn = ttvn;
tt_global_entry->flags = NO_FLAGS;
tt_global_entry->roam_at = 0; tt_global_entry->roam_at = 0;
} }
if (wifi) if (wifi)
tt_global_entry->flags |= TT_CLIENT_WIFI; tt_global_entry->common.flags |= TT_CLIENT_WIFI;
bat_dbg(DBG_TT, bat_priv, bat_dbg(DBG_TT, bat_priv,
"Creating new global tt entry: %pM (via %pM)\n", "Creating new global tt entry: %pM (via %pM)\n",
tt_global_entry->addr, orig_node->orig); tt_global_entry->common.addr, orig_node->orig);
out_remove:
/* remove address from local hash if present */ /* remove address from local hash if present */
tt_local_remove(bat_priv, tt_global_entry->addr, tt_local_remove(bat_priv, tt_global_entry->common.addr,
"global tt received", roaming); "global tt received", roaming);
ret = 1; ret = 1;
out: out:
...@@ -561,6 +574,7 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset) ...@@ -561,6 +574,7 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
struct net_device *net_dev = (struct net_device *)seq->private; struct net_device *net_dev = (struct net_device *)seq->private;
struct bat_priv *bat_priv = netdev_priv(net_dev); struct bat_priv *bat_priv = netdev_priv(net_dev);
struct hashtable_t *hash = bat_priv->tt_global_hash; struct hashtable_t *hash = bat_priv->tt_global_hash;
struct tt_common_entry *tt_common_entry;
struct tt_global_entry *tt_global_entry; struct tt_global_entry *tt_global_entry;
struct hard_iface *primary_if; struct hard_iface *primary_if;
struct hlist_node *node; struct hlist_node *node;
...@@ -593,20 +607,24 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset) ...@@ -593,20 +607,24 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
head = &hash->table[i]; head = &hash->table[i];
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(tt_global_entry, node, hlist_for_each_entry_rcu(tt_common_entry, node,
head, hash_entry) { head, hash_entry) {
tt_global_entry = container_of(tt_common_entry,
struct tt_global_entry,
common);
seq_printf(seq, " * %pM (%3u) via %pM (%3u) " seq_printf(seq, " * %pM (%3u) via %pM (%3u) "
"[%c%c%c]\n", tt_global_entry->addr, "[%c%c%c]\n",
tt_global_entry->common.addr,
tt_global_entry->ttvn, tt_global_entry->ttvn,
tt_global_entry->orig_node->orig, tt_global_entry->orig_node->orig,
(uint8_t) atomic_read( (uint8_t) atomic_read(
&tt_global_entry->orig_node-> &tt_global_entry->orig_node->
last_ttvn), last_ttvn),
(tt_global_entry->flags & (tt_global_entry->common.flags &
TT_CLIENT_ROAM ? 'R' : '.'), TT_CLIENT_ROAM ? 'R' : '.'),
(tt_global_entry->flags & (tt_global_entry->common.flags &
TT_CLIENT_PENDING ? 'X' : '.'), TT_CLIENT_PENDING ? 'X' : '.'),
(tt_global_entry->flags & (tt_global_entry->common.flags &
TT_CLIENT_WIFI ? 'W' : '.')); TT_CLIENT_WIFI ? 'W' : '.'));
} }
rcu_read_unlock(); rcu_read_unlock();
...@@ -626,13 +644,13 @@ static void _tt_global_del(struct bat_priv *bat_priv, ...@@ -626,13 +644,13 @@ static void _tt_global_del(struct bat_priv *bat_priv,
bat_dbg(DBG_TT, bat_priv, bat_dbg(DBG_TT, bat_priv,
"Deleting global tt entry %pM (via %pM): %s\n", "Deleting global tt entry %pM (via %pM): %s\n",
tt_global_entry->addr, tt_global_entry->orig_node->orig, tt_global_entry->common.addr, tt_global_entry->orig_node->orig,
message); message);
atomic_dec(&tt_global_entry->orig_node->tt_size); atomic_dec(&tt_global_entry->orig_node->tt_size);
hash_remove(bat_priv->tt_global_hash, compare_gtt, choose_orig, hash_remove(bat_priv->tt_global_hash, compare_tt, choose_orig,
tt_global_entry->addr); tt_global_entry->common.addr);
out: out:
if (tt_global_entry) if (tt_global_entry)
tt_global_entry_free_ref(tt_global_entry); tt_global_entry_free_ref(tt_global_entry);
...@@ -650,7 +668,7 @@ void tt_global_del(struct bat_priv *bat_priv, ...@@ -650,7 +668,7 @@ void tt_global_del(struct bat_priv *bat_priv,
if (tt_global_entry->orig_node == orig_node) { if (tt_global_entry->orig_node == orig_node) {
if (roaming) { if (roaming) {
tt_global_entry->flags |= TT_CLIENT_ROAM; tt_global_entry->common.flags |= TT_CLIENT_ROAM;
tt_global_entry->roam_at = jiffies; tt_global_entry->roam_at = jiffies;
goto out; goto out;
} }
...@@ -665,6 +683,7 @@ void tt_global_del_orig(struct bat_priv *bat_priv, ...@@ -665,6 +683,7 @@ void tt_global_del_orig(struct bat_priv *bat_priv,
struct orig_node *orig_node, const char *message) struct orig_node *orig_node, const char *message)
{ {
struct tt_global_entry *tt_global_entry; struct tt_global_entry *tt_global_entry;
struct tt_common_entry *tt_common_entry;
uint32_t i; uint32_t i;
struct hashtable_t *hash = bat_priv->tt_global_hash; struct hashtable_t *hash = bat_priv->tt_global_hash;
struct hlist_node *node, *safe; struct hlist_node *node, *safe;
...@@ -679,13 +698,16 @@ void tt_global_del_orig(struct bat_priv *bat_priv, ...@@ -679,13 +698,16 @@ void tt_global_del_orig(struct bat_priv *bat_priv,
list_lock = &hash->list_locks[i]; list_lock = &hash->list_locks[i];
spin_lock_bh(list_lock); spin_lock_bh(list_lock);
hlist_for_each_entry_safe(tt_global_entry, node, safe, hlist_for_each_entry_safe(tt_common_entry, node, safe,
head, hash_entry) { head, hash_entry) {
tt_global_entry = container_of(tt_common_entry,
struct tt_global_entry,
common);
if (tt_global_entry->orig_node == orig_node) { if (tt_global_entry->orig_node == orig_node) {
bat_dbg(DBG_TT, bat_priv, bat_dbg(DBG_TT, bat_priv,
"Deleting global tt entry %pM " "Deleting global tt entry %pM "
"(via %pM): %s\n", "(via %pM): %s\n",
tt_global_entry->addr, tt_global_entry->common.addr,
tt_global_entry->orig_node->orig, tt_global_entry->orig_node->orig,
message); message);
hlist_del_rcu(node); hlist_del_rcu(node);
...@@ -700,6 +722,7 @@ void tt_global_del_orig(struct bat_priv *bat_priv, ...@@ -700,6 +722,7 @@ void tt_global_del_orig(struct bat_priv *bat_priv,
static void tt_global_roam_purge(struct bat_priv *bat_priv) static void tt_global_roam_purge(struct bat_priv *bat_priv)
{ {
struct hashtable_t *hash = bat_priv->tt_global_hash; struct hashtable_t *hash = bat_priv->tt_global_hash;
struct tt_common_entry *tt_common_entry;
struct tt_global_entry *tt_global_entry; struct tt_global_entry *tt_global_entry;
struct hlist_node *node, *node_tmp; struct hlist_node *node, *node_tmp;
struct hlist_head *head; struct hlist_head *head;
...@@ -711,9 +734,12 @@ static void tt_global_roam_purge(struct bat_priv *bat_priv) ...@@ -711,9 +734,12 @@ static void tt_global_roam_purge(struct bat_priv *bat_priv)
list_lock = &hash->list_locks[i]; list_lock = &hash->list_locks[i];
spin_lock_bh(list_lock); spin_lock_bh(list_lock);
hlist_for_each_entry_safe(tt_global_entry, node, node_tmp, hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
head, hash_entry) { head, hash_entry) {
if (!(tt_global_entry->flags & TT_CLIENT_ROAM)) tt_global_entry = container_of(tt_common_entry,
struct tt_global_entry,
common);
if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM))
continue; continue;
if (!is_out_of_time(tt_global_entry->roam_at, if (!is_out_of_time(tt_global_entry->roam_at,
TT_CLIENT_ROAM_TIMEOUT * 1000)) TT_CLIENT_ROAM_TIMEOUT * 1000))
...@@ -721,7 +747,7 @@ static void tt_global_roam_purge(struct bat_priv *bat_priv) ...@@ -721,7 +747,7 @@ static void tt_global_roam_purge(struct bat_priv *bat_priv)
bat_dbg(DBG_TT, bat_priv, "Deleting global " bat_dbg(DBG_TT, bat_priv, "Deleting global "
"tt entry (%pM): Roaming timeout\n", "tt entry (%pM): Roaming timeout\n",
tt_global_entry->addr); tt_global_entry->common.addr);
atomic_dec(&tt_global_entry->orig_node->tt_size); atomic_dec(&tt_global_entry->orig_node->tt_size);
hlist_del_rcu(node); hlist_del_rcu(node);
tt_global_entry_free_ref(tt_global_entry); tt_global_entry_free_ref(tt_global_entry);
...@@ -735,6 +761,7 @@ static void tt_global_table_free(struct bat_priv *bat_priv) ...@@ -735,6 +761,7 @@ static void tt_global_table_free(struct bat_priv *bat_priv)
{ {
struct hashtable_t *hash; struct hashtable_t *hash;
spinlock_t *list_lock; /* protects write access to the hash lists */ spinlock_t *list_lock; /* protects write access to the hash lists */
struct tt_common_entry *tt_common_entry;
struct tt_global_entry *tt_global_entry; struct tt_global_entry *tt_global_entry;
struct hlist_node *node, *node_tmp; struct hlist_node *node, *node_tmp;
struct hlist_head *head; struct hlist_head *head;
...@@ -750,9 +777,12 @@ static void tt_global_table_free(struct bat_priv *bat_priv) ...@@ -750,9 +777,12 @@ static void tt_global_table_free(struct bat_priv *bat_priv)
list_lock = &hash->list_locks[i]; list_lock = &hash->list_locks[i];
spin_lock_bh(list_lock); spin_lock_bh(list_lock);
hlist_for_each_entry_safe(tt_global_entry, node, node_tmp, hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
head, hash_entry) { head, hash_entry) {
hlist_del_rcu(node); hlist_del_rcu(node);
tt_global_entry = container_of(tt_common_entry,
struct tt_global_entry,
common);
tt_global_entry_free_ref(tt_global_entry); tt_global_entry_free_ref(tt_global_entry);
} }
spin_unlock_bh(list_lock); spin_unlock_bh(list_lock);
...@@ -768,8 +798,8 @@ static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry, ...@@ -768,8 +798,8 @@ static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
{ {
bool ret = false; bool ret = false;
if (tt_local_entry->flags & TT_CLIENT_WIFI && if (tt_local_entry->common.flags & TT_CLIENT_WIFI &&
tt_global_entry->flags & TT_CLIENT_WIFI) tt_global_entry->common.flags & TT_CLIENT_WIFI)
ret = true; ret = true;
return ret; return ret;
...@@ -802,7 +832,7 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv, ...@@ -802,7 +832,7 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv,
/* A global client marked as PENDING has already moved from that /* A global client marked as PENDING has already moved from that
* originator */ * originator */
if (tt_global_entry->flags & TT_CLIENT_PENDING) if (tt_global_entry->common.flags & TT_CLIENT_PENDING)
goto out; goto out;
orig_node = tt_global_entry->orig_node; orig_node = tt_global_entry->orig_node;
...@@ -821,6 +851,7 @@ uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node) ...@@ -821,6 +851,7 @@ uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
{ {
uint16_t total = 0, total_one; uint16_t total = 0, total_one;
struct hashtable_t *hash = bat_priv->tt_global_hash; struct hashtable_t *hash = bat_priv->tt_global_hash;
struct tt_common_entry *tt_common_entry;
struct tt_global_entry *tt_global_entry; struct tt_global_entry *tt_global_entry;
struct hlist_node *node; struct hlist_node *node;
struct hlist_head *head; struct hlist_head *head;
...@@ -831,20 +862,23 @@ uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node) ...@@ -831,20 +862,23 @@ uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
head = &hash->table[i]; head = &hash->table[i];
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(tt_global_entry, node, hlist_for_each_entry_rcu(tt_common_entry, node,
head, hash_entry) { head, hash_entry) {
tt_global_entry = container_of(tt_common_entry,
struct tt_global_entry,
common);
if (compare_eth(tt_global_entry->orig_node, if (compare_eth(tt_global_entry->orig_node,
orig_node)) { orig_node)) {
/* Roaming clients are in the global table for /* Roaming clients are in the global table for
* consistency only. They don't have to be * consistency only. They don't have to be
* taken into account while computing the * taken into account while computing the
* global crc */ * global crc */
if (tt_global_entry->flags & TT_CLIENT_ROAM) if (tt_common_entry->flags & TT_CLIENT_ROAM)
continue; continue;
total_one = 0; total_one = 0;
for (j = 0; j < ETH_ALEN; j++) for (j = 0; j < ETH_ALEN; j++)
total_one = crc16_byte(total_one, total_one = crc16_byte(total_one,
tt_global_entry->addr[j]); tt_common_entry->addr[j]);
total ^= total_one; total ^= total_one;
} }
} }
...@@ -859,7 +893,7 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv) ...@@ -859,7 +893,7 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv)
{ {
uint16_t total = 0, total_one; uint16_t total = 0, total_one;
struct hashtable_t *hash = bat_priv->tt_local_hash; struct hashtable_t *hash = bat_priv->tt_local_hash;
struct tt_local_entry *tt_local_entry; struct tt_common_entry *tt_common_entry;
struct hlist_node *node; struct hlist_node *node;
struct hlist_head *head; struct hlist_head *head;
uint32_t i; uint32_t i;
...@@ -869,16 +903,16 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv) ...@@ -869,16 +903,16 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv)
head = &hash->table[i]; head = &hash->table[i];
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(tt_local_entry, node, hlist_for_each_entry_rcu(tt_common_entry, node,
head, hash_entry) { head, hash_entry) {
/* not yet committed clients have not to be taken into /* not yet committed clients have not to be taken into
* account while computing the CRC */ * account while computing the CRC */
if (tt_local_entry->flags & TT_CLIENT_NEW) if (tt_common_entry->flags & TT_CLIENT_NEW)
continue; continue;
total_one = 0; total_one = 0;
for (j = 0; j < ETH_ALEN; j++) for (j = 0; j < ETH_ALEN; j++)
total_one = crc16_byte(total_one, total_one = crc16_byte(total_one,
tt_local_entry->addr[j]); tt_common_entry->addr[j]);
total ^= total_one; total ^= total_one;
} }
rcu_read_unlock(); rcu_read_unlock();
...@@ -967,21 +1001,25 @@ static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv, ...@@ -967,21 +1001,25 @@ static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
/* data_ptr is useless here, but has to be kept to respect the prototype */ /* 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) static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
{ {
const struct tt_local_entry *tt_local_entry = entry_ptr; const struct tt_common_entry *tt_common_entry = entry_ptr;
if (tt_local_entry->flags & TT_CLIENT_NEW) if (tt_common_entry->flags & TT_CLIENT_NEW)
return 0; return 0;
return 1; return 1;
} }
static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr) static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
{ {
const struct tt_global_entry *tt_global_entry = entry_ptr; const struct tt_common_entry *tt_common_entry = entry_ptr;
const struct tt_global_entry *tt_global_entry;
const struct orig_node *orig_node = data_ptr; const struct orig_node *orig_node = data_ptr;
if (tt_global_entry->flags & TT_CLIENT_ROAM) if (tt_common_entry->flags & TT_CLIENT_ROAM)
return 0; return 0;
tt_global_entry = container_of(tt_common_entry, struct tt_global_entry,
common);
return (tt_global_entry->orig_node == orig_node); return (tt_global_entry->orig_node == orig_node);
} }
...@@ -992,7 +1030,7 @@ static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, ...@@ -992,7 +1030,7 @@ static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
const void *), const void *),
void *cb_data) void *cb_data)
{ {
struct tt_local_entry *tt_local_entry; struct tt_common_entry *tt_common_entry;
struct tt_query_packet *tt_response; struct tt_query_packet *tt_response;
struct tt_change *tt_change; struct tt_change *tt_change;
struct hlist_node *node; struct hlist_node *node;
...@@ -1024,15 +1062,16 @@ static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, ...@@ -1024,15 +1062,16 @@ static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
for (i = 0; i < hash->size; i++) { for (i = 0; i < hash->size; i++) {
head = &hash->table[i]; head = &hash->table[i];
hlist_for_each_entry_rcu(tt_local_entry, node, hlist_for_each_entry_rcu(tt_common_entry, node,
head, hash_entry) { head, hash_entry) {
if (tt_count == tt_tot) if (tt_count == tt_tot)
break; break;
if ((valid_cb) && (!valid_cb(tt_local_entry, cb_data))) if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
continue; continue;
memcpy(tt_change->addr, tt_local_entry->addr, ETH_ALEN); memcpy(tt_change->addr, tt_common_entry->addr,
ETH_ALEN);
tt_change->flags = NO_FLAGS; tt_change->flags = NO_FLAGS;
tt_count++; tt_count++;
...@@ -1449,7 +1488,7 @@ bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr) ...@@ -1449,7 +1488,7 @@ bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
goto out; goto out;
/* Check if the client has been logically deleted (but is kept for /* Check if the client has been logically deleted (but is kept for
* consistency purpose) */ * consistency purpose) */
if (tt_local_entry->flags & TT_CLIENT_PENDING) if (tt_local_entry->common.flags & TT_CLIENT_PENDING)
goto out; goto out;
ret = true; ret = true;
out: out:
...@@ -1672,40 +1711,48 @@ void tt_free(struct bat_priv *bat_priv) ...@@ -1672,40 +1711,48 @@ void tt_free(struct bat_priv *bat_priv)
kfree(bat_priv->tt_buff); kfree(bat_priv->tt_buff);
} }
/* This function will reset the specified flags from all the entries in /* This function will enable or disable the specified flags for all the entries
* the given hash table and will increment num_local_tt for each involved * in the given hash table and returns the number of modified entries */
* entry */ static uint16_t tt_set_flags(struct hashtable_t *hash, uint16_t flags,
static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags) bool enable)
{ {
uint32_t i; uint32_t i;
struct hashtable_t *hash = bat_priv->tt_local_hash; uint16_t changed_num = 0;
struct hlist_head *head; struct hlist_head *head;
struct hlist_node *node; struct hlist_node *node;
struct tt_local_entry *tt_local_entry; struct tt_common_entry *tt_common_entry;
if (!hash) if (!hash)
return; goto out;
for (i = 0; i < hash->size; i++) { for (i = 0; i < hash->size; i++) {
head = &hash->table[i]; head = &hash->table[i];
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(tt_local_entry, node, hlist_for_each_entry_rcu(tt_common_entry, node,
head, hash_entry) { head, hash_entry) {
if (!(tt_local_entry->flags & flags)) if (enable) {
if ((tt_common_entry->flags & flags) == flags)
continue;
tt_common_entry->flags |= flags;
} else {
if (!(tt_common_entry->flags & flags))
continue; continue;
tt_local_entry->flags &= ~flags; tt_common_entry->flags &= ~flags;
atomic_inc(&bat_priv->num_local_tt); }
changed_num++;
} }
rcu_read_unlock(); rcu_read_unlock();
} }
out:
return changed_num;
} }
/* Purge out all the tt local entries marked with TT_CLIENT_PENDING */ /* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
static void tt_local_purge_pending_clients(struct bat_priv *bat_priv) static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
{ {
struct hashtable_t *hash = bat_priv->tt_local_hash; struct hashtable_t *hash = bat_priv->tt_local_hash;
struct tt_common_entry *tt_common_entry;
struct tt_local_entry *tt_local_entry; struct tt_local_entry *tt_local_entry;
struct hlist_node *node, *node_tmp; struct hlist_node *node, *node_tmp;
struct hlist_head *head; struct hlist_head *head;
...@@ -1720,16 +1767,19 @@ static void tt_local_purge_pending_clients(struct bat_priv *bat_priv) ...@@ -1720,16 +1767,19 @@ static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
list_lock = &hash->list_locks[i]; list_lock = &hash->list_locks[i];
spin_lock_bh(list_lock); spin_lock_bh(list_lock);
hlist_for_each_entry_safe(tt_local_entry, node, node_tmp, hlist_for_each_entry_safe(tt_common_entry, node, node_tmp,
head, hash_entry) { head, hash_entry) {
if (!(tt_local_entry->flags & TT_CLIENT_PENDING)) if (!(tt_common_entry->flags & TT_CLIENT_PENDING))
continue; continue;
bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry " bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry "
"(%pM): pending\n", tt_local_entry->addr); "(%pM): pending\n", tt_common_entry->addr);
atomic_dec(&bat_priv->num_local_tt); atomic_dec(&bat_priv->num_local_tt);
hlist_del_rcu(node); hlist_del_rcu(node);
tt_local_entry = container_of(tt_common_entry,
struct tt_local_entry,
common);
tt_local_entry_free_ref(tt_local_entry); tt_local_entry_free_ref(tt_local_entry);
} }
spin_unlock_bh(list_lock); spin_unlock_bh(list_lock);
...@@ -1739,7 +1789,11 @@ static void tt_local_purge_pending_clients(struct bat_priv *bat_priv) ...@@ -1739,7 +1789,11 @@ static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
void tt_commit_changes(struct bat_priv *bat_priv) void tt_commit_changes(struct bat_priv *bat_priv)
{ {
tt_local_reset_flags(bat_priv, TT_CLIENT_NEW); uint16_t changed_num = tt_set_flags(bat_priv->tt_local_hash,
TT_CLIENT_NEW, false);
/* all the reset entries have now to be effectively counted as local
* entries */
atomic_add(changed_num, &bat_priv->num_local_tt);
tt_local_purge_pending_clients(bat_priv); tt_local_purge_pending_clients(bat_priv);
/* Increment the TTVN only once per OGM interval */ /* Increment the TTVN only once per OGM interval */
......
...@@ -222,24 +222,24 @@ struct socket_packet { ...@@ -222,24 +222,24 @@ struct socket_packet {
struct icmp_packet_rr icmp_packet; struct icmp_packet_rr icmp_packet;
}; };
struct tt_local_entry { struct tt_common_entry {
uint8_t addr[ETH_ALEN]; uint8_t addr[ETH_ALEN];
struct hlist_node hash_entry; struct hlist_node hash_entry;
unsigned long last_seen;
uint16_t flags; uint16_t flags;
atomic_t refcount; atomic_t refcount;
struct rcu_head rcu; struct rcu_head rcu;
}; };
struct tt_local_entry {
struct tt_common_entry common;
unsigned long last_seen;
};
struct tt_global_entry { struct tt_global_entry {
uint8_t addr[ETH_ALEN]; struct tt_common_entry common;
struct hlist_node hash_entry; /* entry in the global table */
struct orig_node *orig_node; struct orig_node *orig_node;
uint8_t ttvn; uint8_t ttvn;
uint16_t flags; /* only TT_GLOBAL_ROAM is used */
unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */ unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */
atomic_t refcount;
struct rcu_head rcu;
}; };
struct tt_change_node { struct tt_change_node {
......
...@@ -609,7 +609,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv) ...@@ -609,7 +609,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
struct vis_info *info = bat_priv->my_vis_info; struct vis_info *info = bat_priv->my_vis_info;
struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data; struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data;
struct vis_info_entry *entry; struct vis_info_entry *entry;
struct tt_local_entry *tt_local_entry; struct tt_common_entry *tt_common_entry;
int best_tq = -1; int best_tq = -1;
uint32_t i; uint32_t i;
...@@ -672,13 +672,13 @@ static int generate_vis_packet(struct bat_priv *bat_priv) ...@@ -672,13 +672,13 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
head = &hash->table[i]; head = &hash->table[i];
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(tt_local_entry, node, head, hlist_for_each_entry_rcu(tt_common_entry, node, head,
hash_entry) { hash_entry) {
entry = (struct vis_info_entry *) entry = (struct vis_info_entry *)
skb_put(info->skb_packet, skb_put(info->skb_packet,
sizeof(*entry)); sizeof(*entry));
memset(entry->src, 0, ETH_ALEN); memset(entry->src, 0, ETH_ALEN);
memcpy(entry->dest, tt_local_entry->addr, ETH_ALEN); memcpy(entry->dest, tt_common_entry->addr, ETH_ALEN);
entry->quality = 0; /* 0 means TT */ entry->quality = 0; /* 0 means TT */
packet->entries++; packet->entries++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment