| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
|---|
| 2 | | -/* Copyright (C) 2007-2018 B.A.T.M.A.N. contributors: |
|---|
| 2 | +/* Copyright (C) 2007-2020 B.A.T.M.A.N. contributors: |
|---|
| 3 | 3 | * |
|---|
| 4 | 4 | * Marek Lindner, Simon Wunderlich, Antonio Quartulli |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or |
|---|
| 7 | | - * modify it under the terms of version 2 of the GNU General Public |
|---|
| 8 | | - * License as published by the Free Software Foundation. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 11 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 13 | | - * General Public License for more details. |
|---|
| 14 | | - * |
|---|
| 15 | | - * You should have received a copy of the GNU General Public License |
|---|
| 16 | | - * along with this program; if not, see <http://www.gnu.org/licenses/>. |
|---|
| 17 | 5 | */ |
|---|
| 18 | 6 | |
|---|
| 19 | 7 | #include "translation-table.h" |
|---|
| .. | .. |
|---|
| 205 | 193 | * Return: a pointer to the corresponding tt_global_entry struct if the client |
|---|
| 206 | 194 | * is found, NULL otherwise. |
|---|
| 207 | 195 | */ |
|---|
| 208 | | -static struct batadv_tt_global_entry * |
|---|
| 196 | +struct batadv_tt_global_entry * |
|---|
| 209 | 197 | batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr, |
|---|
| 210 | 198 | unsigned short vid) |
|---|
| 211 | 199 | { |
|---|
| .. | .. |
|---|
| 260 | 248 | static void |
|---|
| 261 | 249 | batadv_tt_local_entry_put(struct batadv_tt_local_entry *tt_local_entry) |
|---|
| 262 | 250 | { |
|---|
| 251 | + if (!tt_local_entry) |
|---|
| 252 | + return; |
|---|
| 253 | + |
|---|
| 263 | 254 | kref_put(&tt_local_entry->common.refcount, |
|---|
| 264 | 255 | batadv_tt_local_entry_release); |
|---|
| 265 | 256 | } |
|---|
| .. | .. |
|---|
| 283 | 274 | * queue for free after rcu grace period |
|---|
| 284 | 275 | * @ref: kref pointer of the nc_node |
|---|
| 285 | 276 | */ |
|---|
| 286 | | -static void batadv_tt_global_entry_release(struct kref *ref) |
|---|
| 277 | +void batadv_tt_global_entry_release(struct kref *ref) |
|---|
| 287 | 278 | { |
|---|
| 288 | 279 | struct batadv_tt_global_entry *tt_global_entry; |
|---|
| 289 | 280 | |
|---|
| .. | .. |
|---|
| 296 | 287 | } |
|---|
| 297 | 288 | |
|---|
| 298 | 289 | /** |
|---|
| 299 | | - * batadv_tt_global_entry_put() - decrement the tt_global_entry refcounter and |
|---|
| 300 | | - * possibly release it |
|---|
| 301 | | - * @tt_global_entry: tt_global_entry to be free'd |
|---|
| 302 | | - */ |
|---|
| 303 | | -static void |
|---|
| 304 | | -batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry) |
|---|
| 305 | | -{ |
|---|
| 306 | | - kref_put(&tt_global_entry->common.refcount, |
|---|
| 307 | | - batadv_tt_global_entry_release); |
|---|
| 308 | | -} |
|---|
| 309 | | - |
|---|
| 310 | | -/** |
|---|
| 311 | 290 | * batadv_tt_global_hash_count() - count the number of orig entries |
|---|
| 312 | 291 | * @bat_priv: the bat priv with all the soft interface information |
|---|
| 313 | 292 | * @addr: the mac address of the client to count entries for |
|---|
| 314 | 293 | * @vid: VLAN identifier |
|---|
| 315 | 294 | * |
|---|
| 316 | 295 | * Return: the number of originators advertising the given address/data |
|---|
| 317 | | - * (excluding ourself). |
|---|
| 296 | + * (excluding our self). |
|---|
| 318 | 297 | */ |
|---|
| 319 | 298 | int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, |
|---|
| 320 | 299 | const u8 *addr, unsigned short vid) |
|---|
| .. | .. |
|---|
| 466 | 445 | static void |
|---|
| 467 | 446 | batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry) |
|---|
| 468 | 447 | { |
|---|
| 448 | + if (!orig_entry) |
|---|
| 449 | + return; |
|---|
| 450 | + |
|---|
| 469 | 451 | kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release); |
|---|
| 470 | 452 | } |
|---|
| 471 | 453 | |
|---|
| .. | .. |
|---|
| 793 | 775 | if (roamed_back) { |
|---|
| 794 | 776 | batadv_tt_global_free(bat_priv, tt_global, |
|---|
| 795 | 777 | "Roaming canceled"); |
|---|
| 796 | | - tt_global = NULL; |
|---|
| 797 | 778 | } else { |
|---|
| 798 | 779 | /* The global entry has to be marked as ROAMING and |
|---|
| 799 | 780 | * has to be kept for consistency purpose |
|---|
| .. | .. |
|---|
| 855 | 836 | * table. In case of success the value is updated with the real amount of |
|---|
| 856 | 837 | * reserved bytes |
|---|
| 857 | 838 | * Allocate the needed amount of memory for the entire TT TVLV and write its |
|---|
| 858 | | - * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data |
|---|
| 839 | + * header made up of one tvlv_tt_data object and a series of tvlv_tt_vlan_data |
|---|
| 859 | 840 | * objects, one per active VLAN served by the originator node. |
|---|
| 860 | 841 | * |
|---|
| 861 | 842 | * Return: the size of the allocated buffer or 0 in case of failure. |
|---|
| .. | .. |
|---|
| 875 | 856 | u8 *tt_change_ptr; |
|---|
| 876 | 857 | |
|---|
| 877 | 858 | spin_lock_bh(&orig_node->vlan_list_lock); |
|---|
| 878 | | - hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { |
|---|
| 859 | + hlist_for_each_entry(vlan, &orig_node->vlan_list, list) { |
|---|
| 879 | 860 | num_vlan++; |
|---|
| 880 | 861 | num_entries += atomic_read(&vlan->tt.num_entries); |
|---|
| 881 | 862 | } |
|---|
| .. | .. |
|---|
| 901 | 882 | (*tt_data)->num_vlan = htons(num_vlan); |
|---|
| 902 | 883 | |
|---|
| 903 | 884 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); |
|---|
| 904 | | - hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { |
|---|
| 885 | + hlist_for_each_entry(vlan, &orig_node->vlan_list, list) { |
|---|
| 905 | 886 | tt_vlan->vid = htons(vlan->vid); |
|---|
| 906 | 887 | tt_vlan->crc = htonl(vlan->tt.crc); |
|---|
| 907 | 888 | tt_vlan->reserved = 0; |
|---|
| .. | .. |
|---|
| 951 | 932 | int change_offset; |
|---|
| 952 | 933 | |
|---|
| 953 | 934 | spin_lock_bh(&bat_priv->softif_vlan_list_lock); |
|---|
| 954 | | - hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { |
|---|
| 935 | + hlist_for_each_entry(vlan, &bat_priv->softif_vlan_list, list) { |
|---|
| 955 | 936 | vlan_entries = atomic_read(&vlan->tt.num_entries); |
|---|
| 956 | 937 | if (vlan_entries < 1) |
|---|
| 957 | 938 | continue; |
|---|
| .. | .. |
|---|
| 981 | 962 | (*tt_data)->num_vlan = htons(num_vlan); |
|---|
| 982 | 963 | |
|---|
| 983 | 964 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); |
|---|
| 984 | | - hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { |
|---|
| 965 | + hlist_for_each_entry(vlan, &bat_priv->softif_vlan_list, list) { |
|---|
| 985 | 966 | vlan_entries = atomic_read(&vlan->tt.num_entries); |
|---|
| 986 | 967 | if (vlan_entries < 1) |
|---|
| 987 | 968 | continue; |
|---|
| .. | .. |
|---|
| 1159 | 1140 | * batadv_tt_local_dump_entry() - Dump one TT local entry into a message |
|---|
| 1160 | 1141 | * @msg :Netlink message to dump into |
|---|
| 1161 | 1142 | * @portid: Port making netlink request |
|---|
| 1162 | | - * @seq: Sequence number of netlink message |
|---|
| 1143 | + * @cb: Control block containing additional options |
|---|
| 1163 | 1144 | * @bat_priv: The bat priv with all the soft interface information |
|---|
| 1164 | 1145 | * @common: tt local & tt global common data |
|---|
| 1165 | 1146 | * |
|---|
| 1166 | 1147 | * Return: Error code, or 0 on success |
|---|
| 1167 | 1148 | */ |
|---|
| 1168 | 1149 | static int |
|---|
| 1169 | | -batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, |
|---|
| 1150 | +batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid, |
|---|
| 1151 | + struct netlink_callback *cb, |
|---|
| 1170 | 1152 | struct batadv_priv *bat_priv, |
|---|
| 1171 | 1153 | struct batadv_tt_common_entry *common) |
|---|
| 1172 | 1154 | { |
|---|
| .. | .. |
|---|
| 1187 | 1169 | |
|---|
| 1188 | 1170 | batadv_softif_vlan_put(vlan); |
|---|
| 1189 | 1171 | |
|---|
| 1190 | | - hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, |
|---|
| 1191 | | - NLM_F_MULTI, |
|---|
| 1172 | + hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq, |
|---|
| 1173 | + &batadv_netlink_family, NLM_F_MULTI, |
|---|
| 1192 | 1174 | BATADV_CMD_GET_TRANSTABLE_LOCAL); |
|---|
| 1193 | 1175 | if (!hdr) |
|---|
| 1194 | 1176 | return -ENOBUFS; |
|---|
| 1177 | + |
|---|
| 1178 | + genl_dump_check_consistent(cb, hdr); |
|---|
| 1195 | 1179 | |
|---|
| 1196 | 1180 | if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) || |
|---|
| 1197 | 1181 | nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) || |
|---|
| .. | .. |
|---|
| 1215 | 1199 | * batadv_tt_local_dump_bucket() - Dump one TT local bucket into a message |
|---|
| 1216 | 1200 | * @msg: Netlink message to dump into |
|---|
| 1217 | 1201 | * @portid: Port making netlink request |
|---|
| 1218 | | - * @seq: Sequence number of netlink message |
|---|
| 1202 | + * @cb: Control block containing additional options |
|---|
| 1219 | 1203 | * @bat_priv: The bat priv with all the soft interface information |
|---|
| 1220 | | - * @head: Pointer to the list containing the local tt entries |
|---|
| 1204 | + * @hash: hash to dump |
|---|
| 1205 | + * @bucket: bucket index to dump |
|---|
| 1221 | 1206 | * @idx_s: Number of entries to skip |
|---|
| 1222 | 1207 | * |
|---|
| 1223 | 1208 | * Return: Error code, or 0 on success |
|---|
| 1224 | 1209 | */ |
|---|
| 1225 | 1210 | static int |
|---|
| 1226 | | -batadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, |
|---|
| 1211 | +batadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid, |
|---|
| 1212 | + struct netlink_callback *cb, |
|---|
| 1227 | 1213 | struct batadv_priv *bat_priv, |
|---|
| 1228 | | - struct hlist_head *head, int *idx_s) |
|---|
| 1214 | + struct batadv_hashtable *hash, unsigned int bucket, |
|---|
| 1215 | + int *idx_s) |
|---|
| 1229 | 1216 | { |
|---|
| 1230 | 1217 | struct batadv_tt_common_entry *common; |
|---|
| 1231 | 1218 | int idx = 0; |
|---|
| 1232 | 1219 | |
|---|
| 1233 | | - rcu_read_lock(); |
|---|
| 1234 | | - hlist_for_each_entry_rcu(common, head, hash_entry) { |
|---|
| 1220 | + spin_lock_bh(&hash->list_locks[bucket]); |
|---|
| 1221 | + cb->seq = atomic_read(&hash->generation) << 1 | 1; |
|---|
| 1222 | + |
|---|
| 1223 | + hlist_for_each_entry(common, &hash->table[bucket], hash_entry) { |
|---|
| 1235 | 1224 | if (idx++ < *idx_s) |
|---|
| 1236 | 1225 | continue; |
|---|
| 1237 | 1226 | |
|---|
| 1238 | | - if (batadv_tt_local_dump_entry(msg, portid, seq, bat_priv, |
|---|
| 1227 | + if (batadv_tt_local_dump_entry(msg, portid, cb, bat_priv, |
|---|
| 1239 | 1228 | common)) { |
|---|
| 1240 | | - rcu_read_unlock(); |
|---|
| 1229 | + spin_unlock_bh(&hash->list_locks[bucket]); |
|---|
| 1241 | 1230 | *idx_s = idx - 1; |
|---|
| 1242 | 1231 | return -EMSGSIZE; |
|---|
| 1243 | 1232 | } |
|---|
| 1244 | 1233 | } |
|---|
| 1245 | | - rcu_read_unlock(); |
|---|
| 1234 | + spin_unlock_bh(&hash->list_locks[bucket]); |
|---|
| 1246 | 1235 | |
|---|
| 1247 | 1236 | *idx_s = 0; |
|---|
| 1248 | 1237 | return 0; |
|---|
| .. | .. |
|---|
| 1262 | 1251 | struct batadv_priv *bat_priv; |
|---|
| 1263 | 1252 | struct batadv_hard_iface *primary_if = NULL; |
|---|
| 1264 | 1253 | struct batadv_hashtable *hash; |
|---|
| 1265 | | - struct hlist_head *head; |
|---|
| 1266 | 1254 | int ret; |
|---|
| 1267 | 1255 | int ifindex; |
|---|
| 1268 | 1256 | int bucket = cb->args[0]; |
|---|
| .. | .. |
|---|
| 1290 | 1278 | hash = bat_priv->tt.local_hash; |
|---|
| 1291 | 1279 | |
|---|
| 1292 | 1280 | while (bucket < hash->size) { |
|---|
| 1293 | | - head = &hash->table[bucket]; |
|---|
| 1294 | | - |
|---|
| 1295 | | - if (batadv_tt_local_dump_bucket(msg, portid, cb->nlh->nlmsg_seq, |
|---|
| 1296 | | - bat_priv, head, &idx)) |
|---|
| 1281 | + if (batadv_tt_local_dump_bucket(msg, portid, cb, bat_priv, |
|---|
| 1282 | + hash, bucket, &idx)) |
|---|
| 1297 | 1283 | break; |
|---|
| 1298 | 1284 | |
|---|
| 1299 | 1285 | bucket++; |
|---|
| .. | .. |
|---|
| 1684 | 1670 | * the function argument. |
|---|
| 1685 | 1671 | * If a TT local entry exists for this non-mesh client remove it. |
|---|
| 1686 | 1672 | * |
|---|
| 1687 | | - * The caller must hold orig_node refcount. |
|---|
| 1673 | + * The caller must hold the orig_node refcount. |
|---|
| 1688 | 1674 | * |
|---|
| 1689 | 1675 | * Return: true if the new entry has been added, false otherwise |
|---|
| 1690 | 1676 | */ |
|---|
| .. | .. |
|---|
| 1849 | 1835 | * @bat_priv: the bat priv with all the soft interface information |
|---|
| 1850 | 1836 | * @tt_global_entry: global translation table entry to be analyzed |
|---|
| 1851 | 1837 | * |
|---|
| 1852 | | - * This functon assumes the caller holds rcu_read_lock(). |
|---|
| 1838 | + * This function assumes the caller holds rcu_read_lock(). |
|---|
| 1853 | 1839 | * Return: best originator list entry or NULL on errors. |
|---|
| 1854 | 1840 | */ |
|---|
| 1855 | 1841 | static struct batadv_tt_orig_list_entry * |
|---|
| .. | .. |
|---|
| 1897 | 1883 | * @tt_global_entry: global translation table entry to be printed |
|---|
| 1898 | 1884 | * @seq: debugfs table seq_file struct |
|---|
| 1899 | 1885 | * |
|---|
| 1900 | | - * This functon assumes the caller holds rcu_read_lock(). |
|---|
| 1886 | + * This function assumes the caller holds rcu_read_lock(). |
|---|
| 1901 | 1887 | */ |
|---|
| 1902 | 1888 | static void |
|---|
| 1903 | 1889 | batadv_tt_global_print_entry(struct batadv_priv *bat_priv, |
|---|
| .. | .. |
|---|
| 2826 | 2812 | */ |
|---|
| 2827 | 2813 | static void batadv_tt_req_node_put(struct batadv_tt_req_node *tt_req_node) |
|---|
| 2828 | 2814 | { |
|---|
| 2815 | + if (!tt_req_node) |
|---|
| 2816 | + return; |
|---|
| 2817 | + |
|---|
| 2829 | 2818 | kref_put(&tt_req_node->refcount, batadv_tt_req_node_release); |
|---|
| 2830 | 2819 | } |
|---|
| 2831 | 2820 | |
|---|