diff options
| author | David S. Miller <davem@davemloft.net> | 2018-05-25 14:54:19 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2018-05-25 14:54:19 -0400 |
| commit | e3ffec48b22f3427a576ab6ca58ba5e9c46923f2 (patch) | |
| tree | 2632770c11d4cc3aaafdb07f426a8519351b8188 /net | |
| parent | 1383cb8103bb166e50cbab1543bb3b5118fccf82 (diff) | |
| parent | 16116dac23396e73c01eeee97b102e4833a4b205 (diff) | |
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: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
| -rw-r--r-- | net/batman-adv/multicast.c | 2 | ||||
| -rw-r--r-- | net/batman-adv/translation-table.c | 84 |
2 files changed, 68 insertions, 18 deletions
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index a11d3d89f012..a35f597e8c8b 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c | |||
| @@ -1536,7 +1536,7 @@ out: | |||
| 1536 | 1536 | ||
| 1537 | if (!ret && primary_if) | 1537 | if (!ret && primary_if) |
| 1538 | *primary_if = hard_iface; | 1538 | *primary_if = hard_iface; |
| 1539 | else | 1539 | else if (hard_iface) |
| 1540 | batadv_hardif_put(hard_iface); | 1540 | batadv_hardif_put(hard_iface); |
| 1541 | 1541 | ||
| 1542 | return ret; | 1542 | return ret; |
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 0225616d5771..3986551397ca 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c | |||
| @@ -862,7 +862,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, | |||
| 862 | struct batadv_orig_node_vlan *vlan; | 862 | struct batadv_orig_node_vlan *vlan; |
| 863 | u8 *tt_change_ptr; | 863 | u8 *tt_change_ptr; |
| 864 | 864 | ||
| 865 | rcu_read_lock(); | 865 | spin_lock_bh(&orig_node->vlan_list_lock); |
| 866 | hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { | 866 | hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { |
| 867 | num_vlan++; | 867 | num_vlan++; |
| 868 | num_entries += atomic_read(&vlan->tt.num_entries); | 868 | 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 | *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; | 900 | *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; |
| 901 | 901 | ||
| 902 | out: | 902 | out: |
| 903 | rcu_read_unlock(); | 903 | spin_unlock_bh(&orig_node->vlan_list_lock); |
| 904 | return tvlv_len; | 904 | return tvlv_len; |
| 905 | } | 905 | } |
| 906 | 906 | ||
| @@ -931,15 +931,20 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, | |||
| 931 | struct batadv_tvlv_tt_vlan_data *tt_vlan; | 931 | struct batadv_tvlv_tt_vlan_data *tt_vlan; |
| 932 | struct batadv_softif_vlan *vlan; | 932 | struct batadv_softif_vlan *vlan; |
| 933 | u16 num_vlan = 0; | 933 | u16 num_vlan = 0; |
| 934 | u16 num_entries = 0; | 934 | u16 vlan_entries = 0; |
| 935 | u16 total_entries = 0; | ||
| 935 | u16 tvlv_len; | 936 | u16 tvlv_len; |
| 936 | u8 *tt_change_ptr; | 937 | u8 *tt_change_ptr; |
| 937 | int change_offset; | 938 | int change_offset; |
| 938 | 939 | ||
| 939 | rcu_read_lock(); | 940 | spin_lock_bh(&bat_priv->softif_vlan_list_lock); |
| 940 | hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { | 941 | hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { |
| 942 | vlan_entries = atomic_read(&vlan->tt.num_entries); | ||
| 943 | if (vlan_entries < 1) | ||
| 944 | continue; | ||
| 945 | |||
| 941 | num_vlan++; | 946 | num_vlan++; |
| 942 | num_entries += atomic_read(&vlan->tt.num_entries); | 947 | total_entries += vlan_entries; |
| 943 | } | 948 | } |
| 944 | 949 | ||
| 945 | change_offset = sizeof(**tt_data); | 950 | change_offset = sizeof(**tt_data); |
| @@ -947,7 +952,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, | |||
| 947 | 952 | ||
| 948 | /* if tt_len is negative, allocate the space needed by the full table */ | 953 | /* if tt_len is negative, allocate the space needed by the full table */ |
| 949 | if (*tt_len < 0) | 954 | if (*tt_len < 0) |
| 950 | *tt_len = batadv_tt_len(num_entries); | 955 | *tt_len = batadv_tt_len(total_entries); |
| 951 | 956 | ||
| 952 | tvlv_len = *tt_len; | 957 | tvlv_len = *tt_len; |
| 953 | tvlv_len += change_offset; | 958 | tvlv_len += change_offset; |
| @@ -964,6 +969,10 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, | |||
| 964 | 969 | ||
| 965 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); | 970 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); |
| 966 | hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { | 971 | hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { |
| 972 | vlan_entries = atomic_read(&vlan->tt.num_entries); | ||
| 973 | if (vlan_entries < 1) | ||
| 974 | continue; | ||
| 975 | |||
| 967 | tt_vlan->vid = htons(vlan->vid); | 976 | tt_vlan->vid = htons(vlan->vid); |
| 968 | tt_vlan->crc = htonl(vlan->tt.crc); | 977 | tt_vlan->crc = htonl(vlan->tt.crc); |
| 969 | 978 | ||
| @@ -974,7 +983,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, | |||
| 974 | *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; | 983 | *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; |
| 975 | 984 | ||
| 976 | out: | 985 | out: |
| 977 | rcu_read_unlock(); | 986 | spin_unlock_bh(&bat_priv->softif_vlan_list_lock); |
| 978 | return tvlv_len; | 987 | return tvlv_len; |
| 979 | } | 988 | } |
| 980 | 989 | ||
| @@ -1538,6 +1547,8 @@ batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, | |||
| 1538 | * handled by a given originator | 1547 | * handled by a given originator |
| 1539 | * @entry: the TT global entry to check | 1548 | * @entry: the TT global entry to check |
| 1540 | * @orig_node: the originator to search in the list | 1549 | * @orig_node: the originator to search in the list |
| 1550 | * @flags: a pointer to store TT flags for the given @entry received | ||
| 1551 | * from @orig_node | ||
| 1541 | * | 1552 | * |
| 1542 | * find out if an orig_node is already in the list of a tt_global_entry. | 1553 | * find out if an orig_node is already in the list of a tt_global_entry. |
| 1543 | * | 1554 | * |
| @@ -1545,7 +1556,8 @@ batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, | |||
| 1545 | */ | 1556 | */ |
| 1546 | static bool | 1557 | static bool |
| 1547 | batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, | 1558 | batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, |
| 1548 | const struct batadv_orig_node *orig_node) | 1559 | const struct batadv_orig_node *orig_node, |
| 1560 | u8 *flags) | ||
| 1549 | { | 1561 | { |
| 1550 | struct batadv_tt_orig_list_entry *orig_entry; | 1562 | struct batadv_tt_orig_list_entry *orig_entry; |
| 1551 | bool found = false; | 1563 | bool found = false; |
| @@ -1553,6 +1565,10 @@ batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, | |||
| 1553 | orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node); | 1565 | orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node); |
| 1554 | if (orig_entry) { | 1566 | if (orig_entry) { |
| 1555 | found = true; | 1567 | found = true; |
| 1568 | |||
| 1569 | if (flags) | ||
| 1570 | *flags = orig_entry->flags; | ||
| 1571 | |||
| 1556 | batadv_tt_orig_list_entry_put(orig_entry); | 1572 | batadv_tt_orig_list_entry_put(orig_entry); |
| 1557 | } | 1573 | } |
| 1558 | 1574 | ||
| @@ -1731,7 +1747,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv, | |||
| 1731 | if (!(common->flags & BATADV_TT_CLIENT_TEMP)) | 1747 | if (!(common->flags & BATADV_TT_CLIENT_TEMP)) |
| 1732 | goto out; | 1748 | goto out; |
| 1733 | if (batadv_tt_global_entry_has_orig(tt_global_entry, | 1749 | if (batadv_tt_global_entry_has_orig(tt_global_entry, |
| 1734 | orig_node)) | 1750 | orig_node, NULL)) |
| 1735 | goto out_remove; | 1751 | goto out_remove; |
| 1736 | batadv_tt_global_del_orig_list(tt_global_entry); | 1752 | batadv_tt_global_del_orig_list(tt_global_entry); |
| 1737 | goto add_orig_entry; | 1753 | goto add_orig_entry; |
| @@ -2880,23 +2896,46 @@ unlock: | |||
| 2880 | } | 2896 | } |
| 2881 | 2897 | ||
| 2882 | /** | 2898 | /** |
| 2883 | * batadv_tt_local_valid() - verify that given tt entry is a valid one | 2899 | * batadv_tt_local_valid() - verify local tt entry and get flags |
| 2884 | * @entry_ptr: to be checked local tt entry | 2900 | * @entry_ptr: to be checked local tt entry |
| 2885 | * @data_ptr: not used but definition required to satisfy the callback prototype | 2901 | * @data_ptr: not used but definition required to satisfy the callback prototype |
| 2902 | * @flags: a pointer to store TT flags for this client to | ||
| 2903 | * | ||
| 2904 | * Checks the validity of the given local TT entry. If it is, then the provided | ||
| 2905 | * flags pointer is updated. | ||
| 2886 | * | 2906 | * |
| 2887 | * Return: true if the entry is a valid, false otherwise. | 2907 | * Return: true if the entry is a valid, false otherwise. |
| 2888 | */ | 2908 | */ |
| 2889 | static bool batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr) | 2909 | static bool batadv_tt_local_valid(const void *entry_ptr, |
| 2910 | const void *data_ptr, | ||
| 2911 | u8 *flags) | ||
| 2890 | { | 2912 | { |
| 2891 | const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; | 2913 | const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; |
| 2892 | 2914 | ||
| 2893 | if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) | 2915 | if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) |
| 2894 | return false; | 2916 | return false; |
| 2917 | |||
| 2918 | if (flags) | ||
| 2919 | *flags = tt_common_entry->flags; | ||
| 2920 | |||
| 2895 | return true; | 2921 | return true; |
| 2896 | } | 2922 | } |
| 2897 | 2923 | ||
| 2924 | /** | ||
| 2925 | * batadv_tt_global_valid() - verify global tt entry and get flags | ||
| 2926 | * @entry_ptr: to be checked global tt entry | ||
| 2927 | * @data_ptr: an orig_node object (may be NULL) | ||
| 2928 | * @flags: a pointer to store TT flags for this client to | ||
| 2929 | * | ||
| 2930 | * Checks the validity of the given global TT entry. If it is, then the provided | ||
| 2931 | * flags pointer is updated either with the common (summed) TT flags if data_ptr | ||
| 2932 | * is NULL or the specific, per originator TT flags otherwise. | ||
| 2933 | * | ||
| 2934 | * Return: true if the entry is a valid, false otherwise. | ||
| 2935 | */ | ||
| 2898 | static bool batadv_tt_global_valid(const void *entry_ptr, | 2936 | static bool batadv_tt_global_valid(const void *entry_ptr, |
| 2899 | const void *data_ptr) | 2937 | const void *data_ptr, |
| 2938 | u8 *flags) | ||
| 2900 | { | 2939 | { |
| 2901 | const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; | 2940 | const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; |
| 2902 | const struct batadv_tt_global_entry *tt_global_entry; | 2941 | const struct batadv_tt_global_entry *tt_global_entry; |
| @@ -2910,7 +2949,8 @@ static bool batadv_tt_global_valid(const void *entry_ptr, | |||
| 2910 | struct batadv_tt_global_entry, | 2949 | struct batadv_tt_global_entry, |
| 2911 | common); | 2950 | common); |
| 2912 | 2951 | ||
| 2913 | return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); | 2952 | return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node, |
| 2953 | flags); | ||
| 2914 | } | 2954 | } |
| 2915 | 2955 | ||
| 2916 | /** | 2956 | /** |
| @@ -2920,25 +2960,34 @@ static bool batadv_tt_global_valid(const void *entry_ptr, | |||
| 2920 | * @hash: hash table containing the tt entries | 2960 | * @hash: hash table containing the tt entries |
| 2921 | * @tt_len: expected tvlv tt data buffer length in number of bytes | 2961 | * @tt_len: expected tvlv tt data buffer length in number of bytes |
| 2922 | * @tvlv_buff: pointer to the buffer to fill with the TT data | 2962 | * @tvlv_buff: pointer to the buffer to fill with the TT data |
| 2923 | * @valid_cb: function to filter tt change entries | 2963 | * @valid_cb: function to filter tt change entries and to return TT flags |
| 2924 | * @cb_data: data passed to the filter function as argument | 2964 | * @cb_data: data passed to the filter function as argument |
| 2965 | * | ||
| 2966 | * Fills the tvlv buff with the tt entries from the specified hash. If valid_cb | ||
| 2967 | * is not provided then this becomes a no-op. | ||
| 2925 | */ | 2968 | */ |
| 2926 | static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, | 2969 | static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, |
| 2927 | struct batadv_hashtable *hash, | 2970 | struct batadv_hashtable *hash, |
| 2928 | void *tvlv_buff, u16 tt_len, | 2971 | void *tvlv_buff, u16 tt_len, |
| 2929 | bool (*valid_cb)(const void *, | 2972 | bool (*valid_cb)(const void *, |
| 2930 | const void *), | 2973 | const void *, |
| 2974 | u8 *flags), | ||
| 2931 | void *cb_data) | 2975 | void *cb_data) |
| 2932 | { | 2976 | { |
| 2933 | struct batadv_tt_common_entry *tt_common_entry; | 2977 | struct batadv_tt_common_entry *tt_common_entry; |
| 2934 | struct batadv_tvlv_tt_change *tt_change; | 2978 | struct batadv_tvlv_tt_change *tt_change; |
| 2935 | struct hlist_head *head; | 2979 | struct hlist_head *head; |
| 2936 | u16 tt_tot, tt_num_entries = 0; | 2980 | u16 tt_tot, tt_num_entries = 0; |
| 2981 | u8 flags; | ||
| 2982 | bool ret; | ||
| 2937 | u32 i; | 2983 | u32 i; |
| 2938 | 2984 | ||
| 2939 | tt_tot = batadv_tt_entries(tt_len); | 2985 | tt_tot = batadv_tt_entries(tt_len); |
| 2940 | tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; | 2986 | tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; |
| 2941 | 2987 | ||
| 2988 | if (!valid_cb) | ||
| 2989 | return; | ||
| 2990 | |||
| 2942 | rcu_read_lock(); | 2991 | rcu_read_lock(); |
| 2943 | for (i = 0; i < hash->size; i++) { | 2992 | for (i = 0; i < hash->size; i++) { |
| 2944 | head = &hash->table[i]; | 2993 | head = &hash->table[i]; |
| @@ -2948,11 +2997,12 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, | |||
| 2948 | if (tt_tot == tt_num_entries) | 2997 | if (tt_tot == tt_num_entries) |
| 2949 | break; | 2998 | break; |
| 2950 | 2999 | ||
| 2951 | if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) | 3000 | ret = valid_cb(tt_common_entry, cb_data, &flags); |
| 3001 | if (!ret) | ||
| 2952 | continue; | 3002 | continue; |
| 2953 | 3003 | ||
| 2954 | ether_addr_copy(tt_change->addr, tt_common_entry->addr); | 3004 | ether_addr_copy(tt_change->addr, tt_common_entry->addr); |
| 2955 | tt_change->flags = tt_common_entry->flags; | 3005 | tt_change->flags = flags; |
| 2956 | tt_change->vid = htons(tt_common_entry->vid); | 3006 | tt_change->vid = htons(tt_common_entry->vid); |
| 2957 | memset(tt_change->reserved, 0, | 3007 | memset(tt_change->reserved, 0, |
| 2958 | sizeof(tt_change->reserved)); | 3008 | sizeof(tt_change->reserved)); |
