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 "soft-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/cache.h> 138c2ecf20Sopenharmony_ci#include <linux/compiler.h> 148c2ecf20Sopenharmony_ci#include <linux/cpumask.h> 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 178c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 188c2ecf20Sopenharmony_ci#include <linux/gfp.h> 198c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 208c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 218c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 228c2ecf20Sopenharmony_ci#include <linux/kernel.h> 238c2ecf20Sopenharmony_ci#include <linux/kref.h> 248c2ecf20Sopenharmony_ci#include <linux/list.h> 258c2ecf20Sopenharmony_ci#include <linux/lockdep.h> 268c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 278c2ecf20Sopenharmony_ci#include <linux/netlink.h> 288c2ecf20Sopenharmony_ci#include <linux/percpu.h> 298c2ecf20Sopenharmony_ci#include <linux/printk.h> 308c2ecf20Sopenharmony_ci#include <linux/random.h> 318c2ecf20Sopenharmony_ci#include <linux/rculist.h> 328c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 338c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 348c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 358c2ecf20Sopenharmony_ci#include <linux/slab.h> 368c2ecf20Sopenharmony_ci#include <linux/socket.h> 378c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 388c2ecf20Sopenharmony_ci#include <linux/stddef.h> 398c2ecf20Sopenharmony_ci#include <linux/string.h> 408c2ecf20Sopenharmony_ci#include <linux/types.h> 418c2ecf20Sopenharmony_ci#include <uapi/linux/batadv_packet.h> 428c2ecf20Sopenharmony_ci#include <uapi/linux/batman_adv.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include "bat_algo.h" 458c2ecf20Sopenharmony_ci#include "bridge_loop_avoidance.h" 468c2ecf20Sopenharmony_ci#include "debugfs.h" 478c2ecf20Sopenharmony_ci#include "distributed-arp-table.h" 488c2ecf20Sopenharmony_ci#include "gateway_client.h" 498c2ecf20Sopenharmony_ci#include "hard-interface.h" 508c2ecf20Sopenharmony_ci#include "multicast.h" 518c2ecf20Sopenharmony_ci#include "network-coding.h" 528c2ecf20Sopenharmony_ci#include "originator.h" 538c2ecf20Sopenharmony_ci#include "send.h" 548c2ecf20Sopenharmony_ci#include "sysfs.h" 558c2ecf20Sopenharmony_ci#include "translation-table.h" 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/** 588c2ecf20Sopenharmony_ci * batadv_skb_head_push() - Increase header size and move (push) head pointer 598c2ecf20Sopenharmony_ci * @skb: packet buffer which should be modified 608c2ecf20Sopenharmony_ci * @len: number of bytes to add 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ciint batadv_skb_head_push(struct sk_buff *skb, unsigned int len) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci int result; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* TODO: We must check if we can release all references to non-payload 698c2ecf20Sopenharmony_ci * data using __skb_header_release in our skbs to allow skb_cow_header 708c2ecf20Sopenharmony_ci * to work optimally. This means that those skbs are not allowed to read 718c2ecf20Sopenharmony_ci * or write any data which is before the current position of skb->data 728c2ecf20Sopenharmony_ci * after that call and thus allow other skbs with the same data buffer 738c2ecf20Sopenharmony_ci * to write freely in that area. 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci result = skb_cow_head(skb, len); 768c2ecf20Sopenharmony_ci if (result < 0) 778c2ecf20Sopenharmony_ci return result; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci skb_push(skb, len); 808c2ecf20Sopenharmony_ci return 0; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int batadv_interface_open(struct net_device *dev) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci netif_start_queue(dev); 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic int batadv_interface_release(struct net_device *dev) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci netif_stop_queue(dev); 928c2ecf20Sopenharmony_ci return 0; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/** 968c2ecf20Sopenharmony_ci * batadv_sum_counter() - Sum the cpu-local counters for index 'idx' 978c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 988c2ecf20Sopenharmony_ci * @idx: index of counter to sum up 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Return: sum of all cpu-local counters 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_cistatic u64 batadv_sum_counter(struct batadv_priv *bat_priv, size_t idx) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci u64 *counters, sum = 0; 1058c2ecf20Sopenharmony_ci int cpu; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 1088c2ecf20Sopenharmony_ci counters = per_cpu_ptr(bat_priv->bat_counters, cpu); 1098c2ecf20Sopenharmony_ci sum += counters[idx]; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return sum; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic struct net_device_stats *batadv_interface_stats(struct net_device *dev) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(dev); 1188c2ecf20Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci stats->tx_packets = batadv_sum_counter(bat_priv, BATADV_CNT_TX); 1218c2ecf20Sopenharmony_ci stats->tx_bytes = batadv_sum_counter(bat_priv, BATADV_CNT_TX_BYTES); 1228c2ecf20Sopenharmony_ci stats->tx_dropped = batadv_sum_counter(bat_priv, BATADV_CNT_TX_DROPPED); 1238c2ecf20Sopenharmony_ci stats->rx_packets = batadv_sum_counter(bat_priv, BATADV_CNT_RX); 1248c2ecf20Sopenharmony_ci stats->rx_bytes = batadv_sum_counter(bat_priv, BATADV_CNT_RX_BYTES); 1258c2ecf20Sopenharmony_ci return stats; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int batadv_interface_set_mac_addr(struct net_device *dev, void *p) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(dev); 1318c2ecf20Sopenharmony_ci struct batadv_softif_vlan *vlan; 1328c2ecf20Sopenharmony_ci struct sockaddr *addr = p; 1338c2ecf20Sopenharmony_ci u8 old_addr[ETH_ALEN]; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 1368c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci ether_addr_copy(old_addr, dev->dev_addr); 1398c2ecf20Sopenharmony_ci ether_addr_copy(dev->dev_addr, addr->sa_data); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* only modify transtable if it has been initialized before */ 1428c2ecf20Sopenharmony_ci if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci rcu_read_lock(); 1468c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { 1478c2ecf20Sopenharmony_ci batadv_tt_local_remove(bat_priv, old_addr, vlan->vid, 1488c2ecf20Sopenharmony_ci "mac address changed", false); 1498c2ecf20Sopenharmony_ci batadv_tt_local_add(dev, addr->sa_data, vlan->vid, 1508c2ecf20Sopenharmony_ci BATADV_NULL_IFINDEX, BATADV_NO_MARK); 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci rcu_read_unlock(); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int batadv_interface_change_mtu(struct net_device *dev, int new_mtu) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(dev); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* check ranges */ 1628c2ecf20Sopenharmony_ci if (new_mtu < 68 || new_mtu > batadv_hardif_min_mtu(dev)) 1638c2ecf20Sopenharmony_ci return -EINVAL; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 1668c2ecf20Sopenharmony_ci bat_priv->mtu_set_by_user = new_mtu; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/** 1728c2ecf20Sopenharmony_ci * batadv_interface_set_rx_mode() - set the rx mode of a device 1738c2ecf20Sopenharmony_ci * @dev: registered network device to modify 1748c2ecf20Sopenharmony_ci * 1758c2ecf20Sopenharmony_ci * We do not actually need to set any rx filters for the virtual batman 1768c2ecf20Sopenharmony_ci * soft interface. However a dummy handler enables a user to set static 1778c2ecf20Sopenharmony_ci * multicast listeners for instance. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_cistatic void batadv_interface_set_rx_mode(struct net_device *dev) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic netdev_tx_t batadv_interface_tx(struct sk_buff *skb, 1848c2ecf20Sopenharmony_ci struct net_device *soft_iface) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct ethhdr *ethhdr; 1878c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(soft_iface); 1888c2ecf20Sopenharmony_ci struct batadv_hard_iface *primary_if = NULL; 1898c2ecf20Sopenharmony_ci struct batadv_bcast_packet *bcast_packet; 1908c2ecf20Sopenharmony_ci static const u8 stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 1918c2ecf20Sopenharmony_ci 0x00, 0x00}; 1928c2ecf20Sopenharmony_ci static const u8 ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, 1938c2ecf20Sopenharmony_ci 0x00, 0x00}; 1948c2ecf20Sopenharmony_ci enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO; 1958c2ecf20Sopenharmony_ci u8 *dst_hint = NULL, chaddr[ETH_ALEN]; 1968c2ecf20Sopenharmony_ci struct vlan_ethhdr *vhdr; 1978c2ecf20Sopenharmony_ci unsigned int header_len = 0; 1988c2ecf20Sopenharmony_ci int data_len = skb->len, ret; 1998c2ecf20Sopenharmony_ci unsigned long brd_delay = 1; 2008c2ecf20Sopenharmony_ci bool do_bcast = false, client_added; 2018c2ecf20Sopenharmony_ci unsigned short vid; 2028c2ecf20Sopenharmony_ci u32 seqno; 2038c2ecf20Sopenharmony_ci int gw_mode; 2048c2ecf20Sopenharmony_ci enum batadv_forw_mode forw_mode = BATADV_FORW_SINGLE; 2058c2ecf20Sopenharmony_ci struct batadv_orig_node *mcast_single_orig = NULL; 2068c2ecf20Sopenharmony_ci int mcast_is_routable = 0; 2078c2ecf20Sopenharmony_ci int network_offset = ETH_HLEN; 2088c2ecf20Sopenharmony_ci __be16 proto; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) 2118c2ecf20Sopenharmony_ci goto dropped; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* reset control block to avoid left overs from previous users */ 2148c2ecf20Sopenharmony_ci memset(skb->cb, 0, sizeof(struct batadv_skb_cb)); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci netif_trans_update(soft_iface); 2178c2ecf20Sopenharmony_ci vid = batadv_get_vid(skb, 0); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 2208c2ecf20Sopenharmony_ci ethhdr = eth_hdr(skb); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci proto = ethhdr->h_proto; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci switch (ntohs(proto)) { 2258c2ecf20Sopenharmony_ci case ETH_P_8021Q: 2268c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(*vhdr))) 2278c2ecf20Sopenharmony_ci goto dropped; 2288c2ecf20Sopenharmony_ci vhdr = vlan_eth_hdr(skb); 2298c2ecf20Sopenharmony_ci proto = vhdr->h_vlan_encapsulated_proto; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* drop batman-in-batman packets to prevent loops */ 2328c2ecf20Sopenharmony_ci if (proto != htons(ETH_P_BATMAN)) { 2338c2ecf20Sopenharmony_ci network_offset += VLAN_HLEN; 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci fallthrough; 2388c2ecf20Sopenharmony_ci case ETH_P_BATMAN: 2398c2ecf20Sopenharmony_ci goto dropped; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci skb_set_network_header(skb, network_offset); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (batadv_bla_tx(bat_priv, skb, vid)) 2458c2ecf20Sopenharmony_ci goto dropped; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* skb->data might have been reallocated by batadv_bla_tx() */ 2488c2ecf20Sopenharmony_ci ethhdr = eth_hdr(skb); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* Register the client MAC in the transtable */ 2518c2ecf20Sopenharmony_ci if (!is_multicast_ether_addr(ethhdr->h_source) && 2528c2ecf20Sopenharmony_ci !batadv_bla_is_loopdetect_mac(ethhdr->h_source)) { 2538c2ecf20Sopenharmony_ci client_added = batadv_tt_local_add(soft_iface, ethhdr->h_source, 2548c2ecf20Sopenharmony_ci vid, skb->skb_iif, 2558c2ecf20Sopenharmony_ci skb->mark); 2568c2ecf20Sopenharmony_ci if (!client_added) 2578c2ecf20Sopenharmony_ci goto dropped; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* Snoop address candidates from DHCPACKs for early DAT filling */ 2618c2ecf20Sopenharmony_ci batadv_dat_snoop_outgoing_dhcp_ack(bat_priv, skb, proto, vid); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* don't accept stp packets. STP does not help in meshes. 2648c2ecf20Sopenharmony_ci * better use the bridge loop avoidance ... 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * The same goes for ECTP sent at least by some Cisco Switches, 2678c2ecf20Sopenharmony_ci * it might confuse the mesh when used with bridge loop avoidance. 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_ci if (batadv_compare_eth(ethhdr->h_dest, stp_addr)) 2708c2ecf20Sopenharmony_ci goto dropped; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (batadv_compare_eth(ethhdr->h_dest, ectp_addr)) 2738c2ecf20Sopenharmony_ci goto dropped; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci gw_mode = atomic_read(&bat_priv->gw.mode); 2768c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(ethhdr->h_dest)) { 2778c2ecf20Sopenharmony_ci /* if gw mode is off, broadcast every packet */ 2788c2ecf20Sopenharmony_ci if (gw_mode == BATADV_GW_MODE_OFF) { 2798c2ecf20Sopenharmony_ci do_bcast = true; 2808c2ecf20Sopenharmony_ci goto send; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci dhcp_rcp = batadv_gw_dhcp_recipient_get(skb, &header_len, 2848c2ecf20Sopenharmony_ci chaddr); 2858c2ecf20Sopenharmony_ci /* skb->data may have been modified by 2868c2ecf20Sopenharmony_ci * batadv_gw_dhcp_recipient_get() 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci ethhdr = eth_hdr(skb); 2898c2ecf20Sopenharmony_ci /* if gw_mode is on, broadcast any non-DHCP message. 2908c2ecf20Sopenharmony_ci * All the DHCP packets are going to be sent as unicast 2918c2ecf20Sopenharmony_ci */ 2928c2ecf20Sopenharmony_ci if (dhcp_rcp == BATADV_DHCP_NO) { 2938c2ecf20Sopenharmony_ci do_bcast = true; 2948c2ecf20Sopenharmony_ci goto send; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (dhcp_rcp == BATADV_DHCP_TO_CLIENT) 2988c2ecf20Sopenharmony_ci dst_hint = chaddr; 2998c2ecf20Sopenharmony_ci else if ((gw_mode == BATADV_GW_MODE_SERVER) && 3008c2ecf20Sopenharmony_ci (dhcp_rcp == BATADV_DHCP_TO_SERVER)) 3018c2ecf20Sopenharmony_ci /* gateways should not forward any DHCP message if 3028c2ecf20Sopenharmony_ci * directed to a DHCP server 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_ci goto dropped; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cisend: 3078c2ecf20Sopenharmony_ci if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) { 3088c2ecf20Sopenharmony_ci forw_mode = batadv_mcast_forw_mode(bat_priv, skb, 3098c2ecf20Sopenharmony_ci &mcast_single_orig, 3108c2ecf20Sopenharmony_ci &mcast_is_routable); 3118c2ecf20Sopenharmony_ci if (forw_mode == BATADV_FORW_NONE) 3128c2ecf20Sopenharmony_ci goto dropped; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (forw_mode == BATADV_FORW_SINGLE || 3158c2ecf20Sopenharmony_ci forw_mode == BATADV_FORW_SOME) 3168c2ecf20Sopenharmony_ci do_bcast = false; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci batadv_skb_set_priority(skb, 0); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* ethernet packet should be broadcasted */ 3238c2ecf20Sopenharmony_ci if (do_bcast) { 3248c2ecf20Sopenharmony_ci primary_if = batadv_primary_if_get_selected(bat_priv); 3258c2ecf20Sopenharmony_ci if (!primary_if) 3268c2ecf20Sopenharmony_ci goto dropped; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* in case of ARP request, we do not immediately broadcasti the 3298c2ecf20Sopenharmony_ci * packet, instead we first wait for DAT to try to retrieve the 3308c2ecf20Sopenharmony_ci * correct ARP entry 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ci if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb)) 3338c2ecf20Sopenharmony_ci brd_delay = msecs_to_jiffies(ARP_REQ_DELAY); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (batadv_skb_head_push(skb, sizeof(*bcast_packet)) < 0) 3368c2ecf20Sopenharmony_ci goto dropped; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci bcast_packet = (struct batadv_bcast_packet *)skb->data; 3398c2ecf20Sopenharmony_ci bcast_packet->version = BATADV_COMPAT_VERSION; 3408c2ecf20Sopenharmony_ci bcast_packet->ttl = BATADV_TTL; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* batman packet type: broadcast */ 3438c2ecf20Sopenharmony_ci bcast_packet->packet_type = BATADV_BCAST; 3448c2ecf20Sopenharmony_ci bcast_packet->reserved = 0; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* hw address of first interface is the orig mac because only 3478c2ecf20Sopenharmony_ci * this mac is known throughout the mesh 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ci ether_addr_copy(bcast_packet->orig, 3508c2ecf20Sopenharmony_ci primary_if->net_dev->dev_addr); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* set broadcast sequence number */ 3538c2ecf20Sopenharmony_ci seqno = atomic_inc_return(&bat_priv->bcast_seqno); 3548c2ecf20Sopenharmony_ci bcast_packet->seqno = htonl(seqno); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci batadv_add_bcast_packet_to_list(bat_priv, skb, brd_delay, true); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* a copy is stored in the bcast list, therefore removing 3598c2ecf20Sopenharmony_ci * the original skb. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci consume_skb(skb); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* unicast packet */ 3648c2ecf20Sopenharmony_ci } else { 3658c2ecf20Sopenharmony_ci /* DHCP packets going to a server will use the GW feature */ 3668c2ecf20Sopenharmony_ci if (dhcp_rcp == BATADV_DHCP_TO_SERVER) { 3678c2ecf20Sopenharmony_ci ret = batadv_gw_out_of_range(bat_priv, skb); 3688c2ecf20Sopenharmony_ci if (ret) 3698c2ecf20Sopenharmony_ci goto dropped; 3708c2ecf20Sopenharmony_ci ret = batadv_send_skb_via_gw(bat_priv, skb, vid); 3718c2ecf20Sopenharmony_ci } else if (mcast_single_orig) { 3728c2ecf20Sopenharmony_ci ret = batadv_mcast_forw_send_orig(bat_priv, skb, vid, 3738c2ecf20Sopenharmony_ci mcast_single_orig); 3748c2ecf20Sopenharmony_ci } else if (forw_mode == BATADV_FORW_SOME) { 3758c2ecf20Sopenharmony_ci ret = batadv_mcast_forw_send(bat_priv, skb, vid, 3768c2ecf20Sopenharmony_ci mcast_is_routable); 3778c2ecf20Sopenharmony_ci } else { 3788c2ecf20Sopenharmony_ci if (batadv_dat_snoop_outgoing_arp_request(bat_priv, 3798c2ecf20Sopenharmony_ci skb)) 3808c2ecf20Sopenharmony_ci goto dropped; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci ret = batadv_send_skb_via_tt(bat_priv, skb, dst_hint, 3858c2ecf20Sopenharmony_ci vid); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci if (ret != NET_XMIT_SUCCESS) 3888c2ecf20Sopenharmony_ci goto dropped_freed; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci batadv_inc_counter(bat_priv, BATADV_CNT_TX); 3928c2ecf20Sopenharmony_ci batadv_add_counter(bat_priv, BATADV_CNT_TX_BYTES, data_len); 3938c2ecf20Sopenharmony_ci goto end; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cidropped: 3968c2ecf20Sopenharmony_ci kfree_skb(skb); 3978c2ecf20Sopenharmony_cidropped_freed: 3988c2ecf20Sopenharmony_ci batadv_inc_counter(bat_priv, BATADV_CNT_TX_DROPPED); 3998c2ecf20Sopenharmony_ciend: 4008c2ecf20Sopenharmony_ci if (mcast_single_orig) 4018c2ecf20Sopenharmony_ci batadv_orig_node_put(mcast_single_orig); 4028c2ecf20Sopenharmony_ci if (primary_if) 4038c2ecf20Sopenharmony_ci batadv_hardif_put(primary_if); 4048c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci/** 4088c2ecf20Sopenharmony_ci * batadv_interface_rx() - receive ethernet frame on local batman-adv interface 4098c2ecf20Sopenharmony_ci * @soft_iface: local interface which will receive the ethernet frame 4108c2ecf20Sopenharmony_ci * @skb: ethernet frame for @soft_iface 4118c2ecf20Sopenharmony_ci * @hdr_size: size of already parsed batman-adv header 4128c2ecf20Sopenharmony_ci * @orig_node: originator from which the batman-adv packet was sent 4138c2ecf20Sopenharmony_ci * 4148c2ecf20Sopenharmony_ci * Sends an ethernet frame to the receive path of the local @soft_iface. 4158c2ecf20Sopenharmony_ci * skb->data has still point to the batman-adv header with the size @hdr_size. 4168c2ecf20Sopenharmony_ci * The caller has to have parsed this header already and made sure that at least 4178c2ecf20Sopenharmony_ci * @hdr_size bytes are still available for pull in @skb. 4188c2ecf20Sopenharmony_ci * 4198c2ecf20Sopenharmony_ci * The packet may still get dropped. This can happen when the encapsulated 4208c2ecf20Sopenharmony_ci * ethernet frame is invalid or contains again an batman-adv packet. Also 4218c2ecf20Sopenharmony_ci * unicast packets will be dropped directly when it was sent between two 4228c2ecf20Sopenharmony_ci * isolated clients. 4238c2ecf20Sopenharmony_ci */ 4248c2ecf20Sopenharmony_civoid batadv_interface_rx(struct net_device *soft_iface, 4258c2ecf20Sopenharmony_ci struct sk_buff *skb, int hdr_size, 4268c2ecf20Sopenharmony_ci struct batadv_orig_node *orig_node) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct batadv_bcast_packet *batadv_bcast_packet; 4298c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(soft_iface); 4308c2ecf20Sopenharmony_ci struct vlan_ethhdr *vhdr; 4318c2ecf20Sopenharmony_ci struct ethhdr *ethhdr; 4328c2ecf20Sopenharmony_ci unsigned short vid; 4338c2ecf20Sopenharmony_ci int packet_type; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci batadv_bcast_packet = (struct batadv_bcast_packet *)skb->data; 4368c2ecf20Sopenharmony_ci packet_type = batadv_bcast_packet->packet_type; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci skb_pull_rcsum(skb, hdr_size); 4398c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* clean the netfilter state now that the batman-adv header has been 4428c2ecf20Sopenharmony_ci * removed 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_ci nf_reset_ct(skb); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) 4478c2ecf20Sopenharmony_ci goto dropped; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci vid = batadv_get_vid(skb, 0); 4508c2ecf20Sopenharmony_ci ethhdr = eth_hdr(skb); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci switch (ntohs(ethhdr->h_proto)) { 4538c2ecf20Sopenharmony_ci case ETH_P_8021Q: 4548c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, VLAN_ETH_HLEN)) 4558c2ecf20Sopenharmony_ci goto dropped; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci vhdr = skb_vlan_eth_hdr(skb); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* drop batman-in-batman packets to prevent loops */ 4608c2ecf20Sopenharmony_ci if (vhdr->h_vlan_encapsulated_proto != htons(ETH_P_BATMAN)) 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci fallthrough; 4648c2ecf20Sopenharmony_ci case ETH_P_BATMAN: 4658c2ecf20Sopenharmony_ci goto dropped; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* skb->dev & skb->pkt_type are set here */ 4698c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, soft_iface); 4708c2ecf20Sopenharmony_ci skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci batadv_inc_counter(bat_priv, BATADV_CNT_RX); 4738c2ecf20Sopenharmony_ci batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES, 4748c2ecf20Sopenharmony_ci skb->len + ETH_HLEN); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* Let the bridge loop avoidance check the packet. If will 4778c2ecf20Sopenharmony_ci * not handle it, we can safely push it up. 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci if (batadv_bla_rx(bat_priv, skb, vid, packet_type)) 4808c2ecf20Sopenharmony_ci goto out; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (orig_node) 4838c2ecf20Sopenharmony_ci batadv_tt_add_temporary_global_entry(bat_priv, orig_node, 4848c2ecf20Sopenharmony_ci ethhdr->h_source, vid); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(ethhdr->h_dest)) { 4878c2ecf20Sopenharmony_ci /* set the mark on broadcast packets if AP isolation is ON and 4888c2ecf20Sopenharmony_ci * the packet is coming from an "isolated" client 4898c2ecf20Sopenharmony_ci */ 4908c2ecf20Sopenharmony_ci if (batadv_vlan_ap_isola_get(bat_priv, vid) && 4918c2ecf20Sopenharmony_ci batadv_tt_global_is_isolated(bat_priv, ethhdr->h_source, 4928c2ecf20Sopenharmony_ci vid)) { 4938c2ecf20Sopenharmony_ci /* save bits in skb->mark not covered by the mask and 4948c2ecf20Sopenharmony_ci * apply the mark on the rest 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_ci skb->mark &= ~bat_priv->isolation_mark_mask; 4978c2ecf20Sopenharmony_ci skb->mark |= bat_priv->isolation_mark; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci } else if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, 5008c2ecf20Sopenharmony_ci ethhdr->h_dest, vid)) { 5018c2ecf20Sopenharmony_ci goto dropped; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci netif_rx(skb); 5058c2ecf20Sopenharmony_ci goto out; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cidropped: 5088c2ecf20Sopenharmony_ci kfree_skb(skb); 5098c2ecf20Sopenharmony_ciout: 5108c2ecf20Sopenharmony_ci return; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci/** 5148c2ecf20Sopenharmony_ci * batadv_softif_vlan_release() - release vlan from lists and queue for free 5158c2ecf20Sopenharmony_ci * after rcu grace period 5168c2ecf20Sopenharmony_ci * @ref: kref pointer of the vlan object 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_civoid batadv_softif_vlan_release(struct kref *ref) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci struct batadv_softif_vlan *vlan; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci vlan = container_of(ref, struct batadv_softif_vlan, refcount); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock); 5258c2ecf20Sopenharmony_ci hlist_del_rcu(&vlan->list); 5268c2ecf20Sopenharmony_ci spin_unlock_bh(&vlan->bat_priv->softif_vlan_list_lock); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci kfree_rcu(vlan, rcu); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci/** 5328c2ecf20Sopenharmony_ci * batadv_softif_vlan_get() - get the vlan object for a specific vid 5338c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 5348c2ecf20Sopenharmony_ci * @vid: the identifier of the vlan object to retrieve 5358c2ecf20Sopenharmony_ci * 5368c2ecf20Sopenharmony_ci * Return: the private data of the vlan matching the vid passed as argument or 5378c2ecf20Sopenharmony_ci * NULL otherwise. The refcounter of the returned object is incremented by 1. 5388c2ecf20Sopenharmony_ci */ 5398c2ecf20Sopenharmony_cistruct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv, 5408c2ecf20Sopenharmony_ci unsigned short vid) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct batadv_softif_vlan *vlan_tmp, *vlan = NULL; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci rcu_read_lock(); 5458c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) { 5468c2ecf20Sopenharmony_ci if (vlan_tmp->vid != vid) 5478c2ecf20Sopenharmony_ci continue; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&vlan_tmp->refcount)) 5508c2ecf20Sopenharmony_ci continue; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci vlan = vlan_tmp; 5538c2ecf20Sopenharmony_ci break; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci rcu_read_unlock(); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return vlan; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci/** 5618c2ecf20Sopenharmony_ci * batadv_softif_create_vlan() - allocate the needed resources for a new vlan 5628c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 5638c2ecf20Sopenharmony_ci * @vid: the VLAN identifier 5648c2ecf20Sopenharmony_ci * 5658c2ecf20Sopenharmony_ci * Return: 0 on success, a negative error otherwise. 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_ciint batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci struct batadv_softif_vlan *vlan; 5708c2ecf20Sopenharmony_ci int err; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci spin_lock_bh(&bat_priv->softif_vlan_list_lock); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci vlan = batadv_softif_vlan_get(bat_priv, vid); 5758c2ecf20Sopenharmony_ci if (vlan) { 5768c2ecf20Sopenharmony_ci batadv_softif_vlan_put(vlan); 5778c2ecf20Sopenharmony_ci spin_unlock_bh(&bat_priv->softif_vlan_list_lock); 5788c2ecf20Sopenharmony_ci return -EEXIST; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC); 5828c2ecf20Sopenharmony_ci if (!vlan) { 5838c2ecf20Sopenharmony_ci spin_unlock_bh(&bat_priv->softif_vlan_list_lock); 5848c2ecf20Sopenharmony_ci return -ENOMEM; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci vlan->bat_priv = bat_priv; 5888c2ecf20Sopenharmony_ci vlan->vid = vid; 5898c2ecf20Sopenharmony_ci kref_init(&vlan->refcount); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci atomic_set(&vlan->ap_isolation, 0); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci kref_get(&vlan->refcount); 5948c2ecf20Sopenharmony_ci hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list); 5958c2ecf20Sopenharmony_ci spin_unlock_bh(&bat_priv->softif_vlan_list_lock); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* batadv_sysfs_add_vlan cannot be in the spinlock section due to the 5988c2ecf20Sopenharmony_ci * sleeping behavior of the sysfs functions and the fs_reclaim lock 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_ci err = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan); 6018c2ecf20Sopenharmony_ci if (err) { 6028c2ecf20Sopenharmony_ci /* ref for the function */ 6038c2ecf20Sopenharmony_ci batadv_softif_vlan_put(vlan); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* ref for the list */ 6068c2ecf20Sopenharmony_ci batadv_softif_vlan_put(vlan); 6078c2ecf20Sopenharmony_ci return err; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* add a new TT local entry. This one will be marked with the NOPURGE 6118c2ecf20Sopenharmony_ci * flag 6128c2ecf20Sopenharmony_ci */ 6138c2ecf20Sopenharmony_ci batadv_tt_local_add(bat_priv->soft_iface, 6148c2ecf20Sopenharmony_ci bat_priv->soft_iface->dev_addr, vid, 6158c2ecf20Sopenharmony_ci BATADV_NULL_IFINDEX, BATADV_NO_MARK); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* don't return reference to new softif_vlan */ 6188c2ecf20Sopenharmony_ci batadv_softif_vlan_put(vlan); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci return 0; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci/** 6248c2ecf20Sopenharmony_ci * batadv_softif_destroy_vlan() - remove and destroy a softif_vlan object 6258c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 6268c2ecf20Sopenharmony_ci * @vlan: the object to remove 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_cistatic void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv, 6298c2ecf20Sopenharmony_ci struct batadv_softif_vlan *vlan) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci /* explicitly remove the associated TT local entry because it is marked 6328c2ecf20Sopenharmony_ci * with the NOPURGE flag 6338c2ecf20Sopenharmony_ci */ 6348c2ecf20Sopenharmony_ci batadv_tt_local_remove(bat_priv, bat_priv->soft_iface->dev_addr, 6358c2ecf20Sopenharmony_ci vlan->vid, "vlan interface destroyed", false); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci batadv_sysfs_del_vlan(bat_priv, vlan); 6388c2ecf20Sopenharmony_ci batadv_softif_vlan_put(vlan); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci/** 6428c2ecf20Sopenharmony_ci * batadv_interface_add_vid() - ndo_add_vid API implementation 6438c2ecf20Sopenharmony_ci * @dev: the netdev of the mesh interface 6448c2ecf20Sopenharmony_ci * @proto: protocol of the vlan id 6458c2ecf20Sopenharmony_ci * @vid: identifier of the new vlan 6468c2ecf20Sopenharmony_ci * 6478c2ecf20Sopenharmony_ci * Set up all the internal structures for handling the new vlan on top of the 6488c2ecf20Sopenharmony_ci * mesh interface 6498c2ecf20Sopenharmony_ci * 6508c2ecf20Sopenharmony_ci * Return: 0 on success or a negative error code in case of failure. 6518c2ecf20Sopenharmony_ci */ 6528c2ecf20Sopenharmony_cistatic int batadv_interface_add_vid(struct net_device *dev, __be16 proto, 6538c2ecf20Sopenharmony_ci unsigned short vid) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(dev); 6568c2ecf20Sopenharmony_ci struct batadv_softif_vlan *vlan; 6578c2ecf20Sopenharmony_ci int ret; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* only 802.1Q vlans are supported. 6608c2ecf20Sopenharmony_ci * batman-adv does not know how to handle other types 6618c2ecf20Sopenharmony_ci */ 6628c2ecf20Sopenharmony_ci if (proto != htons(ETH_P_8021Q)) 6638c2ecf20Sopenharmony_ci return -EINVAL; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci vid |= BATADV_VLAN_HAS_TAG; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci /* if a new vlan is getting created and it already exists, it means that 6688c2ecf20Sopenharmony_ci * it was not deleted yet. batadv_softif_vlan_get() increases the 6698c2ecf20Sopenharmony_ci * refcount in order to revive the object. 6708c2ecf20Sopenharmony_ci * 6718c2ecf20Sopenharmony_ci * if it does not exist then create it. 6728c2ecf20Sopenharmony_ci */ 6738c2ecf20Sopenharmony_ci vlan = batadv_softif_vlan_get(bat_priv, vid); 6748c2ecf20Sopenharmony_ci if (!vlan) 6758c2ecf20Sopenharmony_ci return batadv_softif_create_vlan(bat_priv, vid); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* recreate the sysfs object if it was already destroyed (and it should 6788c2ecf20Sopenharmony_ci * be since we received a kill_vid() for this vlan 6798c2ecf20Sopenharmony_ci */ 6808c2ecf20Sopenharmony_ci if (!vlan->kobj) { 6818c2ecf20Sopenharmony_ci ret = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan); 6828c2ecf20Sopenharmony_ci if (ret) { 6838c2ecf20Sopenharmony_ci batadv_softif_vlan_put(vlan); 6848c2ecf20Sopenharmony_ci return ret; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* add a new TT local entry. This one will be marked with the NOPURGE 6898c2ecf20Sopenharmony_ci * flag. This must be added again, even if the vlan object already 6908c2ecf20Sopenharmony_ci * exists, because the entry was deleted by kill_vid() 6918c2ecf20Sopenharmony_ci */ 6928c2ecf20Sopenharmony_ci batadv_tt_local_add(bat_priv->soft_iface, 6938c2ecf20Sopenharmony_ci bat_priv->soft_iface->dev_addr, vid, 6948c2ecf20Sopenharmony_ci BATADV_NULL_IFINDEX, BATADV_NO_MARK); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci return 0; 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci/** 7008c2ecf20Sopenharmony_ci * batadv_interface_kill_vid() - ndo_kill_vid API implementation 7018c2ecf20Sopenharmony_ci * @dev: the netdev of the mesh interface 7028c2ecf20Sopenharmony_ci * @proto: protocol of the vlan id 7038c2ecf20Sopenharmony_ci * @vid: identifier of the deleted vlan 7048c2ecf20Sopenharmony_ci * 7058c2ecf20Sopenharmony_ci * Destroy all the internal structures used to handle the vlan identified by vid 7068c2ecf20Sopenharmony_ci * on top of the mesh interface 7078c2ecf20Sopenharmony_ci * 7088c2ecf20Sopenharmony_ci * Return: 0 on success, -EINVAL if the specified prototype is not ETH_P_8021Q 7098c2ecf20Sopenharmony_ci * or -ENOENT if the specified vlan id wasn't registered. 7108c2ecf20Sopenharmony_ci */ 7118c2ecf20Sopenharmony_cistatic int batadv_interface_kill_vid(struct net_device *dev, __be16 proto, 7128c2ecf20Sopenharmony_ci unsigned short vid) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(dev); 7158c2ecf20Sopenharmony_ci struct batadv_softif_vlan *vlan; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* only 802.1Q vlans are supported. batman-adv does not know how to 7188c2ecf20Sopenharmony_ci * handle other types 7198c2ecf20Sopenharmony_ci */ 7208c2ecf20Sopenharmony_ci if (proto != htons(ETH_P_8021Q)) 7218c2ecf20Sopenharmony_ci return -EINVAL; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci vlan = batadv_softif_vlan_get(bat_priv, vid | BATADV_VLAN_HAS_TAG); 7248c2ecf20Sopenharmony_ci if (!vlan) 7258c2ecf20Sopenharmony_ci return -ENOENT; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci batadv_softif_destroy_vlan(bat_priv, vlan); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci /* finally free the vlan object */ 7308c2ecf20Sopenharmony_ci batadv_softif_vlan_put(vlan); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci return 0; 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci/* batman-adv network devices have devices nesting below it and are a special 7368c2ecf20Sopenharmony_ci * "super class" of normal network devices; split their locks off into a 7378c2ecf20Sopenharmony_ci * separate class since they always nest. 7388c2ecf20Sopenharmony_ci */ 7398c2ecf20Sopenharmony_cistatic struct lock_class_key batadv_netdev_xmit_lock_key; 7408c2ecf20Sopenharmony_cistatic struct lock_class_key batadv_netdev_addr_lock_key; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci/** 7438c2ecf20Sopenharmony_ci * batadv_set_lockdep_class_one() - Set lockdep class for a single tx queue 7448c2ecf20Sopenharmony_ci * @dev: device which owns the tx queue 7458c2ecf20Sopenharmony_ci * @txq: tx queue to modify 7468c2ecf20Sopenharmony_ci * @_unused: always NULL 7478c2ecf20Sopenharmony_ci */ 7488c2ecf20Sopenharmony_cistatic void batadv_set_lockdep_class_one(struct net_device *dev, 7498c2ecf20Sopenharmony_ci struct netdev_queue *txq, 7508c2ecf20Sopenharmony_ci void *_unused) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci lockdep_set_class(&txq->_xmit_lock, &batadv_netdev_xmit_lock_key); 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci/** 7568c2ecf20Sopenharmony_ci * batadv_set_lockdep_class() - Set txq and addr_list lockdep class 7578c2ecf20Sopenharmony_ci * @dev: network device to modify 7588c2ecf20Sopenharmony_ci */ 7598c2ecf20Sopenharmony_cistatic void batadv_set_lockdep_class(struct net_device *dev) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci lockdep_set_class(&dev->addr_list_lock, &batadv_netdev_addr_lock_key); 7628c2ecf20Sopenharmony_ci netdev_for_each_tx_queue(dev, batadv_set_lockdep_class_one, NULL); 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci/** 7668c2ecf20Sopenharmony_ci * batadv_softif_init_late() - late stage initialization of soft interface 7678c2ecf20Sopenharmony_ci * @dev: registered network device to modify 7688c2ecf20Sopenharmony_ci * 7698c2ecf20Sopenharmony_ci * Return: error code on failures 7708c2ecf20Sopenharmony_ci */ 7718c2ecf20Sopenharmony_cistatic int batadv_softif_init_late(struct net_device *dev) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv; 7748c2ecf20Sopenharmony_ci u32 random_seqno; 7758c2ecf20Sopenharmony_ci int ret; 7768c2ecf20Sopenharmony_ci size_t cnt_len = sizeof(u64) * BATADV_CNT_NUM; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci batadv_set_lockdep_class(dev); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci bat_priv = netdev_priv(dev); 7818c2ecf20Sopenharmony_ci bat_priv->soft_iface = dev; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci /* batadv_interface_stats() needs to be available as soon as 7848c2ecf20Sopenharmony_ci * register_netdevice() has been called 7858c2ecf20Sopenharmony_ci */ 7868c2ecf20Sopenharmony_ci bat_priv->bat_counters = __alloc_percpu(cnt_len, __alignof__(u64)); 7878c2ecf20Sopenharmony_ci if (!bat_priv->bat_counters) 7888c2ecf20Sopenharmony_ci return -ENOMEM; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci atomic_set(&bat_priv->aggregated_ogms, 1); 7918c2ecf20Sopenharmony_ci atomic_set(&bat_priv->bonding, 0); 7928c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_BLA 7938c2ecf20Sopenharmony_ci atomic_set(&bat_priv->bridge_loop_avoidance, 1); 7948c2ecf20Sopenharmony_ci#endif 7958c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DAT 7968c2ecf20Sopenharmony_ci atomic_set(&bat_priv->distributed_arp_table, 1); 7978c2ecf20Sopenharmony_ci#endif 7988c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_MCAST 7998c2ecf20Sopenharmony_ci atomic_set(&bat_priv->multicast_mode, 1); 8008c2ecf20Sopenharmony_ci atomic_set(&bat_priv->multicast_fanout, 16); 8018c2ecf20Sopenharmony_ci atomic_set(&bat_priv->mcast.num_want_all_unsnoopables, 0); 8028c2ecf20Sopenharmony_ci atomic_set(&bat_priv->mcast.num_want_all_ipv4, 0); 8038c2ecf20Sopenharmony_ci atomic_set(&bat_priv->mcast.num_want_all_ipv6, 0); 8048c2ecf20Sopenharmony_ci#endif 8058c2ecf20Sopenharmony_ci atomic_set(&bat_priv->gw.mode, BATADV_GW_MODE_OFF); 8068c2ecf20Sopenharmony_ci atomic_set(&bat_priv->gw.bandwidth_down, 100); 8078c2ecf20Sopenharmony_ci atomic_set(&bat_priv->gw.bandwidth_up, 20); 8088c2ecf20Sopenharmony_ci atomic_set(&bat_priv->orig_interval, 1000); 8098c2ecf20Sopenharmony_ci atomic_set(&bat_priv->hop_penalty, 30); 8108c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUG 8118c2ecf20Sopenharmony_ci atomic_set(&bat_priv->log_level, 0); 8128c2ecf20Sopenharmony_ci#endif 8138c2ecf20Sopenharmony_ci atomic_set(&bat_priv->fragmentation, 1); 8148c2ecf20Sopenharmony_ci atomic_set(&bat_priv->packet_size_max, ETH_DATA_LEN); 8158c2ecf20Sopenharmony_ci atomic_set(&bat_priv->bcast_queue_left, BATADV_BCAST_QUEUE_LEN); 8168c2ecf20Sopenharmony_ci atomic_set(&bat_priv->batman_queue_left, BATADV_BATMAN_QUEUE_LEN); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE); 8198c2ecf20Sopenharmony_ci atomic_set(&bat_priv->bcast_seqno, 1); 8208c2ecf20Sopenharmony_ci atomic_set(&bat_priv->tt.vn, 0); 8218c2ecf20Sopenharmony_ci atomic_set(&bat_priv->tt.local_changes, 0); 8228c2ecf20Sopenharmony_ci atomic_set(&bat_priv->tt.ogm_append_cnt, 0); 8238c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_BLA 8248c2ecf20Sopenharmony_ci atomic_set(&bat_priv->bla.num_requests, 0); 8258c2ecf20Sopenharmony_ci#endif 8268c2ecf20Sopenharmony_ci atomic_set(&bat_priv->tp_num, 0); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci bat_priv->tt.last_changeset = NULL; 8298c2ecf20Sopenharmony_ci bat_priv->tt.last_changeset_len = 0; 8308c2ecf20Sopenharmony_ci bat_priv->isolation_mark = 0; 8318c2ecf20Sopenharmony_ci bat_priv->isolation_mark_mask = 0; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* randomize initial seqno to avoid collision */ 8348c2ecf20Sopenharmony_ci get_random_bytes(&random_seqno, sizeof(random_seqno)); 8358c2ecf20Sopenharmony_ci atomic_set(&bat_priv->frag_seqno, random_seqno); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci bat_priv->primary_if = NULL; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci batadv_nc_init_bat_priv(bat_priv); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci ret = batadv_algo_select(bat_priv, batadv_routing_algo); 8428c2ecf20Sopenharmony_ci if (ret < 0) 8438c2ecf20Sopenharmony_ci goto free_bat_counters; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci ret = batadv_debugfs_add_meshif(dev); 8468c2ecf20Sopenharmony_ci if (ret < 0) 8478c2ecf20Sopenharmony_ci goto free_bat_counters; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci ret = batadv_mesh_init(dev); 8508c2ecf20Sopenharmony_ci if (ret < 0) 8518c2ecf20Sopenharmony_ci goto unreg_debugfs; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci return 0; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ciunreg_debugfs: 8568c2ecf20Sopenharmony_ci batadv_debugfs_del_meshif(dev); 8578c2ecf20Sopenharmony_cifree_bat_counters: 8588c2ecf20Sopenharmony_ci free_percpu(bat_priv->bat_counters); 8598c2ecf20Sopenharmony_ci bat_priv->bat_counters = NULL; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci return ret; 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci/** 8658c2ecf20Sopenharmony_ci * batadv_softif_slave_add() - Add a slave interface to a batadv_soft_interface 8668c2ecf20Sopenharmony_ci * @dev: batadv_soft_interface used as master interface 8678c2ecf20Sopenharmony_ci * @slave_dev: net_device which should become the slave interface 8688c2ecf20Sopenharmony_ci * @extack: extended ACK report struct 8698c2ecf20Sopenharmony_ci * 8708c2ecf20Sopenharmony_ci * Return: 0 if successful or error otherwise. 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_cistatic int batadv_softif_slave_add(struct net_device *dev, 8738c2ecf20Sopenharmony_ci struct net_device *slave_dev, 8748c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface; 8778c2ecf20Sopenharmony_ci struct net *net = dev_net(dev); 8788c2ecf20Sopenharmony_ci int ret = -EINVAL; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci hard_iface = batadv_hardif_get_by_netdev(slave_dev); 8818c2ecf20Sopenharmony_ci if (!hard_iface || hard_iface->soft_iface) 8828c2ecf20Sopenharmony_ci goto out; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci ret = batadv_hardif_enable_interface(hard_iface, net, dev->name); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ciout: 8878c2ecf20Sopenharmony_ci if (hard_iface) 8888c2ecf20Sopenharmony_ci batadv_hardif_put(hard_iface); 8898c2ecf20Sopenharmony_ci return ret; 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci/** 8938c2ecf20Sopenharmony_ci * batadv_softif_slave_del() - Delete a slave iface from a batadv_soft_interface 8948c2ecf20Sopenharmony_ci * @dev: batadv_soft_interface used as master interface 8958c2ecf20Sopenharmony_ci * @slave_dev: net_device which should be removed from the master interface 8968c2ecf20Sopenharmony_ci * 8978c2ecf20Sopenharmony_ci * Return: 0 if successful or error otherwise. 8988c2ecf20Sopenharmony_ci */ 8998c2ecf20Sopenharmony_cistatic int batadv_softif_slave_del(struct net_device *dev, 9008c2ecf20Sopenharmony_ci struct net_device *slave_dev) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface; 9038c2ecf20Sopenharmony_ci int ret = -EINVAL; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci hard_iface = batadv_hardif_get_by_netdev(slave_dev); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci if (!hard_iface || hard_iface->soft_iface != dev) 9088c2ecf20Sopenharmony_ci goto out; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci batadv_hardif_disable_interface(hard_iface, BATADV_IF_CLEANUP_KEEP); 9118c2ecf20Sopenharmony_ci ret = 0; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ciout: 9148c2ecf20Sopenharmony_ci if (hard_iface) 9158c2ecf20Sopenharmony_ci batadv_hardif_put(hard_iface); 9168c2ecf20Sopenharmony_ci return ret; 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_cistatic const struct net_device_ops batadv_netdev_ops = { 9208c2ecf20Sopenharmony_ci .ndo_init = batadv_softif_init_late, 9218c2ecf20Sopenharmony_ci .ndo_open = batadv_interface_open, 9228c2ecf20Sopenharmony_ci .ndo_stop = batadv_interface_release, 9238c2ecf20Sopenharmony_ci .ndo_get_stats = batadv_interface_stats, 9248c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = batadv_interface_add_vid, 9258c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = batadv_interface_kill_vid, 9268c2ecf20Sopenharmony_ci .ndo_set_mac_address = batadv_interface_set_mac_addr, 9278c2ecf20Sopenharmony_ci .ndo_change_mtu = batadv_interface_change_mtu, 9288c2ecf20Sopenharmony_ci .ndo_set_rx_mode = batadv_interface_set_rx_mode, 9298c2ecf20Sopenharmony_ci .ndo_start_xmit = batadv_interface_tx, 9308c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 9318c2ecf20Sopenharmony_ci .ndo_add_slave = batadv_softif_slave_add, 9328c2ecf20Sopenharmony_ci .ndo_del_slave = batadv_softif_slave_del, 9338c2ecf20Sopenharmony_ci}; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic void batadv_get_drvinfo(struct net_device *dev, 9368c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 9378c2ecf20Sopenharmony_ci{ 9388c2ecf20Sopenharmony_ci strscpy(info->driver, "B.A.T.M.A.N. advanced", sizeof(info->driver)); 9398c2ecf20Sopenharmony_ci strscpy(info->version, BATADV_SOURCE_VERSION, sizeof(info->version)); 9408c2ecf20Sopenharmony_ci strscpy(info->fw_version, "N/A", sizeof(info->fw_version)); 9418c2ecf20Sopenharmony_ci strscpy(info->bus_info, "batman", sizeof(info->bus_info)); 9428c2ecf20Sopenharmony_ci} 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci/* Inspired by drivers/net/ethernet/dlink/sundance.c:1702 9458c2ecf20Sopenharmony_ci * Declare each description string in struct.name[] to get fixed sized buffer 9468c2ecf20Sopenharmony_ci * and compile time checking for strings longer than ETH_GSTRING_LEN. 9478c2ecf20Sopenharmony_ci */ 9488c2ecf20Sopenharmony_cistatic const struct { 9498c2ecf20Sopenharmony_ci const char name[ETH_GSTRING_LEN]; 9508c2ecf20Sopenharmony_ci} batadv_counters_strings[] = { 9518c2ecf20Sopenharmony_ci { "tx" }, 9528c2ecf20Sopenharmony_ci { "tx_bytes" }, 9538c2ecf20Sopenharmony_ci { "tx_dropped" }, 9548c2ecf20Sopenharmony_ci { "rx" }, 9558c2ecf20Sopenharmony_ci { "rx_bytes" }, 9568c2ecf20Sopenharmony_ci { "forward" }, 9578c2ecf20Sopenharmony_ci { "forward_bytes" }, 9588c2ecf20Sopenharmony_ci { "mgmt_tx" }, 9598c2ecf20Sopenharmony_ci { "mgmt_tx_bytes" }, 9608c2ecf20Sopenharmony_ci { "mgmt_rx" }, 9618c2ecf20Sopenharmony_ci { "mgmt_rx_bytes" }, 9628c2ecf20Sopenharmony_ci { "frag_tx" }, 9638c2ecf20Sopenharmony_ci { "frag_tx_bytes" }, 9648c2ecf20Sopenharmony_ci { "frag_rx" }, 9658c2ecf20Sopenharmony_ci { "frag_rx_bytes" }, 9668c2ecf20Sopenharmony_ci { "frag_fwd" }, 9678c2ecf20Sopenharmony_ci { "frag_fwd_bytes" }, 9688c2ecf20Sopenharmony_ci { "tt_request_tx" }, 9698c2ecf20Sopenharmony_ci { "tt_request_rx" }, 9708c2ecf20Sopenharmony_ci { "tt_response_tx" }, 9718c2ecf20Sopenharmony_ci { "tt_response_rx" }, 9728c2ecf20Sopenharmony_ci { "tt_roam_adv_tx" }, 9738c2ecf20Sopenharmony_ci { "tt_roam_adv_rx" }, 9748c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DAT 9758c2ecf20Sopenharmony_ci { "dat_get_tx" }, 9768c2ecf20Sopenharmony_ci { "dat_get_rx" }, 9778c2ecf20Sopenharmony_ci { "dat_put_tx" }, 9788c2ecf20Sopenharmony_ci { "dat_put_rx" }, 9798c2ecf20Sopenharmony_ci { "dat_cached_reply_tx" }, 9808c2ecf20Sopenharmony_ci#endif 9818c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_NC 9828c2ecf20Sopenharmony_ci { "nc_code" }, 9838c2ecf20Sopenharmony_ci { "nc_code_bytes" }, 9848c2ecf20Sopenharmony_ci { "nc_recode" }, 9858c2ecf20Sopenharmony_ci { "nc_recode_bytes" }, 9868c2ecf20Sopenharmony_ci { "nc_buffer" }, 9878c2ecf20Sopenharmony_ci { "nc_decode" }, 9888c2ecf20Sopenharmony_ci { "nc_decode_bytes" }, 9898c2ecf20Sopenharmony_ci { "nc_decode_failed" }, 9908c2ecf20Sopenharmony_ci { "nc_sniffed" }, 9918c2ecf20Sopenharmony_ci#endif 9928c2ecf20Sopenharmony_ci}; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_cistatic void batadv_get_strings(struct net_device *dev, u32 stringset, u8 *data) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci if (stringset == ETH_SS_STATS) 9978c2ecf20Sopenharmony_ci memcpy(data, batadv_counters_strings, 9988c2ecf20Sopenharmony_ci sizeof(batadv_counters_strings)); 9998c2ecf20Sopenharmony_ci} 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_cistatic void batadv_get_ethtool_stats(struct net_device *dev, 10028c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(dev); 10058c2ecf20Sopenharmony_ci int i; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci for (i = 0; i < BATADV_CNT_NUM; i++) 10088c2ecf20Sopenharmony_ci data[i] = batadv_sum_counter(bat_priv, i); 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic int batadv_get_sset_count(struct net_device *dev, int stringset) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci if (stringset == ETH_SS_STATS) 10148c2ecf20Sopenharmony_ci return BATADV_CNT_NUM; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_cistatic const struct ethtool_ops batadv_ethtool_ops = { 10208c2ecf20Sopenharmony_ci .get_drvinfo = batadv_get_drvinfo, 10218c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 10228c2ecf20Sopenharmony_ci .get_strings = batadv_get_strings, 10238c2ecf20Sopenharmony_ci .get_ethtool_stats = batadv_get_ethtool_stats, 10248c2ecf20Sopenharmony_ci .get_sset_count = batadv_get_sset_count, 10258c2ecf20Sopenharmony_ci}; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci/** 10288c2ecf20Sopenharmony_ci * batadv_softif_free() - Deconstructor of batadv_soft_interface 10298c2ecf20Sopenharmony_ci * @dev: Device to cleanup and remove 10308c2ecf20Sopenharmony_ci */ 10318c2ecf20Sopenharmony_cistatic void batadv_softif_free(struct net_device *dev) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci batadv_debugfs_del_meshif(dev); 10348c2ecf20Sopenharmony_ci batadv_mesh_free(dev); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci /* some scheduled RCU callbacks need the bat_priv struct to accomplish 10378c2ecf20Sopenharmony_ci * their tasks. Wait for them all to be finished before freeing the 10388c2ecf20Sopenharmony_ci * netdev and its private data (bat_priv) 10398c2ecf20Sopenharmony_ci */ 10408c2ecf20Sopenharmony_ci rcu_barrier(); 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci/** 10448c2ecf20Sopenharmony_ci * batadv_softif_init_early() - early stage initialization of soft interface 10458c2ecf20Sopenharmony_ci * @dev: registered network device to modify 10468c2ecf20Sopenharmony_ci */ 10478c2ecf20Sopenharmony_cistatic void batadv_softif_init_early(struct net_device *dev) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci ether_setup(dev); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci dev->netdev_ops = &batadv_netdev_ops; 10528c2ecf20Sopenharmony_ci dev->needs_free_netdev = true; 10538c2ecf20Sopenharmony_ci dev->priv_destructor = batadv_softif_free; 10548c2ecf20Sopenharmony_ci dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_NETNS_LOCAL; 10558c2ecf20Sopenharmony_ci dev->features |= NETIF_F_LLTX; 10568c2ecf20Sopenharmony_ci dev->priv_flags |= IFF_NO_QUEUE; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci /* can't call min_mtu, because the needed variables 10598c2ecf20Sopenharmony_ci * have not been initialized yet 10608c2ecf20Sopenharmony_ci */ 10618c2ecf20Sopenharmony_ci dev->mtu = ETH_DATA_LEN; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci /* generate random address */ 10648c2ecf20Sopenharmony_ci eth_hw_addr_random(dev); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci dev->ethtool_ops = &batadv_ethtool_ops; 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci/** 10708c2ecf20Sopenharmony_ci * batadv_softif_create() - Create and register soft interface 10718c2ecf20Sopenharmony_ci * @net: the applicable net namespace 10728c2ecf20Sopenharmony_ci * @name: name of the new soft interface 10738c2ecf20Sopenharmony_ci * 10748c2ecf20Sopenharmony_ci * Return: newly allocated soft_interface, NULL on errors 10758c2ecf20Sopenharmony_ci */ 10768c2ecf20Sopenharmony_cistruct net_device *batadv_softif_create(struct net *net, const char *name) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci struct net_device *soft_iface; 10798c2ecf20Sopenharmony_ci int ret; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci soft_iface = alloc_netdev(sizeof(struct batadv_priv), name, 10828c2ecf20Sopenharmony_ci NET_NAME_UNKNOWN, batadv_softif_init_early); 10838c2ecf20Sopenharmony_ci if (!soft_iface) 10848c2ecf20Sopenharmony_ci return NULL; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci dev_net_set(soft_iface, net); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci soft_iface->rtnl_link_ops = &batadv_link_ops; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci ret = register_netdevice(soft_iface); 10918c2ecf20Sopenharmony_ci if (ret < 0) { 10928c2ecf20Sopenharmony_ci pr_err("Unable to register the batman interface '%s': %i\n", 10938c2ecf20Sopenharmony_ci name, ret); 10948c2ecf20Sopenharmony_ci free_netdev(soft_iface); 10958c2ecf20Sopenharmony_ci return NULL; 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci return soft_iface; 10998c2ecf20Sopenharmony_ci} 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci/** 11028c2ecf20Sopenharmony_ci * batadv_softif_destroy_sysfs() - deletion of batadv_soft_interface via sysfs 11038c2ecf20Sopenharmony_ci * @soft_iface: the to-be-removed batman-adv interface 11048c2ecf20Sopenharmony_ci */ 11058c2ecf20Sopenharmony_civoid batadv_softif_destroy_sysfs(struct net_device *soft_iface) 11068c2ecf20Sopenharmony_ci{ 11078c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(soft_iface); 11088c2ecf20Sopenharmony_ci struct batadv_softif_vlan *vlan; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci ASSERT_RTNL(); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci /* destroy the "untagged" VLAN */ 11138c2ecf20Sopenharmony_ci vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS); 11148c2ecf20Sopenharmony_ci if (vlan) { 11158c2ecf20Sopenharmony_ci batadv_softif_destroy_vlan(bat_priv, vlan); 11168c2ecf20Sopenharmony_ci batadv_softif_vlan_put(vlan); 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci batadv_sysfs_del_meshif(soft_iface); 11208c2ecf20Sopenharmony_ci unregister_netdevice(soft_iface); 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci/** 11248c2ecf20Sopenharmony_ci * batadv_softif_destroy_netlink() - deletion of batadv_soft_interface via 11258c2ecf20Sopenharmony_ci * netlink 11268c2ecf20Sopenharmony_ci * @soft_iface: the to-be-removed batman-adv interface 11278c2ecf20Sopenharmony_ci * @head: list pointer 11288c2ecf20Sopenharmony_ci */ 11298c2ecf20Sopenharmony_cistatic void batadv_softif_destroy_netlink(struct net_device *soft_iface, 11308c2ecf20Sopenharmony_ci struct list_head *head) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = netdev_priv(soft_iface); 11338c2ecf20Sopenharmony_ci struct batadv_hard_iface *hard_iface; 11348c2ecf20Sopenharmony_ci struct batadv_softif_vlan *vlan; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci list_for_each_entry(hard_iface, &batadv_hardif_list, list) { 11378c2ecf20Sopenharmony_ci if (hard_iface->soft_iface == soft_iface) 11388c2ecf20Sopenharmony_ci batadv_hardif_disable_interface(hard_iface, 11398c2ecf20Sopenharmony_ci BATADV_IF_CLEANUP_KEEP); 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* destroy the "untagged" VLAN */ 11438c2ecf20Sopenharmony_ci vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS); 11448c2ecf20Sopenharmony_ci if (vlan) { 11458c2ecf20Sopenharmony_ci batadv_softif_destroy_vlan(bat_priv, vlan); 11468c2ecf20Sopenharmony_ci batadv_softif_vlan_put(vlan); 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci batadv_sysfs_del_meshif(soft_iface); 11508c2ecf20Sopenharmony_ci unregister_netdevice_queue(soft_iface, head); 11518c2ecf20Sopenharmony_ci} 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci/** 11548c2ecf20Sopenharmony_ci * batadv_softif_is_valid() - Check whether device is a batadv soft interface 11558c2ecf20Sopenharmony_ci * @net_dev: device which should be checked 11568c2ecf20Sopenharmony_ci * 11578c2ecf20Sopenharmony_ci * Return: true when net_dev is a batman-adv interface, false otherwise 11588c2ecf20Sopenharmony_ci */ 11598c2ecf20Sopenharmony_cibool batadv_softif_is_valid(const struct net_device *net_dev) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci if (net_dev->netdev_ops->ndo_start_xmit == batadv_interface_tx) 11628c2ecf20Sopenharmony_ci return true; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci return false; 11658c2ecf20Sopenharmony_ci} 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_cistruct rtnl_link_ops batadv_link_ops __read_mostly = { 11688c2ecf20Sopenharmony_ci .kind = "batadv", 11698c2ecf20Sopenharmony_ci .priv_size = sizeof(struct batadv_priv), 11708c2ecf20Sopenharmony_ci .setup = batadv_softif_init_early, 11718c2ecf20Sopenharmony_ci .dellink = batadv_softif_destroy_netlink, 11728c2ecf20Sopenharmony_ci}; 1173