18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (C) 2007-2020 B.A.T.M.A.N. contributors: 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Marek Lindner, Simon Wunderlich 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "hard-interface.h" 88c2ecf20Sopenharmony_ci#include "main.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/atomic.h> 118c2ecf20Sopenharmony_ci#include <linux/byteorder/generic.h> 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/gfp.h> 148c2ecf20Sopenharmony_ci#include <linux/if.h> 158c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 168c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/kref.h> 198c2ecf20Sopenharmony_ci#include <linux/limits.h> 208c2ecf20Sopenharmony_ci#include <linux/list.h> 218c2ecf20Sopenharmony_ci#include <linux/mutex.h> 228c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 238c2ecf20Sopenharmony_ci#include <linux/printk.h> 248c2ecf20Sopenharmony_ci#include <linux/rculist.h> 258c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 268c2ecf20Sopenharmony_ci#include <linux/slab.h> 278c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 288c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 298c2ecf20Sopenharmony_ci#include <net/rtnetlink.h> 308c2ecf20Sopenharmony_ci#include <uapi/linux/batadv_packet.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "bat_v.h" 338c2ecf20Sopenharmony_ci#include "bridge_loop_avoidance.h" 348c2ecf20Sopenharmony_ci#include "debugfs.h" 358c2ecf20Sopenharmony_ci#include "distributed-arp-table.h" 368c2ecf20Sopenharmony_ci#include "gateway_client.h" 378c2ecf20Sopenharmony_ci#include "log.h" 388c2ecf20Sopenharmony_ci#include "originator.h" 398c2ecf20Sopenharmony_ci#include "send.h" 408c2ecf20Sopenharmony_ci#include "soft-interface.h" 418c2ecf20Sopenharmony_ci#include "sysfs.h" 428c2ecf20Sopenharmony_ci#include "translation-table.h" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/** 458c2ecf20Sopenharmony_ci * batadv_hardif_release() - release hard interface from lists and queue for 468c2ecf20Sopenharmony_ci * free after rcu grace period 478c2ecf20Sopenharmony_ci * @ref: kref pointer of the hard interface 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_civoid batadv_hardif_release(struct kref *ref) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci hard_iface = container_of(ref, struct batadv_hard_iface, refcount); 548c2ecf20Sopenharmony_ci dev_put(hard_iface->net_dev); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci kfree_rcu(hard_iface, rcu); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/** 608c2ecf20Sopenharmony_ci * batadv_hardif_get_by_netdev() - Get hard interface object of a net_device 618c2ecf20Sopenharmony_ci * @net_dev: net_device to search for 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * Return: batadv_hard_iface of net_dev (with increased refcnt), NULL on errors 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_cistruct batadv_hard_iface * 668c2ecf20Sopenharmony_cibatadv_hardif_get_by_netdev(const struct net_device *net_dev) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci rcu_read_lock(); 718c2ecf20Sopenharmony_ci list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { 728c2ecf20Sopenharmony_ci if (hard_iface->net_dev == net_dev && 738c2ecf20Sopenharmony_ci kref_get_unless_zero(&hard_iface->refcount)) 748c2ecf20Sopenharmony_ci goto out; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci hard_iface = NULL; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciout: 808c2ecf20Sopenharmony_ci rcu_read_unlock(); 818c2ecf20Sopenharmony_ci return hard_iface; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/** 858c2ecf20Sopenharmony_ci * batadv_getlink_net() - return link net namespace (of use fallback) 868c2ecf20Sopenharmony_ci * @netdev: net_device to check 878c2ecf20Sopenharmony_ci * @fallback_net: return in case get_link_net is not available for @netdev 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * Return: result of rtnl_link_ops->get_link_net or @fallback_net 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_cistatic struct net *batadv_getlink_net(const struct net_device *netdev, 928c2ecf20Sopenharmony_ci struct net *fallback_net) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci if (!netdev->rtnl_link_ops) 958c2ecf20Sopenharmony_ci return fallback_net; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (!netdev->rtnl_link_ops->get_link_net) 988c2ecf20Sopenharmony_ci return fallback_net; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return netdev->rtnl_link_ops->get_link_net(netdev); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/** 1048c2ecf20Sopenharmony_ci * batadv_mutual_parents() - check if two devices are each others parent 1058c2ecf20Sopenharmony_ci * @dev1: 1st net dev 1068c2ecf20Sopenharmony_ci * @net1: 1st devices netns 1078c2ecf20Sopenharmony_ci * @dev2: 2nd net dev 1088c2ecf20Sopenharmony_ci * @net2: 2nd devices netns 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * veth devices come in pairs and each is the parent of the other! 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * Return: true if the devices are each others parent, otherwise false 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_cistatic bool batadv_mutual_parents(const struct net_device *dev1, 1158c2ecf20Sopenharmony_ci struct net *net1, 1168c2ecf20Sopenharmony_ci const struct net_device *dev2, 1178c2ecf20Sopenharmony_ci struct net *net2) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci int dev1_parent_iflink = dev_get_iflink(dev1); 1208c2ecf20Sopenharmony_ci int dev2_parent_iflink = dev_get_iflink(dev2); 1218c2ecf20Sopenharmony_ci const struct net *dev1_parent_net; 1228c2ecf20Sopenharmony_ci const struct net *dev2_parent_net; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci dev1_parent_net = batadv_getlink_net(dev1, net1); 1258c2ecf20Sopenharmony_ci dev2_parent_net = batadv_getlink_net(dev2, net2); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (!dev1_parent_iflink || !dev2_parent_iflink) 1288c2ecf20Sopenharmony_ci return false; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return (dev1_parent_iflink == dev2->ifindex) && 1318c2ecf20Sopenharmony_ci (dev2_parent_iflink == dev1->ifindex) && 1328c2ecf20Sopenharmony_ci net_eq(dev1_parent_net, net2) && 1338c2ecf20Sopenharmony_ci net_eq(dev2_parent_net, net1); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/** 1378c2ecf20Sopenharmony_ci * batadv_is_on_batman_iface() - check if a device is a batman iface descendant 1388c2ecf20Sopenharmony_ci * @net_dev: the device to check 1398c2ecf20Sopenharmony_ci * 1408c2ecf20Sopenharmony_ci * If the user creates any virtual device on top of a batman-adv interface, it 1418c2ecf20Sopenharmony_ci * is important to prevent this new interface from being used to create a new 1428c2ecf20Sopenharmony_ci * mesh network (this behaviour would lead to a batman-over-batman 1438c2ecf20Sopenharmony_ci * configuration). This function recursively checks all the fathers of the 1448c2ecf20Sopenharmony_ci * device passed as argument looking for a batman-adv soft interface. 1458c2ecf20Sopenharmony_ci * 1468c2ecf20Sopenharmony_ci * Return: true if the device is descendant of a batman-adv mesh interface (or 1478c2ecf20Sopenharmony_ci * if it is a batman-adv interface itself), false otherwise 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_cistatic bool batadv_is_on_batman_iface(const struct net_device *net_dev) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct net *net = dev_net(net_dev); 1528c2ecf20Sopenharmony_ci struct net_device *parent_dev; 1538c2ecf20Sopenharmony_ci struct net *parent_net; 1548c2ecf20Sopenharmony_ci int iflink; 1558c2ecf20Sopenharmony_ci bool ret; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* check if this is a batman-adv mesh interface */ 1588c2ecf20Sopenharmony_ci if (batadv_softif_is_valid(net_dev)) 1598c2ecf20Sopenharmony_ci return true; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci iflink = dev_get_iflink(net_dev); 1628c2ecf20Sopenharmony_ci if (iflink == 0) 1638c2ecf20Sopenharmony_ci return false; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci parent_net = batadv_getlink_net(net_dev, net); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* iflink to itself, most likely physical device */ 1688c2ecf20Sopenharmony_ci if (net == parent_net && iflink == net_dev->ifindex) 1698c2ecf20Sopenharmony_ci return false; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* recurse over the parent device */ 1728c2ecf20Sopenharmony_ci parent_dev = __dev_get_by_index((struct net *)parent_net, iflink); 1738c2ecf20Sopenharmony_ci /* if we got a NULL parent_dev there is something broken.. */ 1748c2ecf20Sopenharmony_ci if (!parent_dev) { 1758c2ecf20Sopenharmony_ci pr_err("Cannot find parent device\n"); 1768c2ecf20Sopenharmony_ci return false; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (batadv_mutual_parents(net_dev, net, parent_dev, parent_net)) 1808c2ecf20Sopenharmony_ci return false; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci ret = batadv_is_on_batman_iface(parent_dev); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return ret; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic bool batadv_is_valid_iface(const struct net_device *net_dev) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci if (net_dev->flags & IFF_LOOPBACK) 1908c2ecf20Sopenharmony_ci return false; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (net_dev->type != ARPHRD_ETHER) 1938c2ecf20Sopenharmony_ci return false; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (net_dev->addr_len != ETH_ALEN) 1968c2ecf20Sopenharmony_ci return false; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* no batman over batman */ 1998c2ecf20Sopenharmony_ci if (batadv_is_on_batman_iface(net_dev)) 2008c2ecf20Sopenharmony_ci return false; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return true; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/** 2068c2ecf20Sopenharmony_ci * batadv_get_real_netdevice() - check if the given netdev struct is a virtual 2078c2ecf20Sopenharmony_ci * interface on top of another 'real' interface 2088c2ecf20Sopenharmony_ci * @netdev: the device to check 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * Callers must hold the rtnl semaphore. You may want batadv_get_real_netdev() 2118c2ecf20Sopenharmony_ci * instead of this. 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * Return: the 'real' net device or the original net device and NULL in case 2148c2ecf20Sopenharmony_ci * of an error. 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_cistatic struct net_device *batadv_get_real_netdevice(struct net_device *netdev) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface = NULL; 2198c2ecf20Sopenharmony_ci struct net_device *real_netdev = NULL; 2208c2ecf20Sopenharmony_ci struct net *real_net; 2218c2ecf20Sopenharmony_ci struct net *net; 2228c2ecf20Sopenharmony_ci int iflink; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci ASSERT_RTNL(); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (!netdev) 2278c2ecf20Sopenharmony_ci return NULL; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci iflink = dev_get_iflink(netdev); 2308c2ecf20Sopenharmony_ci if (iflink == 0) { 2318c2ecf20Sopenharmony_ci dev_hold(netdev); 2328c2ecf20Sopenharmony_ci return netdev; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci hard_iface = batadv_hardif_get_by_netdev(netdev); 2368c2ecf20Sopenharmony_ci if (!hard_iface || !hard_iface->soft_iface) 2378c2ecf20Sopenharmony_ci goto out; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci net = dev_net(hard_iface->soft_iface); 2408c2ecf20Sopenharmony_ci real_net = batadv_getlink_net(netdev, net); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* iflink to itself, most likely physical device */ 2438c2ecf20Sopenharmony_ci if (net == real_net && netdev->ifindex == iflink) { 2448c2ecf20Sopenharmony_ci real_netdev = netdev; 2458c2ecf20Sopenharmony_ci dev_hold(real_netdev); 2468c2ecf20Sopenharmony_ci goto out; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci real_netdev = dev_get_by_index(real_net, iflink); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciout: 2528c2ecf20Sopenharmony_ci if (hard_iface) 2538c2ecf20Sopenharmony_ci batadv_hardif_put(hard_iface); 2548c2ecf20Sopenharmony_ci return real_netdev; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/** 2588c2ecf20Sopenharmony_ci * batadv_get_real_netdev() - check if the given net_device struct is a virtual 2598c2ecf20Sopenharmony_ci * interface on top of another 'real' interface 2608c2ecf20Sopenharmony_ci * @net_device: the device to check 2618c2ecf20Sopenharmony_ci * 2628c2ecf20Sopenharmony_ci * Return: the 'real' net device or the original net device and NULL in case 2638c2ecf20Sopenharmony_ci * of an error. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_cistruct net_device *batadv_get_real_netdev(struct net_device *net_device) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct net_device *real_netdev; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci rtnl_lock(); 2708c2ecf20Sopenharmony_ci real_netdev = batadv_get_real_netdevice(net_device); 2718c2ecf20Sopenharmony_ci rtnl_unlock(); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return real_netdev; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/** 2778c2ecf20Sopenharmony_ci * batadv_is_wext_netdev() - check if the given net_device struct is a 2788c2ecf20Sopenharmony_ci * wext wifi interface 2798c2ecf20Sopenharmony_ci * @net_device: the device to check 2808c2ecf20Sopenharmony_ci * 2818c2ecf20Sopenharmony_ci * Return: true if the net device is a wext wireless device, false 2828c2ecf20Sopenharmony_ci * otherwise. 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_cistatic bool batadv_is_wext_netdev(struct net_device *net_device) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci if (!net_device) 2878c2ecf20Sopenharmony_ci return false; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci#ifdef CONFIG_WIRELESS_EXT 2908c2ecf20Sopenharmony_ci /* pre-cfg80211 drivers have to implement WEXT, so it is possible to 2918c2ecf20Sopenharmony_ci * check for wireless_handlers != NULL 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci if (net_device->wireless_handlers) 2948c2ecf20Sopenharmony_ci return true; 2958c2ecf20Sopenharmony_ci#endif 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return false; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci/** 3018c2ecf20Sopenharmony_ci * batadv_is_cfg80211_netdev() - check if the given net_device struct is a 3028c2ecf20Sopenharmony_ci * cfg80211 wifi interface 3038c2ecf20Sopenharmony_ci * @net_device: the device to check 3048c2ecf20Sopenharmony_ci * 3058c2ecf20Sopenharmony_ci * Return: true if the net device is a cfg80211 wireless device, false 3068c2ecf20Sopenharmony_ci * otherwise. 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_cistatic bool batadv_is_cfg80211_netdev(struct net_device *net_device) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci if (!net_device) 3118c2ecf20Sopenharmony_ci return false; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* cfg80211 drivers have to set ieee80211_ptr */ 3148c2ecf20Sopenharmony_ci if (net_device->ieee80211_ptr) 3158c2ecf20Sopenharmony_ci return true; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return false; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/** 3218c2ecf20Sopenharmony_ci * batadv_wifi_flags_evaluate() - calculate wifi flags for net_device 3228c2ecf20Sopenharmony_ci * @net_device: the device to check 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * Return: batadv_hard_iface_wifi_flags flags of the device 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_cistatic u32 batadv_wifi_flags_evaluate(struct net_device *net_device) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci u32 wifi_flags = 0; 3298c2ecf20Sopenharmony_ci struct net_device *real_netdev; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (batadv_is_wext_netdev(net_device)) 3328c2ecf20Sopenharmony_ci wifi_flags |= BATADV_HARDIF_WIFI_WEXT_DIRECT; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (batadv_is_cfg80211_netdev(net_device)) 3358c2ecf20Sopenharmony_ci wifi_flags |= BATADV_HARDIF_WIFI_CFG80211_DIRECT; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci real_netdev = batadv_get_real_netdevice(net_device); 3388c2ecf20Sopenharmony_ci if (!real_netdev) 3398c2ecf20Sopenharmony_ci return wifi_flags; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (real_netdev == net_device) 3428c2ecf20Sopenharmony_ci goto out; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (batadv_is_wext_netdev(real_netdev)) 3458c2ecf20Sopenharmony_ci wifi_flags |= BATADV_HARDIF_WIFI_WEXT_INDIRECT; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (batadv_is_cfg80211_netdev(real_netdev)) 3488c2ecf20Sopenharmony_ci wifi_flags |= BATADV_HARDIF_WIFI_CFG80211_INDIRECT; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ciout: 3518c2ecf20Sopenharmony_ci dev_put(real_netdev); 3528c2ecf20Sopenharmony_ci return wifi_flags; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci/** 3568c2ecf20Sopenharmony_ci * batadv_is_cfg80211_hardif() - check if the given hardif is a cfg80211 wifi 3578c2ecf20Sopenharmony_ci * interface 3588c2ecf20Sopenharmony_ci * @hard_iface: the device to check 3598c2ecf20Sopenharmony_ci * 3608c2ecf20Sopenharmony_ci * Return: true if the net device is a cfg80211 wireless device, false 3618c2ecf20Sopenharmony_ci * otherwise. 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_cibool batadv_is_cfg80211_hardif(struct batadv_hard_iface *hard_iface) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci u32 allowed_flags = 0; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_DIRECT; 3688c2ecf20Sopenharmony_ci allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_INDIRECT; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return !!(hard_iface->wifi_flags & allowed_flags); 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci/** 3748c2ecf20Sopenharmony_ci * batadv_is_wifi_hardif() - check if the given hardif is a wifi interface 3758c2ecf20Sopenharmony_ci * @hard_iface: the device to check 3768c2ecf20Sopenharmony_ci * 3778c2ecf20Sopenharmony_ci * Return: true if the net device is a 802.11 wireless device, false otherwise. 3788c2ecf20Sopenharmony_ci */ 3798c2ecf20Sopenharmony_cibool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci if (!hard_iface) 3828c2ecf20Sopenharmony_ci return false; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return hard_iface->wifi_flags != 0; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci/** 3888c2ecf20Sopenharmony_ci * batadv_hardif_no_broadcast() - check whether (re)broadcast is necessary 3898c2ecf20Sopenharmony_ci * @if_outgoing: the outgoing interface checked and considered for (re)broadcast 3908c2ecf20Sopenharmony_ci * @orig_addr: the originator of this packet 3918c2ecf20Sopenharmony_ci * @orig_neigh: originator address of the forwarder we just got the packet from 3928c2ecf20Sopenharmony_ci * (NULL if we originated) 3938c2ecf20Sopenharmony_ci * 3948c2ecf20Sopenharmony_ci * Checks whether a packet needs to be (re)broadcasted on the given interface. 3958c2ecf20Sopenharmony_ci * 3968c2ecf20Sopenharmony_ci * Return: 3978c2ecf20Sopenharmony_ci * BATADV_HARDIF_BCAST_NORECIPIENT: No neighbor on interface 3988c2ecf20Sopenharmony_ci * BATADV_HARDIF_BCAST_DUPFWD: Just one neighbor, but it is the forwarder 3998c2ecf20Sopenharmony_ci * BATADV_HARDIF_BCAST_DUPORIG: Just one neighbor, but it is the originator 4008c2ecf20Sopenharmony_ci * BATADV_HARDIF_BCAST_OK: Several neighbors, must broadcast 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_ciint batadv_hardif_no_broadcast(struct batadv_hard_iface *if_outgoing, 4038c2ecf20Sopenharmony_ci u8 *orig_addr, u8 *orig_neigh) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct batadv_hardif_neigh_node *hardif_neigh; 4068c2ecf20Sopenharmony_ci struct hlist_node *first; 4078c2ecf20Sopenharmony_ci int ret = BATADV_HARDIF_BCAST_OK; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci rcu_read_lock(); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* 0 neighbors -> no (re)broadcast */ 4128c2ecf20Sopenharmony_ci first = rcu_dereference(hlist_first_rcu(&if_outgoing->neigh_list)); 4138c2ecf20Sopenharmony_ci if (!first) { 4148c2ecf20Sopenharmony_ci ret = BATADV_HARDIF_BCAST_NORECIPIENT; 4158c2ecf20Sopenharmony_ci goto out; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* >1 neighbors -> (re)brodcast */ 4198c2ecf20Sopenharmony_ci if (rcu_dereference(hlist_next_rcu(first))) 4208c2ecf20Sopenharmony_ci goto out; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci hardif_neigh = hlist_entry(first, struct batadv_hardif_neigh_node, 4238c2ecf20Sopenharmony_ci list); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* 1 neighbor, is the originator -> no rebroadcast */ 4268c2ecf20Sopenharmony_ci if (orig_addr && batadv_compare_eth(hardif_neigh->orig, orig_addr)) { 4278c2ecf20Sopenharmony_ci ret = BATADV_HARDIF_BCAST_DUPORIG; 4288c2ecf20Sopenharmony_ci /* 1 neighbor, is the one we received from -> no rebroadcast */ 4298c2ecf20Sopenharmony_ci } else if (orig_neigh && 4308c2ecf20Sopenharmony_ci batadv_compare_eth(hardif_neigh->orig, orig_neigh)) { 4318c2ecf20Sopenharmony_ci ret = BATADV_HARDIF_BCAST_DUPFWD; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ciout: 4358c2ecf20Sopenharmony_ci rcu_read_unlock(); 4368c2ecf20Sopenharmony_ci return ret; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic struct batadv_hard_iface * 4408c2ecf20Sopenharmony_cibatadv_hardif_get_active(const struct net_device *soft_iface) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci rcu_read_lock(); 4458c2ecf20Sopenharmony_ci list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { 4468c2ecf20Sopenharmony_ci if (hard_iface->soft_iface != soft_iface) 4478c2ecf20Sopenharmony_ci continue; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (hard_iface->if_status == BATADV_IF_ACTIVE && 4508c2ecf20Sopenharmony_ci kref_get_unless_zero(&hard_iface->refcount)) 4518c2ecf20Sopenharmony_ci goto out; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci hard_iface = NULL; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ciout: 4578c2ecf20Sopenharmony_ci rcu_read_unlock(); 4588c2ecf20Sopenharmony_ci return hard_iface; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic void batadv_primary_if_update_addr(struct batadv_priv *bat_priv, 4628c2ecf20Sopenharmony_ci struct batadv_hard_iface *oldif) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct batadv_hard_iface *primary_if; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci primary_if = batadv_primary_if_get_selected(bat_priv); 4678c2ecf20Sopenharmony_ci if (!primary_if) 4688c2ecf20Sopenharmony_ci goto out; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci batadv_dat_init_own_addr(bat_priv, primary_if); 4718c2ecf20Sopenharmony_ci batadv_bla_update_orig_address(bat_priv, primary_if, oldif); 4728c2ecf20Sopenharmony_ciout: 4738c2ecf20Sopenharmony_ci if (primary_if) 4748c2ecf20Sopenharmony_ci batadv_hardif_put(primary_if); 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic void batadv_primary_if_select(struct batadv_priv *bat_priv, 4788c2ecf20Sopenharmony_ci struct batadv_hard_iface *new_hard_iface) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci struct batadv_hard_iface *curr_hard_iface; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci ASSERT_RTNL(); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (new_hard_iface) 4858c2ecf20Sopenharmony_ci kref_get(&new_hard_iface->refcount); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci curr_hard_iface = rcu_replace_pointer(bat_priv->primary_if, 4888c2ecf20Sopenharmony_ci new_hard_iface, 1); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (!new_hard_iface) 4918c2ecf20Sopenharmony_ci goto out; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci bat_priv->algo_ops->iface.primary_set(new_hard_iface); 4948c2ecf20Sopenharmony_ci batadv_primary_if_update_addr(bat_priv, curr_hard_iface); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ciout: 4978c2ecf20Sopenharmony_ci if (curr_hard_iface) 4988c2ecf20Sopenharmony_ci batadv_hardif_put(curr_hard_iface); 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic bool 5028c2ecf20Sopenharmony_cibatadv_hardif_is_iface_up(const struct batadv_hard_iface *hard_iface) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci if (hard_iface->net_dev->flags & IFF_UP) 5058c2ecf20Sopenharmony_ci return true; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return false; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic void batadv_check_known_mac_addr(const struct net_device *net_dev) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci const struct batadv_hard_iface *hard_iface; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci rcu_read_lock(); 5158c2ecf20Sopenharmony_ci list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { 5168c2ecf20Sopenharmony_ci if (hard_iface->if_status != BATADV_IF_ACTIVE && 5178c2ecf20Sopenharmony_ci hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED) 5188c2ecf20Sopenharmony_ci continue; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (hard_iface->net_dev == net_dev) 5218c2ecf20Sopenharmony_ci continue; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (!batadv_compare_eth(hard_iface->net_dev->dev_addr, 5248c2ecf20Sopenharmony_ci net_dev->dev_addr)) 5258c2ecf20Sopenharmony_ci continue; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci pr_warn("The newly added mac address (%pM) already exists on: %s\n", 5288c2ecf20Sopenharmony_ci net_dev->dev_addr, hard_iface->net_dev->name); 5298c2ecf20Sopenharmony_ci pr_warn("It is strongly recommended to keep mac addresses unique to avoid problems!\n"); 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci rcu_read_unlock(); 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci/** 5358c2ecf20Sopenharmony_ci * batadv_hardif_recalc_extra_skbroom() - Recalculate skbuff extra head/tailroom 5368c2ecf20Sopenharmony_ci * @soft_iface: netdev struct of the mesh interface 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_cistatic void batadv_hardif_recalc_extra_skbroom(struct net_device *soft_iface) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci const struct batadv_hard_iface *hard_iface; 5418c2ecf20Sopenharmony_ci unsigned short lower_header_len = ETH_HLEN; 5428c2ecf20Sopenharmony_ci unsigned short lower_headroom = 0; 5438c2ecf20Sopenharmony_ci unsigned short lower_tailroom = 0; 5448c2ecf20Sopenharmony_ci unsigned short needed_headroom; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci rcu_read_lock(); 5478c2ecf20Sopenharmony_ci list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { 5488c2ecf20Sopenharmony_ci if (hard_iface->if_status == BATADV_IF_NOT_IN_USE) 5498c2ecf20Sopenharmony_ci continue; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (hard_iface->soft_iface != soft_iface) 5528c2ecf20Sopenharmony_ci continue; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci lower_header_len = max_t(unsigned short, lower_header_len, 5558c2ecf20Sopenharmony_ci hard_iface->net_dev->hard_header_len); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci lower_headroom = max_t(unsigned short, lower_headroom, 5588c2ecf20Sopenharmony_ci hard_iface->net_dev->needed_headroom); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci lower_tailroom = max_t(unsigned short, lower_tailroom, 5618c2ecf20Sopenharmony_ci hard_iface->net_dev->needed_tailroom); 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci rcu_read_unlock(); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci needed_headroom = lower_headroom + (lower_header_len - ETH_HLEN); 5668c2ecf20Sopenharmony_ci needed_headroom += batadv_max_header_len(); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* fragmentation headers don't strip the unicast/... header */ 5698c2ecf20Sopenharmony_ci needed_headroom += sizeof(struct batadv_frag_packet); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci soft_iface->needed_headroom = needed_headroom; 5728c2ecf20Sopenharmony_ci soft_iface->needed_tailroom = lower_tailroom; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci/** 5768c2ecf20Sopenharmony_ci * batadv_hardif_min_mtu() - Calculate maximum MTU for soft interface 5778c2ecf20Sopenharmony_ci * @soft_iface: netdev struct of the soft interface 5788c2ecf20Sopenharmony_ci * 5798c2ecf20Sopenharmony_ci * Return: MTU for the soft-interface (limited by the minimal MTU of all active 5808c2ecf20Sopenharmony_ci * slave interfaces) 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_ciint batadv_hardif_min_mtu(struct net_device *soft_iface) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(soft_iface); 5858c2ecf20Sopenharmony_ci const struct batadv_hard_iface *hard_iface; 5868c2ecf20Sopenharmony_ci int min_mtu = INT_MAX; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci rcu_read_lock(); 5898c2ecf20Sopenharmony_ci list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { 5908c2ecf20Sopenharmony_ci if (hard_iface->if_status != BATADV_IF_ACTIVE && 5918c2ecf20Sopenharmony_ci hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED) 5928c2ecf20Sopenharmony_ci continue; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (hard_iface->soft_iface != soft_iface) 5958c2ecf20Sopenharmony_ci continue; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci min_mtu = min_t(int, hard_iface->net_dev->mtu, min_mtu); 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci rcu_read_unlock(); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (atomic_read(&bat_priv->fragmentation) == 0) 6028c2ecf20Sopenharmony_ci goto out; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* with fragmentation enabled the maximum size of internally generated 6058c2ecf20Sopenharmony_ci * packets such as translation table exchanges or tvlv containers, etc 6068c2ecf20Sopenharmony_ci * has to be calculated 6078c2ecf20Sopenharmony_ci */ 6088c2ecf20Sopenharmony_ci min_mtu = min_t(int, min_mtu, BATADV_FRAG_MAX_FRAG_SIZE); 6098c2ecf20Sopenharmony_ci min_mtu -= sizeof(struct batadv_frag_packet); 6108c2ecf20Sopenharmony_ci min_mtu *= BATADV_FRAG_MAX_FRAGMENTS; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ciout: 6138c2ecf20Sopenharmony_ci /* report to the other components the maximum amount of bytes that 6148c2ecf20Sopenharmony_ci * batman-adv can send over the wire (without considering the payload 6158c2ecf20Sopenharmony_ci * overhead). For example, this value is used by TT to compute the 6168c2ecf20Sopenharmony_ci * maximum local table size 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_ci atomic_set(&bat_priv->packet_size_max, min_mtu); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* the real soft-interface MTU is computed by removing the payload 6218c2ecf20Sopenharmony_ci * overhead from the maximum amount of bytes that was just computed. 6228c2ecf20Sopenharmony_ci * 6238c2ecf20Sopenharmony_ci * However batman-adv does not support MTUs bigger than ETH_DATA_LEN 6248c2ecf20Sopenharmony_ci */ 6258c2ecf20Sopenharmony_ci return min_t(int, min_mtu - batadv_max_header_len(), ETH_DATA_LEN); 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci/** 6298c2ecf20Sopenharmony_ci * batadv_update_min_mtu() - Adjusts the MTU if a new interface with a smaller 6308c2ecf20Sopenharmony_ci * MTU appeared 6318c2ecf20Sopenharmony_ci * @soft_iface: netdev struct of the soft interface 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_civoid batadv_update_min_mtu(struct net_device *soft_iface) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(soft_iface); 6368c2ecf20Sopenharmony_ci int limit_mtu; 6378c2ecf20Sopenharmony_ci int mtu; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci mtu = batadv_hardif_min_mtu(soft_iface); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (bat_priv->mtu_set_by_user) 6428c2ecf20Sopenharmony_ci limit_mtu = bat_priv->mtu_set_by_user; 6438c2ecf20Sopenharmony_ci else 6448c2ecf20Sopenharmony_ci limit_mtu = ETH_DATA_LEN; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci mtu = min(mtu, limit_mtu); 6478c2ecf20Sopenharmony_ci dev_set_mtu(soft_iface, mtu); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* Check if the local translate table should be cleaned up to match a 6508c2ecf20Sopenharmony_ci * new (and smaller) MTU. 6518c2ecf20Sopenharmony_ci */ 6528c2ecf20Sopenharmony_ci batadv_tt_local_resize_to_mtu(soft_iface); 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic void 6568c2ecf20Sopenharmony_cibatadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv; 6598c2ecf20Sopenharmony_ci struct batadv_hard_iface *primary_if = NULL; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (hard_iface->if_status != BATADV_IF_INACTIVE) 6628c2ecf20Sopenharmony_ci goto out; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci bat_priv = netdev_priv(hard_iface->soft_iface); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci bat_priv->algo_ops->iface.update_mac(hard_iface); 6678c2ecf20Sopenharmony_ci hard_iface->if_status = BATADV_IF_TO_BE_ACTIVATED; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci /* the first active interface becomes our primary interface or 6708c2ecf20Sopenharmony_ci * the next active interface after the old primary interface was removed 6718c2ecf20Sopenharmony_ci */ 6728c2ecf20Sopenharmony_ci primary_if = batadv_primary_if_get_selected(bat_priv); 6738c2ecf20Sopenharmony_ci if (!primary_if) 6748c2ecf20Sopenharmony_ci batadv_primary_if_select(bat_priv, hard_iface); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci batadv_info(hard_iface->soft_iface, "Interface activated: %s\n", 6778c2ecf20Sopenharmony_ci hard_iface->net_dev->name); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci batadv_update_min_mtu(hard_iface->soft_iface); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (bat_priv->algo_ops->iface.activate) 6828c2ecf20Sopenharmony_ci bat_priv->algo_ops->iface.activate(hard_iface); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ciout: 6858c2ecf20Sopenharmony_ci if (primary_if) 6868c2ecf20Sopenharmony_ci batadv_hardif_put(primary_if); 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic void 6908c2ecf20Sopenharmony_cibatadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci if (hard_iface->if_status != BATADV_IF_ACTIVE && 6938c2ecf20Sopenharmony_ci hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED) 6948c2ecf20Sopenharmony_ci return; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci hard_iface->if_status = BATADV_IF_INACTIVE; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci batadv_info(hard_iface->soft_iface, "Interface deactivated: %s\n", 6998c2ecf20Sopenharmony_ci hard_iface->net_dev->name); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci batadv_update_min_mtu(hard_iface->soft_iface); 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci/** 7058c2ecf20Sopenharmony_ci * batadv_master_del_slave() - remove hard_iface from the current master iface 7068c2ecf20Sopenharmony_ci * @slave: the interface enslaved in another master 7078c2ecf20Sopenharmony_ci * @master: the master from which slave has to be removed 7088c2ecf20Sopenharmony_ci * 7098c2ecf20Sopenharmony_ci * Invoke ndo_del_slave on master passing slave as argument. In this way the 7108c2ecf20Sopenharmony_ci * slave is free'd and the master can correctly change its internal state. 7118c2ecf20Sopenharmony_ci * 7128c2ecf20Sopenharmony_ci * Return: 0 on success, a negative value representing the error otherwise 7138c2ecf20Sopenharmony_ci */ 7148c2ecf20Sopenharmony_cistatic int batadv_master_del_slave(struct batadv_hard_iface *slave, 7158c2ecf20Sopenharmony_ci struct net_device *master) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci int ret; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (!master) 7208c2ecf20Sopenharmony_ci return 0; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci ret = -EBUSY; 7238c2ecf20Sopenharmony_ci if (master->netdev_ops->ndo_del_slave) 7248c2ecf20Sopenharmony_ci ret = master->netdev_ops->ndo_del_slave(master, slave->net_dev); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return ret; 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci/** 7308c2ecf20Sopenharmony_ci * batadv_hardif_enable_interface() - Enslave hard interface to soft interface 7318c2ecf20Sopenharmony_ci * @hard_iface: hard interface to add to soft interface 7328c2ecf20Sopenharmony_ci * @net: the applicable net namespace 7338c2ecf20Sopenharmony_ci * @iface_name: name of the soft interface 7348c2ecf20Sopenharmony_ci * 7358c2ecf20Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 7368c2ecf20Sopenharmony_ci */ 7378c2ecf20Sopenharmony_ciint batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, 7388c2ecf20Sopenharmony_ci struct net *net, const char *iface_name) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv; 7418c2ecf20Sopenharmony_ci struct net_device *soft_iface, *master; 7428c2ecf20Sopenharmony_ci __be16 ethertype = htons(ETH_P_BATMAN); 7438c2ecf20Sopenharmony_ci int max_header_len = batadv_max_header_len(); 7448c2ecf20Sopenharmony_ci int ret; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) 7478c2ecf20Sopenharmony_ci goto out; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci kref_get(&hard_iface->refcount); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci soft_iface = dev_get_by_name(net, iface_name); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (!soft_iface) { 7548c2ecf20Sopenharmony_ci soft_iface = batadv_softif_create(net, iface_name); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci if (!soft_iface) { 7578c2ecf20Sopenharmony_ci ret = -ENOMEM; 7588c2ecf20Sopenharmony_ci goto err; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci /* dev_get_by_name() increases the reference counter for us */ 7628c2ecf20Sopenharmony_ci dev_hold(soft_iface); 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci if (!batadv_softif_is_valid(soft_iface)) { 7668c2ecf20Sopenharmony_ci pr_err("Can't create batman mesh interface %s: already exists as regular interface\n", 7678c2ecf20Sopenharmony_ci soft_iface->name); 7688c2ecf20Sopenharmony_ci ret = -EINVAL; 7698c2ecf20Sopenharmony_ci goto err_dev; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci /* check if the interface is enslaved in another virtual one and 7738c2ecf20Sopenharmony_ci * in that case unlink it first 7748c2ecf20Sopenharmony_ci */ 7758c2ecf20Sopenharmony_ci master = netdev_master_upper_dev_get(hard_iface->net_dev); 7768c2ecf20Sopenharmony_ci ret = batadv_master_del_slave(hard_iface, master); 7778c2ecf20Sopenharmony_ci if (ret) 7788c2ecf20Sopenharmony_ci goto err_dev; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci hard_iface->soft_iface = soft_iface; 7818c2ecf20Sopenharmony_ci bat_priv = netdev_priv(hard_iface->soft_iface); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci ret = netdev_master_upper_dev_link(hard_iface->net_dev, 7848c2ecf20Sopenharmony_ci soft_iface, NULL, NULL, NULL); 7858c2ecf20Sopenharmony_ci if (ret) 7868c2ecf20Sopenharmony_ci goto err_dev; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci ret = bat_priv->algo_ops->iface.enable(hard_iface); 7898c2ecf20Sopenharmony_ci if (ret < 0) 7908c2ecf20Sopenharmony_ci goto err_upper; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci hard_iface->if_status = BATADV_IF_INACTIVE; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci kref_get(&hard_iface->refcount); 7958c2ecf20Sopenharmony_ci hard_iface->batman_adv_ptype.type = ethertype; 7968c2ecf20Sopenharmony_ci hard_iface->batman_adv_ptype.func = batadv_batman_skb_recv; 7978c2ecf20Sopenharmony_ci hard_iface->batman_adv_ptype.dev = hard_iface->net_dev; 7988c2ecf20Sopenharmony_ci dev_add_pack(&hard_iface->batman_adv_ptype); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci batadv_info(hard_iface->soft_iface, "Adding interface: %s\n", 8018c2ecf20Sopenharmony_ci hard_iface->net_dev->name); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (atomic_read(&bat_priv->fragmentation) && 8048c2ecf20Sopenharmony_ci hard_iface->net_dev->mtu < ETH_DATA_LEN + max_header_len) 8058c2ecf20Sopenharmony_ci batadv_info(hard_iface->soft_iface, 8068c2ecf20Sopenharmony_ci "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to %i would solve the problem.\n", 8078c2ecf20Sopenharmony_ci hard_iface->net_dev->name, hard_iface->net_dev->mtu, 8088c2ecf20Sopenharmony_ci ETH_DATA_LEN + max_header_len); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (!atomic_read(&bat_priv->fragmentation) && 8118c2ecf20Sopenharmony_ci hard_iface->net_dev->mtu < ETH_DATA_LEN + max_header_len) 8128c2ecf20Sopenharmony_ci batadv_info(hard_iface->soft_iface, 8138c2ecf20Sopenharmony_ci "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. If you experience problems getting traffic through try increasing the MTU to %i.\n", 8148c2ecf20Sopenharmony_ci hard_iface->net_dev->name, hard_iface->net_dev->mtu, 8158c2ecf20Sopenharmony_ci ETH_DATA_LEN + max_header_len); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (batadv_hardif_is_iface_up(hard_iface)) 8188c2ecf20Sopenharmony_ci batadv_hardif_activate_interface(hard_iface); 8198c2ecf20Sopenharmony_ci else 8208c2ecf20Sopenharmony_ci batadv_err(hard_iface->soft_iface, 8218c2ecf20Sopenharmony_ci "Not using interface %s (retrying later): interface not active\n", 8228c2ecf20Sopenharmony_ci hard_iface->net_dev->name); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci batadv_hardif_recalc_extra_skbroom(soft_iface); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (bat_priv->algo_ops->iface.enabled) 8278c2ecf20Sopenharmony_ci bat_priv->algo_ops->iface.enabled(hard_iface); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ciout: 8308c2ecf20Sopenharmony_ci return 0; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_cierr_upper: 8338c2ecf20Sopenharmony_ci netdev_upper_dev_unlink(hard_iface->net_dev, soft_iface); 8348c2ecf20Sopenharmony_cierr_dev: 8358c2ecf20Sopenharmony_ci hard_iface->soft_iface = NULL; 8368c2ecf20Sopenharmony_ci dev_put(soft_iface); 8378c2ecf20Sopenharmony_cierr: 8388c2ecf20Sopenharmony_ci batadv_hardif_put(hard_iface); 8398c2ecf20Sopenharmony_ci return ret; 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci/** 8438c2ecf20Sopenharmony_ci * batadv_hardif_cnt() - get number of interfaces enslaved to soft interface 8448c2ecf20Sopenharmony_ci * @soft_iface: soft interface to check 8458c2ecf20Sopenharmony_ci * 8468c2ecf20Sopenharmony_ci * This function is only using RCU for locking - the result can therefore be 8478c2ecf20Sopenharmony_ci * off when another function is modifying the list at the same time. The 8488c2ecf20Sopenharmony_ci * caller can use the rtnl_lock to make sure that the count is accurate. 8498c2ecf20Sopenharmony_ci * 8508c2ecf20Sopenharmony_ci * Return: number of connected/enslaved hard interfaces 8518c2ecf20Sopenharmony_ci */ 8528c2ecf20Sopenharmony_cistatic size_t batadv_hardif_cnt(const struct net_device *soft_iface) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface; 8558c2ecf20Sopenharmony_ci size_t count = 0; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci rcu_read_lock(); 8588c2ecf20Sopenharmony_ci list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { 8598c2ecf20Sopenharmony_ci if (hard_iface->soft_iface != soft_iface) 8608c2ecf20Sopenharmony_ci continue; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci count++; 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci rcu_read_unlock(); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci return count; 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci/** 8708c2ecf20Sopenharmony_ci * batadv_hardif_disable_interface() - Remove hard interface from soft interface 8718c2ecf20Sopenharmony_ci * @hard_iface: hard interface to be removed 8728c2ecf20Sopenharmony_ci * @autodel: whether to delete soft interface when it doesn't contain any other 8738c2ecf20Sopenharmony_ci * slave interfaces 8748c2ecf20Sopenharmony_ci */ 8758c2ecf20Sopenharmony_civoid batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, 8768c2ecf20Sopenharmony_ci enum batadv_hard_if_cleanup autodel) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); 8798c2ecf20Sopenharmony_ci struct batadv_hard_iface *primary_if = NULL; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci batadv_hardif_deactivate_interface(hard_iface); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (hard_iface->if_status != BATADV_IF_INACTIVE) 8848c2ecf20Sopenharmony_ci goto out; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci batadv_info(hard_iface->soft_iface, "Removing interface: %s\n", 8878c2ecf20Sopenharmony_ci hard_iface->net_dev->name); 8888c2ecf20Sopenharmony_ci dev_remove_pack(&hard_iface->batman_adv_ptype); 8898c2ecf20Sopenharmony_ci batadv_hardif_put(hard_iface); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci primary_if = batadv_primary_if_get_selected(bat_priv); 8928c2ecf20Sopenharmony_ci if (hard_iface == primary_if) { 8938c2ecf20Sopenharmony_ci struct batadv_hard_iface *new_if; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci new_if = batadv_hardif_get_active(hard_iface->soft_iface); 8968c2ecf20Sopenharmony_ci batadv_primary_if_select(bat_priv, new_if); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (new_if) 8998c2ecf20Sopenharmony_ci batadv_hardif_put(new_if); 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci bat_priv->algo_ops->iface.disable(hard_iface); 9038c2ecf20Sopenharmony_ci hard_iface->if_status = BATADV_IF_NOT_IN_USE; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* delete all references to this hard_iface */ 9068c2ecf20Sopenharmony_ci batadv_purge_orig_ref(bat_priv); 9078c2ecf20Sopenharmony_ci batadv_purge_outstanding_packets(bat_priv, hard_iface); 9088c2ecf20Sopenharmony_ci dev_put(hard_iface->soft_iface); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->soft_iface); 9118c2ecf20Sopenharmony_ci batadv_hardif_recalc_extra_skbroom(hard_iface->soft_iface); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* nobody uses this interface anymore */ 9148c2ecf20Sopenharmony_ci if (batadv_hardif_cnt(hard_iface->soft_iface) <= 1) { 9158c2ecf20Sopenharmony_ci batadv_gw_check_client_stop(bat_priv); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci if (autodel == BATADV_IF_CLEANUP_AUTO) 9188c2ecf20Sopenharmony_ci batadv_softif_destroy_sysfs(hard_iface->soft_iface); 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci hard_iface->soft_iface = NULL; 9228c2ecf20Sopenharmony_ci batadv_hardif_put(hard_iface); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ciout: 9258c2ecf20Sopenharmony_ci if (primary_if) 9268c2ecf20Sopenharmony_ci batadv_hardif_put(primary_if); 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic struct batadv_hard_iface * 9308c2ecf20Sopenharmony_cibatadv_hardif_add_interface(struct net_device *net_dev) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface; 9338c2ecf20Sopenharmony_ci int ret; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci ASSERT_RTNL(); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (!batadv_is_valid_iface(net_dev)) 9388c2ecf20Sopenharmony_ci goto out; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci dev_hold(net_dev); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci hard_iface = kzalloc(sizeof(*hard_iface), GFP_ATOMIC); 9438c2ecf20Sopenharmony_ci if (!hard_iface) 9448c2ecf20Sopenharmony_ci goto release_dev; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci ret = batadv_sysfs_add_hardif(&hard_iface->hardif_obj, net_dev); 9478c2ecf20Sopenharmony_ci if (ret) 9488c2ecf20Sopenharmony_ci goto free_if; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci hard_iface->net_dev = net_dev; 9518c2ecf20Sopenharmony_ci hard_iface->soft_iface = NULL; 9528c2ecf20Sopenharmony_ci hard_iface->if_status = BATADV_IF_NOT_IN_USE; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci batadv_debugfs_add_hardif(hard_iface); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hard_iface->list); 9578c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&hard_iface->neigh_list); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci mutex_init(&hard_iface->bat_iv.ogm_buff_mutex); 9608c2ecf20Sopenharmony_ci spin_lock_init(&hard_iface->neigh_list_lock); 9618c2ecf20Sopenharmony_ci kref_init(&hard_iface->refcount); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci hard_iface->num_bcasts = BATADV_NUM_BCASTS_DEFAULT; 9648c2ecf20Sopenharmony_ci hard_iface->wifi_flags = batadv_wifi_flags_evaluate(net_dev); 9658c2ecf20Sopenharmony_ci if (batadv_is_wifi_hardif(hard_iface)) 9668c2ecf20Sopenharmony_ci hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci atomic_set(&hard_iface->hop_penalty, 0); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci batadv_v_hardif_init(hard_iface); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci batadv_check_known_mac_addr(hard_iface->net_dev); 9738c2ecf20Sopenharmony_ci kref_get(&hard_iface->refcount); 9748c2ecf20Sopenharmony_ci list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list); 9758c2ecf20Sopenharmony_ci batadv_hardif_generation++; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci return hard_iface; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cifree_if: 9808c2ecf20Sopenharmony_ci kfree(hard_iface); 9818c2ecf20Sopenharmony_cirelease_dev: 9828c2ecf20Sopenharmony_ci dev_put(net_dev); 9838c2ecf20Sopenharmony_ciout: 9848c2ecf20Sopenharmony_ci return NULL; 9858c2ecf20Sopenharmony_ci} 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_cistatic void batadv_hardif_remove_interface(struct batadv_hard_iface *hard_iface) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci ASSERT_RTNL(); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci /* first deactivate interface */ 9928c2ecf20Sopenharmony_ci if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) 9938c2ecf20Sopenharmony_ci batadv_hardif_disable_interface(hard_iface, 9948c2ecf20Sopenharmony_ci BATADV_IF_CLEANUP_KEEP); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) 9978c2ecf20Sopenharmony_ci return; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci hard_iface->if_status = BATADV_IF_TO_BE_REMOVED; 10008c2ecf20Sopenharmony_ci batadv_debugfs_del_hardif(hard_iface); 10018c2ecf20Sopenharmony_ci batadv_sysfs_del_hardif(&hard_iface->hardif_obj); 10028c2ecf20Sopenharmony_ci batadv_hardif_put(hard_iface); 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci/** 10068c2ecf20Sopenharmony_ci * batadv_hard_if_event_softif() - Handle events for soft interfaces 10078c2ecf20Sopenharmony_ci * @event: NETDEV_* event to handle 10088c2ecf20Sopenharmony_ci * @net_dev: net_device which generated an event 10098c2ecf20Sopenharmony_ci * 10108c2ecf20Sopenharmony_ci * Return: NOTIFY_* result 10118c2ecf20Sopenharmony_ci */ 10128c2ecf20Sopenharmony_cistatic int batadv_hard_if_event_softif(unsigned long event, 10138c2ecf20Sopenharmony_ci struct net_device *net_dev) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci switch (event) { 10188c2ecf20Sopenharmony_ci case NETDEV_REGISTER: 10198c2ecf20Sopenharmony_ci batadv_sysfs_add_meshif(net_dev); 10208c2ecf20Sopenharmony_ci bat_priv = netdev_priv(net_dev); 10218c2ecf20Sopenharmony_ci batadv_softif_create_vlan(bat_priv, BATADV_NO_FLAGS); 10228c2ecf20Sopenharmony_ci break; 10238c2ecf20Sopenharmony_ci case NETDEV_CHANGENAME: 10248c2ecf20Sopenharmony_ci batadv_debugfs_rename_meshif(net_dev); 10258c2ecf20Sopenharmony_ci break; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci return NOTIFY_DONE; 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_cistatic int batadv_hard_if_event(struct notifier_block *this, 10328c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 10338c2ecf20Sopenharmony_ci{ 10348c2ecf20Sopenharmony_ci struct net_device *net_dev = netdev_notifier_info_to_dev(ptr); 10358c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface; 10368c2ecf20Sopenharmony_ci struct batadv_hard_iface *primary_if = NULL; 10378c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (batadv_softif_is_valid(net_dev)) 10408c2ecf20Sopenharmony_ci return batadv_hard_if_event_softif(event, net_dev); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci hard_iface = batadv_hardif_get_by_netdev(net_dev); 10438c2ecf20Sopenharmony_ci if (!hard_iface && (event == NETDEV_REGISTER || 10448c2ecf20Sopenharmony_ci event == NETDEV_POST_TYPE_CHANGE)) 10458c2ecf20Sopenharmony_ci hard_iface = batadv_hardif_add_interface(net_dev); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (!hard_iface) 10488c2ecf20Sopenharmony_ci goto out; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci switch (event) { 10518c2ecf20Sopenharmony_ci case NETDEV_UP: 10528c2ecf20Sopenharmony_ci batadv_hardif_activate_interface(hard_iface); 10538c2ecf20Sopenharmony_ci break; 10548c2ecf20Sopenharmony_ci case NETDEV_GOING_DOWN: 10558c2ecf20Sopenharmony_ci case NETDEV_DOWN: 10568c2ecf20Sopenharmony_ci batadv_hardif_deactivate_interface(hard_iface); 10578c2ecf20Sopenharmony_ci break; 10588c2ecf20Sopenharmony_ci case NETDEV_UNREGISTER: 10598c2ecf20Sopenharmony_ci case NETDEV_PRE_TYPE_CHANGE: 10608c2ecf20Sopenharmony_ci list_del_rcu(&hard_iface->list); 10618c2ecf20Sopenharmony_ci batadv_hardif_generation++; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci batadv_hardif_remove_interface(hard_iface); 10648c2ecf20Sopenharmony_ci break; 10658c2ecf20Sopenharmony_ci case NETDEV_CHANGEMTU: 10668c2ecf20Sopenharmony_ci if (hard_iface->soft_iface) 10678c2ecf20Sopenharmony_ci batadv_update_min_mtu(hard_iface->soft_iface); 10688c2ecf20Sopenharmony_ci break; 10698c2ecf20Sopenharmony_ci case NETDEV_CHANGEADDR: 10708c2ecf20Sopenharmony_ci if (hard_iface->if_status == BATADV_IF_NOT_IN_USE) 10718c2ecf20Sopenharmony_ci goto hardif_put; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci batadv_check_known_mac_addr(hard_iface->net_dev); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci bat_priv = netdev_priv(hard_iface->soft_iface); 10768c2ecf20Sopenharmony_ci bat_priv->algo_ops->iface.update_mac(hard_iface); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci primary_if = batadv_primary_if_get_selected(bat_priv); 10798c2ecf20Sopenharmony_ci if (!primary_if) 10808c2ecf20Sopenharmony_ci goto hardif_put; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (hard_iface == primary_if) 10838c2ecf20Sopenharmony_ci batadv_primary_if_update_addr(bat_priv, NULL); 10848c2ecf20Sopenharmony_ci break; 10858c2ecf20Sopenharmony_ci case NETDEV_CHANGEUPPER: 10868c2ecf20Sopenharmony_ci hard_iface->wifi_flags = batadv_wifi_flags_evaluate(net_dev); 10878c2ecf20Sopenharmony_ci if (batadv_is_wifi_hardif(hard_iface)) 10888c2ecf20Sopenharmony_ci hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS; 10898c2ecf20Sopenharmony_ci break; 10908c2ecf20Sopenharmony_ci case NETDEV_CHANGENAME: 10918c2ecf20Sopenharmony_ci batadv_debugfs_rename_hardif(hard_iface); 10928c2ecf20Sopenharmony_ci break; 10938c2ecf20Sopenharmony_ci default: 10948c2ecf20Sopenharmony_ci break; 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_cihardif_put: 10988c2ecf20Sopenharmony_ci batadv_hardif_put(hard_iface); 10998c2ecf20Sopenharmony_ciout: 11008c2ecf20Sopenharmony_ci if (primary_if) 11018c2ecf20Sopenharmony_ci batadv_hardif_put(primary_if); 11028c2ecf20Sopenharmony_ci return NOTIFY_DONE; 11038c2ecf20Sopenharmony_ci} 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_cistruct notifier_block batadv_hard_if_notifier = { 11068c2ecf20Sopenharmony_ci .notifier_call = batadv_hard_if_event, 11078c2ecf20Sopenharmony_ci}; 1108