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

Merge tag 'batadv-net-for-davem-20180524' of git://git.open-mesh.org/linux-merge

Simon Wunderlich says:

====================
Here are some batman-adv bugfixes:

 - prevent hardif_put call with NULL parameter, by Colin Ian King

 - Avoid race in Translation Table allocator, by Sven Eckelmann

 - Fix Translation Table sync flags for intermediate Responses,
   by Linus Luessing

 - prevent sending inconsistent Translation Table TVLVs,
   by Marek Lindner
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1383cb81 16116dac
...@@ -1536,7 +1536,7 @@ batadv_mcast_netlink_get_primary(struct netlink_callback *cb, ...@@ -1536,7 +1536,7 @@ batadv_mcast_netlink_get_primary(struct netlink_callback *cb,
if (!ret && primary_if) if (!ret && primary_if)
*primary_if = hard_iface; *primary_if = hard_iface;
else else if (hard_iface)
batadv_hardif_put(hard_iface); batadv_hardif_put(hard_iface);
return ret; return ret;
......
...@@ -862,7 +862,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, ...@@ -862,7 +862,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
struct batadv_orig_node_vlan *vlan; struct batadv_orig_node_vlan *vlan;
u8 *tt_change_ptr; u8 *tt_change_ptr;
rcu_read_lock(); spin_lock_bh(&orig_node->vlan_list_lock);
hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
num_vlan++; num_vlan++;
num_entries += atomic_read(&vlan->tt.num_entries); num_entries += atomic_read(&vlan->tt.num_entries);
...@@ -900,7 +900,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, ...@@ -900,7 +900,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
*tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;
out: out:
rcu_read_unlock(); spin_unlock_bh(&orig_node->vlan_list_lock);
return tvlv_len; return tvlv_len;
} }
...@@ -931,15 +931,20 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, ...@@ -931,15 +931,20 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_tvlv_tt_vlan_data *tt_vlan;
struct batadv_softif_vlan *vlan; struct batadv_softif_vlan *vlan;
u16 num_vlan = 0; u16 num_vlan = 0;
u16 num_entries = 0; u16 vlan_entries = 0;
u16 total_entries = 0;
u16 tvlv_len; u16 tvlv_len;
u8 *tt_change_ptr; u8 *tt_change_ptr;
int change_offset; int change_offset;
rcu_read_lock(); spin_lock_bh(&bat_priv->softif_vlan_list_lock);
hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
vlan_entries = atomic_read(&vlan->tt.num_entries);
if (vlan_entries < 1)
continue;
num_vlan++; num_vlan++;
num_entries += atomic_read(&vlan->tt.num_entries); total_entries += vlan_entries;
} }
change_offset = sizeof(**tt_data); change_offset = sizeof(**tt_data);
...@@ -947,7 +952,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, ...@@ -947,7 +952,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
/* if tt_len is negative, allocate the space needed by the full table */ /* if tt_len is negative, allocate the space needed by the full table */
if (*tt_len < 0) if (*tt_len < 0)
*tt_len = batadv_tt_len(num_entries); *tt_len = batadv_tt_len(total_entries);
tvlv_len = *tt_len; tvlv_len = *tt_len;
tvlv_len += change_offset; tvlv_len += change_offset;
...@@ -964,6 +969,10 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, ...@@ -964,6 +969,10 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
vlan_entries = atomic_read(&vlan->tt.num_entries);
if (vlan_entries < 1)
continue;
tt_vlan->vid = htons(vlan->vid); tt_vlan->vid = htons(vlan->vid);
tt_vlan->crc = htonl(vlan->tt.crc); tt_vlan->crc = htonl(vlan->tt.crc);
...@@ -974,7 +983,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, ...@@ -974,7 +983,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
*tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;
out: out:
rcu_read_unlock(); spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
return tvlv_len; return tvlv_len;
} }
...@@ -1538,6 +1547,8 @@ batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, ...@@ -1538,6 +1547,8 @@ batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
* handled by a given originator * handled by a given originator
* @entry: the TT global entry to check * @entry: the TT global entry to check
* @orig_node: the originator to search in the list * @orig_node: the originator to search in the list
* @flags: a pointer to store TT flags for the given @entry received
* from @orig_node
* *
* find out if an orig_node is already in the list of a tt_global_entry. * find out if an orig_node is already in the list of a tt_global_entry.
* *
...@@ -1545,7 +1556,8 @@ batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, ...@@ -1545,7 +1556,8 @@ batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
*/ */
static bool static bool
batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
const struct batadv_orig_node *orig_node) const struct batadv_orig_node *orig_node,
u8 *flags)
{ {
struct batadv_tt_orig_list_entry *orig_entry; struct batadv_tt_orig_list_entry *orig_entry;
bool found = false; bool found = false;
...@@ -1553,6 +1565,10 @@ batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, ...@@ -1553,6 +1565,10 @@ batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node); orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node);
if (orig_entry) { if (orig_entry) {
found = true; found = true;
if (flags)
*flags = orig_entry->flags;
batadv_tt_orig_list_entry_put(orig_entry); batadv_tt_orig_list_entry_put(orig_entry);
} }
...@@ -1731,7 +1747,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv, ...@@ -1731,7 +1747,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
if (!(common->flags & BATADV_TT_CLIENT_TEMP)) if (!(common->flags & BATADV_TT_CLIENT_TEMP))
goto out; goto out;
if (batadv_tt_global_entry_has_orig(tt_global_entry, if (batadv_tt_global_entry_has_orig(tt_global_entry,
orig_node)) orig_node, NULL))
goto out_remove; goto out_remove;
batadv_tt_global_del_orig_list(tt_global_entry); batadv_tt_global_del_orig_list(tt_global_entry);
goto add_orig_entry; goto add_orig_entry;
...@@ -2880,23 +2896,46 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv, ...@@ -2880,23 +2896,46 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv,
} }
/** /**
* batadv_tt_local_valid() - verify that given tt entry is a valid one * batadv_tt_local_valid() - verify local tt entry and get flags
* @entry_ptr: to be checked local tt entry * @entry_ptr: to be checked local tt entry
* @data_ptr: not used but definition required to satisfy the callback prototype * @data_ptr: not used but definition required to satisfy the callback prototype
* @flags: a pointer to store TT flags for this client to
*
* Checks the validity of the given local TT entry. If it is, then the provided
* flags pointer is updated.
* *
* Return: true if the entry is a valid, false otherwise. * Return: true if the entry is a valid, false otherwise.
*/ */
static bool batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr) static bool batadv_tt_local_valid(const void *entry_ptr,
const void *data_ptr,
u8 *flags)
{ {
const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
return false; return false;
if (flags)
*flags = tt_common_entry->flags;
return true; return true;
} }
/**
* batadv_tt_global_valid() - verify global tt entry and get flags
* @entry_ptr: to be checked global tt entry
* @data_ptr: an orig_node object (may be NULL)
* @flags: a pointer to store TT flags for this client to
*
* Checks the validity of the given global TT entry. If it is, then the provided
* flags pointer is updated either with the common (summed) TT flags if data_ptr
* is NULL or the specific, per originator TT flags otherwise.
*
* Return: true if the entry is a valid, false otherwise.
*/
static bool batadv_tt_global_valid(const void *entry_ptr, static bool batadv_tt_global_valid(const void *entry_ptr,
const void *data_ptr) const void *data_ptr,
u8 *flags)
{ {
const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
const struct batadv_tt_global_entry *tt_global_entry; const struct batadv_tt_global_entry *tt_global_entry;
...@@ -2910,7 +2949,8 @@ static bool batadv_tt_global_valid(const void *entry_ptr, ...@@ -2910,7 +2949,8 @@ static bool batadv_tt_global_valid(const void *entry_ptr,
struct batadv_tt_global_entry, struct batadv_tt_global_entry,
common); common);
return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node,
flags);
} }
/** /**
...@@ -2920,25 +2960,34 @@ static bool batadv_tt_global_valid(const void *entry_ptr, ...@@ -2920,25 +2960,34 @@ static bool batadv_tt_global_valid(const void *entry_ptr,
* @hash: hash table containing the tt entries * @hash: hash table containing the tt entries
* @tt_len: expected tvlv tt data buffer length in number of bytes * @tt_len: expected tvlv tt data buffer length in number of bytes
* @tvlv_buff: pointer to the buffer to fill with the TT data * @tvlv_buff: pointer to the buffer to fill with the TT data
* @valid_cb: function to filter tt change entries * @valid_cb: function to filter tt change entries and to return TT flags
* @cb_data: data passed to the filter function as argument * @cb_data: data passed to the filter function as argument
*
* Fills the tvlv buff with the tt entries from the specified hash. If valid_cb
* is not provided then this becomes a no-op.
*/ */
static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
struct batadv_hashtable *hash, struct batadv_hashtable *hash,
void *tvlv_buff, u16 tt_len, void *tvlv_buff, u16 tt_len,
bool (*valid_cb)(const void *, bool (*valid_cb)(const void *,
const void *), const void *,
u8 *flags),
void *cb_data) void *cb_data)
{ {
struct batadv_tt_common_entry *tt_common_entry; struct batadv_tt_common_entry *tt_common_entry;
struct batadv_tvlv_tt_change *tt_change; struct batadv_tvlv_tt_change *tt_change;
struct hlist_head *head; struct hlist_head *head;
u16 tt_tot, tt_num_entries = 0; u16 tt_tot, tt_num_entries = 0;
u8 flags;
bool ret;
u32 i; u32 i;
tt_tot = batadv_tt_entries(tt_len); tt_tot = batadv_tt_entries(tt_len);
tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff;
if (!valid_cb)
return;
rcu_read_lock(); rcu_read_lock();
for (i = 0; i < hash->size; i++) { for (i = 0; i < hash->size; i++) {
head = &hash->table[i]; head = &hash->table[i];
...@@ -2948,11 +2997,12 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, ...@@ -2948,11 +2997,12 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
if (tt_tot == tt_num_entries) if (tt_tot == tt_num_entries)
break; break;
if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) ret = valid_cb(tt_common_entry, cb_data, &flags);
if (!ret)
continue; continue;
ether_addr_copy(tt_change->addr, tt_common_entry->addr); ether_addr_copy(tt_change->addr, tt_common_entry->addr);
tt_change->flags = tt_common_entry->flags; tt_change->flags = flags;
tt_change->vid = htons(tt_common_entry->vid); tt_change->vid = htons(tt_common_entry->vid);
memset(tt_change->reserved, 0, memset(tt_change->reserved, 0,
sizeof(tt_change->reserved)); sizeof(tt_change->reserved));
......
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