.. | .. |
---|
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 |
---|
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 "hard-interface.h" |
---|
.. | .. |
---|
28 | 16 | #include <linux/if_ether.h> |
---|
29 | 17 | #include <linux/kernel.h> |
---|
30 | 18 | #include <linux/kref.h> |
---|
| 19 | +#include <linux/limits.h> |
---|
31 | 20 | #include <linux/list.h> |
---|
32 | 21 | #include <linux/mutex.h> |
---|
33 | 22 | #include <linux/netdevice.h> |
---|
.. | .. |
---|
149 | 138 | * @net_dev: the device to check |
---|
150 | 139 | * |
---|
151 | 140 | * If the user creates any virtual device on top of a batman-adv interface, it |
---|
152 | | - * is important to prevent this new interface to be used to create a new mesh |
---|
153 | | - * network (this behaviour would lead to a batman-over-batman configuration). |
---|
154 | | - * This function recursively checks all the fathers of the device passed as |
---|
155 | | - * argument looking for a batman-adv soft interface. |
---|
| 141 | + * is important to prevent this new interface from being used to create a new |
---|
| 142 | + * mesh network (this behaviour would lead to a batman-over-batman |
---|
| 143 | + * configuration). This function recursively checks all the fathers of the |
---|
| 144 | + * device passed as argument looking for a batman-adv soft interface. |
---|
156 | 145 | * |
---|
157 | 146 | * Return: true if the device is descendant of a batman-adv mesh interface (or |
---|
158 | 147 | * if it is a batman-adv interface itself), false otherwise |
---|
.. | .. |
---|
162 | 151 | struct net *net = dev_net(net_dev); |
---|
163 | 152 | struct net_device *parent_dev; |
---|
164 | 153 | struct net *parent_net; |
---|
| 154 | + int iflink; |
---|
165 | 155 | bool ret; |
---|
166 | 156 | |
---|
167 | 157 | /* check if this is a batman-adv mesh interface */ |
---|
168 | 158 | if (batadv_softif_is_valid(net_dev)) |
---|
169 | 159 | return true; |
---|
170 | 160 | |
---|
171 | | - /* no more parents..stop recursion */ |
---|
172 | | - if (dev_get_iflink(net_dev) == 0 || |
---|
173 | | - dev_get_iflink(net_dev) == net_dev->ifindex) |
---|
| 161 | + iflink = dev_get_iflink(net_dev); |
---|
| 162 | + if (iflink == 0) |
---|
174 | 163 | return false; |
---|
175 | 164 | |
---|
176 | 165 | parent_net = batadv_getlink_net(net_dev, net); |
---|
177 | 166 | |
---|
| 167 | + /* iflink to itself, most likely physical device */ |
---|
| 168 | + if (net == parent_net && iflink == net_dev->ifindex) |
---|
| 169 | + return false; |
---|
| 170 | + |
---|
178 | 171 | /* recurse over the parent device */ |
---|
179 | | - parent_dev = __dev_get_by_index((struct net *)parent_net, |
---|
180 | | - dev_get_iflink(net_dev)); |
---|
| 172 | + parent_dev = __dev_get_by_index((struct net *)parent_net, iflink); |
---|
181 | 173 | /* if we got a NULL parent_dev there is something broken.. */ |
---|
182 | 174 | if (!parent_dev) { |
---|
183 | 175 | pr_err("Cannot find parent device\n"); |
---|
.. | .. |
---|
227 | 219 | struct net_device *real_netdev = NULL; |
---|
228 | 220 | struct net *real_net; |
---|
229 | 221 | struct net *net; |
---|
230 | | - int ifindex; |
---|
| 222 | + int iflink; |
---|
231 | 223 | |
---|
232 | 224 | ASSERT_RTNL(); |
---|
233 | 225 | |
---|
234 | 226 | if (!netdev) |
---|
235 | 227 | return NULL; |
---|
236 | 228 | |
---|
237 | | - if (netdev->ifindex == dev_get_iflink(netdev)) { |
---|
| 229 | + iflink = dev_get_iflink(netdev); |
---|
| 230 | + if (iflink == 0) { |
---|
238 | 231 | dev_hold(netdev); |
---|
239 | 232 | return netdev; |
---|
240 | 233 | } |
---|
.. | .. |
---|
244 | 237 | goto out; |
---|
245 | 238 | |
---|
246 | 239 | net = dev_net(hard_iface->soft_iface); |
---|
247 | | - ifindex = dev_get_iflink(netdev); |
---|
248 | 240 | real_net = batadv_getlink_net(netdev, net); |
---|
249 | | - real_netdev = dev_get_by_index(real_net, ifindex); |
---|
| 241 | + |
---|
| 242 | + /* iflink to itself, most likely physical device */ |
---|
| 243 | + if (net == real_net && netdev->ifindex == iflink) { |
---|
| 244 | + real_netdev = netdev; |
---|
| 245 | + dev_hold(real_netdev); |
---|
| 246 | + goto out; |
---|
| 247 | + } |
---|
| 248 | + |
---|
| 249 | + real_netdev = dev_get_by_index(real_net, iflink); |
---|
250 | 250 | |
---|
251 | 251 | out: |
---|
252 | 252 | if (hard_iface) |
---|
.. | .. |
---|
484 | 484 | if (new_hard_iface) |
---|
485 | 485 | kref_get(&new_hard_iface->refcount); |
---|
486 | 486 | |
---|
487 | | - curr_hard_iface = rcu_dereference_protected(bat_priv->primary_if, 1); |
---|
488 | | - rcu_assign_pointer(bat_priv->primary_if, new_hard_iface); |
---|
| 487 | + curr_hard_iface = rcu_replace_pointer(bat_priv->primary_if, |
---|
| 488 | + new_hard_iface, 1); |
---|
489 | 489 | |
---|
490 | 490 | if (!new_hard_iface) |
---|
491 | 491 | goto out; |
---|
.. | .. |
---|
613 | 613 | /* report to the other components the maximum amount of bytes that |
---|
614 | 614 | * batman-adv can send over the wire (without considering the payload |
---|
615 | 615 | * overhead). For example, this value is used by TT to compute the |
---|
616 | | - * maximum local table table size |
---|
| 616 | + * maximum local table size |
---|
617 | 617 | */ |
---|
618 | 618 | atomic_set(&bat_priv->packet_size_max, min_mtu); |
---|
619 | 619 | |
---|
.. | .. |
---|
632 | 632 | */ |
---|
633 | 633 | void batadv_update_min_mtu(struct net_device *soft_iface) |
---|
634 | 634 | { |
---|
635 | | - soft_iface->mtu = batadv_hardif_min_mtu(soft_iface); |
---|
| 635 | + struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
---|
| 636 | + int limit_mtu; |
---|
| 637 | + int mtu; |
---|
| 638 | + |
---|
| 639 | + mtu = batadv_hardif_min_mtu(soft_iface); |
---|
| 640 | + |
---|
| 641 | + if (bat_priv->mtu_set_by_user) |
---|
| 642 | + limit_mtu = bat_priv->mtu_set_by_user; |
---|
| 643 | + else |
---|
| 644 | + limit_mtu = ETH_DATA_LEN; |
---|
| 645 | + |
---|
| 646 | + mtu = min(mtu, limit_mtu); |
---|
| 647 | + dev_set_mtu(soft_iface, mtu); |
---|
636 | 648 | |
---|
637 | 649 | /* Check if the local translate table should be cleaned up to match a |
---|
638 | 650 | * new (and smaller) MTU. |
---|
.. | .. |
---|
694 | 706 | * @slave: the interface enslaved in another master |
---|
695 | 707 | * @master: the master from which slave has to be removed |
---|
696 | 708 | * |
---|
697 | | - * Invoke ndo_del_slave on master passing slave as argument. In this way slave |
---|
698 | | - * is free'd and master can correctly change its internal state. |
---|
| 709 | + * Invoke ndo_del_slave on master passing slave as argument. In this way the |
---|
| 710 | + * slave is free'd and the master can correctly change its internal state. |
---|
699 | 711 | * |
---|
700 | 712 | * Return: 0 on success, a negative value representing the error otherwise |
---|
701 | 713 | */ |
---|
.. | .. |
---|
768 | 780 | hard_iface->soft_iface = soft_iface; |
---|
769 | 781 | bat_priv = netdev_priv(hard_iface->soft_iface); |
---|
770 | 782 | |
---|
771 | | - if (bat_priv->num_ifaces >= UINT_MAX) { |
---|
772 | | - ret = -ENOSPC; |
---|
773 | | - goto err_dev; |
---|
774 | | - } |
---|
775 | | - |
---|
776 | 783 | ret = netdev_master_upper_dev_link(hard_iface->net_dev, |
---|
777 | 784 | soft_iface, NULL, NULL, NULL); |
---|
778 | 785 | if (ret) |
---|
.. | .. |
---|
782 | 789 | if (ret < 0) |
---|
783 | 790 | goto err_upper; |
---|
784 | 791 | |
---|
785 | | - hard_iface->if_num = bat_priv->num_ifaces; |
---|
786 | | - bat_priv->num_ifaces++; |
---|
787 | 792 | hard_iface->if_status = BATADV_IF_INACTIVE; |
---|
788 | | - ret = batadv_orig_hash_add_if(hard_iface, bat_priv->num_ifaces); |
---|
789 | | - if (ret < 0) { |
---|
790 | | - bat_priv->algo_ops->iface.disable(hard_iface); |
---|
791 | | - bat_priv->num_ifaces--; |
---|
792 | | - hard_iface->if_status = BATADV_IF_NOT_IN_USE; |
---|
793 | | - goto err_upper; |
---|
794 | | - } |
---|
795 | 793 | |
---|
796 | 794 | kref_get(&hard_iface->refcount); |
---|
797 | 795 | hard_iface->batman_adv_ptype.type = ethertype; |
---|
.. | .. |
---|
842 | 840 | } |
---|
843 | 841 | |
---|
844 | 842 | /** |
---|
| 843 | + * batadv_hardif_cnt() - get number of interfaces enslaved to soft interface |
---|
| 844 | + * @soft_iface: soft interface to check |
---|
| 845 | + * |
---|
| 846 | + * This function is only using RCU for locking - the result can therefore be |
---|
| 847 | + * off when another function is modifying the list at the same time. The |
---|
| 848 | + * caller can use the rtnl_lock to make sure that the count is accurate. |
---|
| 849 | + * |
---|
| 850 | + * Return: number of connected/enslaved hard interfaces |
---|
| 851 | + */ |
---|
| 852 | +static size_t batadv_hardif_cnt(const struct net_device *soft_iface) |
---|
| 853 | +{ |
---|
| 854 | + struct batadv_hard_iface *hard_iface; |
---|
| 855 | + size_t count = 0; |
---|
| 856 | + |
---|
| 857 | + rcu_read_lock(); |
---|
| 858 | + list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { |
---|
| 859 | + if (hard_iface->soft_iface != soft_iface) |
---|
| 860 | + continue; |
---|
| 861 | + |
---|
| 862 | + count++; |
---|
| 863 | + } |
---|
| 864 | + rcu_read_unlock(); |
---|
| 865 | + |
---|
| 866 | + return count; |
---|
| 867 | +} |
---|
| 868 | + |
---|
| 869 | +/** |
---|
845 | 870 | * batadv_hardif_disable_interface() - Remove hard interface from soft interface |
---|
846 | 871 | * @hard_iface: hard interface to be removed |
---|
847 | 872 | * @autodel: whether to delete soft interface when it doesn't contain any other |
---|
.. | .. |
---|
862 | 887 | hard_iface->net_dev->name); |
---|
863 | 888 | dev_remove_pack(&hard_iface->batman_adv_ptype); |
---|
864 | 889 | batadv_hardif_put(hard_iface); |
---|
865 | | - |
---|
866 | | - bat_priv->num_ifaces--; |
---|
867 | | - batadv_orig_hash_del_if(hard_iface, bat_priv->num_ifaces); |
---|
868 | 890 | |
---|
869 | 891 | primary_if = batadv_primary_if_get_selected(bat_priv); |
---|
870 | 892 | if (hard_iface == primary_if) { |
---|
.. | .. |
---|
889 | 911 | batadv_hardif_recalc_extra_skbroom(hard_iface->soft_iface); |
---|
890 | 912 | |
---|
891 | 913 | /* nobody uses this interface anymore */ |
---|
892 | | - if (bat_priv->num_ifaces == 0) { |
---|
| 914 | + if (batadv_hardif_cnt(hard_iface->soft_iface) <= 1) { |
---|
893 | 915 | batadv_gw_check_client_stop(bat_priv); |
---|
894 | 916 | |
---|
895 | 917 | if (autodel == BATADV_IF_CLEANUP_AUTO) |
---|
.. | .. |
---|
925 | 947 | if (ret) |
---|
926 | 948 | goto free_if; |
---|
927 | 949 | |
---|
928 | | - hard_iface->if_num = 0; |
---|
929 | 950 | hard_iface->net_dev = net_dev; |
---|
930 | 951 | hard_iface->soft_iface = NULL; |
---|
931 | 952 | hard_iface->if_status = BATADV_IF_NOT_IN_USE; |
---|
932 | 953 | |
---|
933 | | - ret = batadv_debugfs_add_hardif(hard_iface); |
---|
934 | | - if (ret) |
---|
935 | | - goto free_sysfs; |
---|
| 954 | + batadv_debugfs_add_hardif(hard_iface); |
---|
936 | 955 | |
---|
937 | 956 | INIT_LIST_HEAD(&hard_iface->list); |
---|
938 | 957 | INIT_HLIST_HEAD(&hard_iface->neigh_list); |
---|
.. | .. |
---|
946 | 965 | if (batadv_is_wifi_hardif(hard_iface)) |
---|
947 | 966 | hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS; |
---|
948 | 967 | |
---|
| 968 | + atomic_set(&hard_iface->hop_penalty, 0); |
---|
| 969 | + |
---|
949 | 970 | batadv_v_hardif_init(hard_iface); |
---|
950 | 971 | |
---|
951 | 972 | batadv_check_known_mac_addr(hard_iface->net_dev); |
---|
952 | 973 | kref_get(&hard_iface->refcount); |
---|
953 | 974 | list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list); |
---|
| 975 | + batadv_hardif_generation++; |
---|
954 | 976 | |
---|
955 | 977 | return hard_iface; |
---|
956 | 978 | |
---|
957 | | -free_sysfs: |
---|
958 | | - batadv_sysfs_del_hardif(&hard_iface->hardif_obj); |
---|
959 | 979 | free_if: |
---|
960 | 980 | kfree(hard_iface); |
---|
961 | 981 | release_dev: |
---|
.. | .. |
---|
980 | 1000 | batadv_debugfs_del_hardif(hard_iface); |
---|
981 | 1001 | batadv_sysfs_del_hardif(&hard_iface->hardif_obj); |
---|
982 | 1002 | batadv_hardif_put(hard_iface); |
---|
983 | | -} |
---|
984 | | - |
---|
985 | | -/** |
---|
986 | | - * batadv_hardif_remove_interfaces() - Remove all hard interfaces |
---|
987 | | - */ |
---|
988 | | -void batadv_hardif_remove_interfaces(void) |
---|
989 | | -{ |
---|
990 | | - struct batadv_hard_iface *hard_iface, *hard_iface_tmp; |
---|
991 | | - |
---|
992 | | - rtnl_lock(); |
---|
993 | | - list_for_each_entry_safe(hard_iface, hard_iface_tmp, |
---|
994 | | - &batadv_hardif_list, list) { |
---|
995 | | - list_del_rcu(&hard_iface->list); |
---|
996 | | - batadv_hardif_remove_interface(hard_iface); |
---|
997 | | - } |
---|
998 | | - rtnl_unlock(); |
---|
999 | 1003 | } |
---|
1000 | 1004 | |
---|
1001 | 1005 | /** |
---|
.. | .. |
---|
1054 | 1058 | case NETDEV_UNREGISTER: |
---|
1055 | 1059 | case NETDEV_PRE_TYPE_CHANGE: |
---|
1056 | 1060 | list_del_rcu(&hard_iface->list); |
---|
| 1061 | + batadv_hardif_generation++; |
---|
1057 | 1062 | |
---|
1058 | 1063 | batadv_hardif_remove_interface(hard_iface); |
---|
1059 | 1064 | break; |
---|