xref: /openbmc/linux/net/batman-adv/soft-interface.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
17db7d9f3SSven Eckelmann // SPDX-License-Identifier: GPL-2.0
2cfa55c6dSSven Eckelmann /* Copyright (C) B.A.T.M.A.N. contributors:
3c6c8fea2SSven Eckelmann  *
4c6c8fea2SSven Eckelmann  * Marek Lindner, Simon Wunderlich
5c6c8fea2SSven Eckelmann  */
6c6c8fea2SSven Eckelmann 
7c6c8fea2SSven Eckelmann #include "soft-interface.h"
81e2c2a4fSSven Eckelmann #include "main.h"
91e2c2a4fSSven Eckelmann 
101e2c2a4fSSven Eckelmann #include <linux/atomic.h>
111e2c2a4fSSven Eckelmann #include <linux/byteorder/generic.h>
121e2c2a4fSSven Eckelmann #include <linux/cache.h>
131e2c2a4fSSven Eckelmann #include <linux/compiler.h>
14eb7da4f1SSven Eckelmann #include <linux/container_of.h>
15c408c1b9SSven Eckelmann #include <linux/cpumask.h>
161e2c2a4fSSven Eckelmann #include <linux/errno.h>
17c6c8fea2SSven Eckelmann #include <linux/etherdevice.h>
181e2c2a4fSSven Eckelmann #include <linux/ethtool.h>
19b92b94acSSven Eckelmann #include <linux/gfp.h>
201e2c2a4fSSven Eckelmann #include <linux/if_ether.h>
21c6c8fea2SSven Eckelmann #include <linux/if_vlan.h>
221e2c2a4fSSven Eckelmann #include <linux/jiffies.h>
236be4d30cSSven Eckelmann #include <linux/kref.h>
241e2c2a4fSSven Eckelmann #include <linux/list.h>
252092c910SSven Eckelmann #include <linux/lockdep.h>
261e2c2a4fSSven Eckelmann #include <linux/netdevice.h>
2768a600deSSven Eckelmann #include <linux/netlink.h>
281e2c2a4fSSven Eckelmann #include <linux/percpu.h>
291e2c2a4fSSven Eckelmann #include <linux/random.h>
301e2c2a4fSSven Eckelmann #include <linux/rculist.h>
311e2c2a4fSSven Eckelmann #include <linux/rcupdate.h>
321e2c2a4fSSven Eckelmann #include <linux/skbuff.h>
331e2c2a4fSSven Eckelmann #include <linux/slab.h>
341e2c2a4fSSven Eckelmann #include <linux/socket.h>
351e2c2a4fSSven Eckelmann #include <linux/spinlock.h>
361e2c2a4fSSven Eckelmann #include <linux/stddef.h>
371e2c2a4fSSven Eckelmann #include <linux/string.h>
381e2c2a4fSSven Eckelmann #include <linux/types.h>
39bf6b260bSSven Eckelmann #include <net/net_namespace.h>
40128254ceSSven Eckelmann #include <net/netlink.h>
41fec149f5SSven Eckelmann #include <uapi/linux/batadv_packet.h>
42e2d0d35bSSven Eckelmann #include <uapi/linux/batman_adv.h>
431e2c2a4fSSven Eckelmann 
4401d350d1SSven Eckelmann #include "bat_algo.h"
4523721387SSimon Wunderlich #include "bridge_loop_avoidance.h"
461e2c2a4fSSven Eckelmann #include "distributed-arp-table.h"
471e2c2a4fSSven Eckelmann #include "gateway_client.h"
481e2c2a4fSSven Eckelmann #include "hard-interface.h"
491e2c2a4fSSven Eckelmann #include "multicast.h"
50d353d8d4SMartin Hundebøll #include "network-coding.h"
511e2c2a4fSSven Eckelmann #include "send.h"
521e2c2a4fSSven Eckelmann #include "translation-table.h"
53c6c8fea2SSven Eckelmann 
54ff15c27cSSven Eckelmann /**
55ff15c27cSSven Eckelmann  * batadv_skb_head_push() - Increase header size and move (push) head pointer
56ff15c27cSSven Eckelmann  * @skb: packet buffer which should be modified
57ff15c27cSSven Eckelmann  * @len: number of bytes to add
58ff15c27cSSven Eckelmann  *
59ff15c27cSSven Eckelmann  * Return: 0 on success or negative error number in case of failure
60ff15c27cSSven Eckelmann  */
batadv_skb_head_push(struct sk_buff * skb,unsigned int len)6104b482a2SSven Eckelmann int batadv_skb_head_push(struct sk_buff *skb, unsigned int len)
62c6c8fea2SSven Eckelmann {
63c6c8fea2SSven Eckelmann 	int result;
64c6c8fea2SSven Eckelmann 
659cfc7bd6SSven Eckelmann 	/* TODO: We must check if we can release all references to non-payload
6648915aedSSven Eckelmann 	 * data using __skb_header_release in our skbs to allow skb_cow_header
6748915aedSSven Eckelmann 	 * to work optimally. This means that those skbs are not allowed to read
68c6c8fea2SSven Eckelmann 	 * or write any data which is before the current position of skb->data
69c6c8fea2SSven Eckelmann 	 * after that call and thus allow other skbs with the same data buffer
70c6c8fea2SSven Eckelmann 	 * to write freely in that area.
71c6c8fea2SSven Eckelmann 	 */
72c6c8fea2SSven Eckelmann 	result = skb_cow_head(skb, len);
73c6c8fea2SSven Eckelmann 	if (result < 0)
74c6c8fea2SSven Eckelmann 		return result;
75c6c8fea2SSven Eckelmann 
76c6c8fea2SSven Eckelmann 	skb_push(skb, len);
77c6c8fea2SSven Eckelmann 	return 0;
78c6c8fea2SSven Eckelmann }
79c6c8fea2SSven Eckelmann 
batadv_interface_open(struct net_device * dev)800294ca0dSSven Eckelmann static int batadv_interface_open(struct net_device *dev)
81c6c8fea2SSven Eckelmann {
82c6c8fea2SSven Eckelmann 	netif_start_queue(dev);
83c6c8fea2SSven Eckelmann 	return 0;
84c6c8fea2SSven Eckelmann }
85c6c8fea2SSven Eckelmann 
batadv_interface_release(struct net_device * dev)860294ca0dSSven Eckelmann static int batadv_interface_release(struct net_device *dev)
87c6c8fea2SSven Eckelmann {
88c6c8fea2SSven Eckelmann 	netif_stop_queue(dev);
89c6c8fea2SSven Eckelmann 	return 0;
90c6c8fea2SSven Eckelmann }
91c6c8fea2SSven Eckelmann 
92c408c1b9SSven Eckelmann /**
937e9a8c2cSSven Eckelmann  * batadv_sum_counter() - Sum the cpu-local counters for index 'idx'
94c408c1b9SSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
95c408c1b9SSven Eckelmann  * @idx: index of counter to sum up
96c408c1b9SSven Eckelmann  *
97c408c1b9SSven Eckelmann  * Return: sum of all cpu-local counters
98c408c1b9SSven Eckelmann  */
batadv_sum_counter(struct batadv_priv * bat_priv,size_t idx)99c408c1b9SSven Eckelmann static u64 batadv_sum_counter(struct batadv_priv *bat_priv,  size_t idx)
100c408c1b9SSven Eckelmann {
101c408c1b9SSven Eckelmann 	u64 *counters, sum = 0;
102c408c1b9SSven Eckelmann 	int cpu;
103c408c1b9SSven Eckelmann 
104c408c1b9SSven Eckelmann 	for_each_possible_cpu(cpu) {
105c408c1b9SSven Eckelmann 		counters = per_cpu_ptr(bat_priv->bat_counters, cpu);
106c408c1b9SSven Eckelmann 		sum += counters[idx];
107c408c1b9SSven Eckelmann 	}
108c408c1b9SSven Eckelmann 
109c408c1b9SSven Eckelmann 	return sum;
110c408c1b9SSven Eckelmann }
111c408c1b9SSven Eckelmann 
batadv_interface_stats(struct net_device * dev)1120294ca0dSSven Eckelmann static struct net_device_stats *batadv_interface_stats(struct net_device *dev)
113c6c8fea2SSven Eckelmann {
11456303d34SSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(dev);
115ab044f8eSTobias Klauser 	struct net_device_stats *stats = &dev->stats;
1161c9b0550SMarek Lindner 
1171c9b0550SMarek Lindner 	stats->tx_packets = batadv_sum_counter(bat_priv, BATADV_CNT_TX);
1181c9b0550SMarek Lindner 	stats->tx_bytes = batadv_sum_counter(bat_priv, BATADV_CNT_TX_BYTES);
1191c9b0550SMarek Lindner 	stats->tx_dropped = batadv_sum_counter(bat_priv, BATADV_CNT_TX_DROPPED);
1201c9b0550SMarek Lindner 	stats->rx_packets = batadv_sum_counter(bat_priv, BATADV_CNT_RX);
1211c9b0550SMarek Lindner 	stats->rx_bytes = batadv_sum_counter(bat_priv, BATADV_CNT_RX_BYTES);
1221c9b0550SMarek Lindner 	return stats;
123c6c8fea2SSven Eckelmann }
124c6c8fea2SSven Eckelmann 
batadv_interface_set_mac_addr(struct net_device * dev,void * p)1250294ca0dSSven Eckelmann static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
126c6c8fea2SSven Eckelmann {
12756303d34SSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(dev);
12894d1dd87SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
129c6c8fea2SSven Eckelmann 	struct sockaddr *addr = p;
1306b5e971aSSven Eckelmann 	u8 old_addr[ETH_ALEN];
131c6c8fea2SSven Eckelmann 
132c6c8fea2SSven Eckelmann 	if (!is_valid_ether_addr(addr->sa_data))
133c6c8fea2SSven Eckelmann 		return -EADDRNOTAVAIL;
134c6c8fea2SSven Eckelmann 
1358fdd0153SAntonio Quartulli 	ether_addr_copy(old_addr, dev->dev_addr);
1360f00e70eSJakub Kicinski 	eth_hw_addr_set(dev, addr->sa_data);
13740a3eb33SDef 
138015758d0SAntonio Quartulli 	/* only modify transtable if it has been initialized before */
13994d1dd87SAntonio Quartulli 	if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
14094d1dd87SAntonio Quartulli 		return 0;
14194d1dd87SAntonio Quartulli 
14294d1dd87SAntonio Quartulli 	rcu_read_lock();
14394d1dd87SAntonio Quartulli 	hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
14494d1dd87SAntonio Quartulli 		batadv_tt_local_remove(bat_priv, old_addr, vlan->vid,
145cc47f66eSAntonio Quartulli 				       "mac address changed", false);
14694d1dd87SAntonio Quartulli 		batadv_tt_local_add(dev, addr->sa_data, vlan->vid,
1479464d071SAntonio Quartulli 				    BATADV_NULL_IFINDEX, BATADV_NO_MARK);
148c6c8fea2SSven Eckelmann 	}
14994d1dd87SAntonio Quartulli 	rcu_read_unlock();
150c6c8fea2SSven Eckelmann 
151c6c8fea2SSven Eckelmann 	return 0;
152c6c8fea2SSven Eckelmann }
153c6c8fea2SSven Eckelmann 
batadv_interface_change_mtu(struct net_device * dev,int new_mtu)1540294ca0dSSven Eckelmann static int batadv_interface_change_mtu(struct net_device *dev, int new_mtu)
155c6c8fea2SSven Eckelmann {
156d8e42a2bSSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(dev);
157d8e42a2bSSven Eckelmann 
158c6c8fea2SSven Eckelmann 	/* check ranges */
159*e4b81780SSven Eckelmann 	if (new_mtu < ETH_MIN_MTU || new_mtu > batadv_hardif_min_mtu(dev))
160c6c8fea2SSven Eckelmann 		return -EINVAL;
161c6c8fea2SSven Eckelmann 
162c6c8fea2SSven Eckelmann 	dev->mtu = new_mtu;
163d8e42a2bSSven Eckelmann 	bat_priv->mtu_set_by_user = new_mtu;
164c6c8fea2SSven Eckelmann 
165c6c8fea2SSven Eckelmann 	return 0;
166c6c8fea2SSven Eckelmann }
167c6c8fea2SSven Eckelmann 
168a4deee1aSLinus Lüssing /**
1697e9a8c2cSSven Eckelmann  * batadv_interface_set_rx_mode() - set the rx mode of a device
170a4deee1aSLinus Lüssing  * @dev: registered network device to modify
171a4deee1aSLinus Lüssing  *
172a4deee1aSLinus Lüssing  * We do not actually need to set any rx filters for the virtual batman
173a4deee1aSLinus Lüssing  * soft interface. However a dummy handler enables a user to set static
174a4deee1aSLinus Lüssing  * multicast listeners for instance.
175a4deee1aSLinus Lüssing  */
batadv_interface_set_rx_mode(struct net_device * dev)176a4deee1aSLinus Lüssing static void batadv_interface_set_rx_mode(struct net_device *dev)
177a4deee1aSLinus Lüssing {
178a4deee1aSLinus Lüssing }
179a4deee1aSLinus Lüssing 
batadv_interface_tx(struct sk_buff * skb,struct net_device * soft_iface)1806bf9e4d3SLuc Van Oostenryck static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
1810294ca0dSSven Eckelmann 				       struct net_device *soft_iface)
182c6c8fea2SSven Eckelmann {
183c018ad3dSAntonio Quartulli 	struct ethhdr *ethhdr;
18456303d34SSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
18556303d34SSven Eckelmann 	struct batadv_hard_iface *primary_if = NULL;
18696412690SSven Eckelmann 	struct batadv_bcast_packet *bcast_packet;
1876b5e971aSSven Eckelmann 	static const u8 stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00,
1884934ab95SSimon Wunderlich 					      0x00, 0x00};
1896b5e971aSSven Eckelmann 	static const u8 ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00,
1904934ab95SSimon Wunderlich 					       0x00, 0x00};
1916c413b1cSAntonio Quartulli 	enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO;
1926b5e971aSSven Eckelmann 	u8 *dst_hint = NULL, chaddr[ETH_ALEN];
193c018ad3dSAntonio Quartulli 	struct vlan_ethhdr *vhdr;
194be7af5cfSMarek Lindner 	unsigned int header_len = 0;
195c6c8fea2SSven Eckelmann 	int data_len = skb->len, ret;
1963f693390SLinus Lüssing 	unsigned long brd_delay = 0;
197a19d3d85SMarek Lindner 	bool do_bcast = false, client_added;
198c018ad3dSAntonio Quartulli 	unsigned short vid;
1996b5e971aSSven Eckelmann 	u32 seqno;
2006c413b1cSAntonio Quartulli 	int gw_mode;
201e7d6127bSLinus Lüssing 	enum batadv_forw_mode forw_mode = BATADV_FORW_BCAST;
202938f2e0bSLinus Lüssing 	int mcast_is_routable = 0;
20353cf037bSLinus Lüssing 	int network_offset = ETH_HLEN;
204b61ec31cSLinus Lüssing 	__be16 proto;
205c6c8fea2SSven Eckelmann 
20639c75a51SSven Eckelmann 	if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
207c6c8fea2SSven Eckelmann 		goto dropped;
208c6c8fea2SSven Eckelmann 
209e2d9ba43SLinus Lüssing 	/* reset control block to avoid left overs from previous users */
210e2d9ba43SLinus Lüssing 	memset(skb->cb, 0, sizeof(struct batadv_skb_cb));
211e2d9ba43SLinus Lüssing 
212860e9538SFlorian Westphal 	netif_trans_update(soft_iface);
213c018ad3dSAntonio Quartulli 	vid = batadv_get_vid(skb, 0);
2149114daa8SSven Eckelmann 
2159114daa8SSven Eckelmann 	skb_reset_mac_header(skb);
216927c2ed7SLinus Lüssing 	ethhdr = eth_hdr(skb);
217c6c8fea2SSven Eckelmann 
218b61ec31cSLinus Lüssing 	proto = ethhdr->h_proto;
219b61ec31cSLinus Lüssing 
220b61ec31cSLinus Lüssing 	switch (ntohs(proto)) {
221c6c8fea2SSven Eckelmann 	case ETH_P_8021Q:
2224ffcbfacSEric Dumazet 		if (!pskb_may_pull(skb, sizeof(*vhdr)))
2234ffcbfacSEric Dumazet 			goto dropped;
224927c2ed7SLinus Lüssing 		vhdr = vlan_eth_hdr(skb);
225b61ec31cSLinus Lüssing 		proto = vhdr->h_vlan_encapsulated_proto;
226c6c8fea2SSven Eckelmann 
2279d1601efSMarek Lindner 		/* drop batman-in-batman packets to prevent loops */
228b61ec31cSLinus Lüssing 		if (proto != htons(ETH_P_BATMAN)) {
22953cf037bSLinus Lüssing 			network_offset += VLAN_HLEN;
230c6c8fea2SSven Eckelmann 			break;
23153cf037bSLinus Lüssing 		}
232c6c8fea2SSven Eckelmann 
233a7757d31SSven Eckelmann 		fallthrough;
234af5d4f77SAntonio Quartulli 	case ETH_P_BATMAN:
235c6c8fea2SSven Eckelmann 		goto dropped;
236a7f6ee94SSimon Wunderlich 	}
237c6c8fea2SSven Eckelmann 
23853cf037bSLinus Lüssing 	skb_set_network_header(skb, network_offset);
23953cf037bSLinus Lüssing 
24008adf151SSven Eckelmann 	if (batadv_bla_tx(bat_priv, skb, vid))
24123721387SSimon Wunderlich 		goto dropped;
24223721387SSimon Wunderlich 
2439d2c9488SLinus Lüssing 	/* skb->data might have been reallocated by batadv_bla_tx() */
244927c2ed7SLinus Lüssing 	ethhdr = eth_hdr(skb);
2459d2c9488SLinus Lüssing 
246a73105b8SAntonio Quartulli 	/* Register the client MAC in the transtable */
247d3e9768aSSimon Wunderlich 	if (!is_multicast_ether_addr(ethhdr->h_source) &&
248d3e9768aSSimon Wunderlich 	    !batadv_bla_is_loopdetect_mac(ethhdr->h_source)) {
249a19d3d85SMarek Lindner 		client_added = batadv_tt_local_add(soft_iface, ethhdr->h_source,
2509464d071SAntonio Quartulli 						   vid, skb->skb_iif,
2519464d071SAntonio Quartulli 						   skb->mark);
252a19d3d85SMarek Lindner 		if (!client_added)
253a19d3d85SMarek Lindner 			goto dropped;
254a19d3d85SMarek Lindner 	}
255c6c8fea2SSven Eckelmann 
256b61ec31cSLinus Lüssing 	/* Snoop address candidates from DHCPACKs for early DAT filling */
257b61ec31cSLinus Lüssing 	batadv_dat_snoop_outgoing_dhcp_ack(bat_priv, skb, proto, vid);
258b61ec31cSLinus Lüssing 
259b1a8c04bSSimon Wunderlich 	/* don't accept stp packets. STP does not help in meshes.
260b1a8c04bSSimon Wunderlich 	 * better use the bridge loop avoidance ...
2614934ab95SSimon Wunderlich 	 *
2624934ab95SSimon Wunderlich 	 * The same goes for ECTP sent at least by some Cisco Switches,
2634934ab95SSimon Wunderlich 	 * it might confuse the mesh when used with bridge loop avoidance.
264b1a8c04bSSimon Wunderlich 	 */
2651eda58bfSSven Eckelmann 	if (batadv_compare_eth(ethhdr->h_dest, stp_addr))
266b1a8c04bSSimon Wunderlich 		goto dropped;
267b1a8c04bSSimon Wunderlich 
2684934ab95SSimon Wunderlich 	if (batadv_compare_eth(ethhdr->h_dest, ectp_addr))
2694934ab95SSimon Wunderlich 		goto dropped;
2704934ab95SSimon Wunderlich 
2713a24a63eSAntonio Quartulli 	gw_mode = atomic_read(&bat_priv->gw.mode);
272be7af5cfSMarek Lindner 	if (is_multicast_ether_addr(ethhdr->h_dest)) {
2736c413b1cSAntonio Quartulli 		/* if gw mode is off, broadcast every packet */
2746c413b1cSAntonio Quartulli 		if (gw_mode == BATADV_GW_MODE_OFF) {
275be7af5cfSMarek Lindner 			do_bcast = true;
2766c413b1cSAntonio Quartulli 			goto send;
2776c413b1cSAntonio Quartulli 		}
278c6c8fea2SSven Eckelmann 
2796c413b1cSAntonio Quartulli 		dhcp_rcp = batadv_gw_dhcp_recipient_get(skb, &header_len,
2806c413b1cSAntonio Quartulli 							chaddr);
2816c413b1cSAntonio Quartulli 		/* skb->data may have been modified by
2826c413b1cSAntonio Quartulli 		 * batadv_gw_dhcp_recipient_get()
2839cfc7bd6SSven Eckelmann 		 */
284927c2ed7SLinus Lüssing 		ethhdr = eth_hdr(skb);
2856c413b1cSAntonio Quartulli 		/* if gw_mode is on, broadcast any non-DHCP message.
2866c413b1cSAntonio Quartulli 		 * All the DHCP packets are going to be sent as unicast
2876c413b1cSAntonio Quartulli 		 */
2886c413b1cSAntonio Quartulli 		if (dhcp_rcp == BATADV_DHCP_NO) {
2896c413b1cSAntonio Quartulli 			do_bcast = true;
2906c413b1cSAntonio Quartulli 			goto send;
2916c413b1cSAntonio Quartulli 		}
2926c413b1cSAntonio Quartulli 
2936c413b1cSAntonio Quartulli 		if (dhcp_rcp == BATADV_DHCP_TO_CLIENT)
2946c413b1cSAntonio Quartulli 			dst_hint = chaddr;
2956c413b1cSAntonio Quartulli 		else if ((gw_mode == BATADV_GW_MODE_SERVER) &&
2966c413b1cSAntonio Quartulli 			 (dhcp_rcp == BATADV_DHCP_TO_SERVER))
2976c413b1cSAntonio Quartulli 			/* gateways should not forward any DHCP message if
2986c413b1cSAntonio Quartulli 			 * directed to a DHCP server
2996c413b1cSAntonio Quartulli 			 */
300c6c8fea2SSven Eckelmann 			goto dropped;
3019d2c9488SLinus Lüssing 
3026c413b1cSAntonio Quartulli send:
3031d8ab8d3SLinus Lüssing 		if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) {
3041d8ab8d3SLinus Lüssing 			forw_mode = batadv_mcast_forw_mode(bat_priv, skb,
305938f2e0bSLinus Lüssing 							   &mcast_is_routable);
306e7d6127bSLinus Lüssing 			switch (forw_mode) {
307e7d6127bSLinus Lüssing 			case BATADV_FORW_BCAST:
308e7d6127bSLinus Lüssing 				break;
309e7d6127bSLinus Lüssing 			case BATADV_FORW_UCASTS:
3101d8ab8d3SLinus Lüssing 				do_bcast = false;
311e7d6127bSLinus Lüssing 				break;
312e7d6127bSLinus Lüssing 			case BATADV_FORW_NONE:
313e7d6127bSLinus Lüssing 				fallthrough;
314e7d6127bSLinus Lüssing 			default:
315e7d6127bSLinus Lüssing 				goto dropped;
316e7d6127bSLinus Lüssing 			}
3171d8ab8d3SLinus Lüssing 		}
3181d8ab8d3SLinus Lüssing 	}
3191d8ab8d3SLinus Lüssing 
320c54f38c9SSimon Wunderlich 	batadv_skb_set_priority(skb, 0);
321c54f38c9SSimon Wunderlich 
322c6c8fea2SSven Eckelmann 	/* ethernet packet should be broadcasted */
323c6c8fea2SSven Eckelmann 	if (do_bcast) {
324e5d89254SSven Eckelmann 		primary_if = batadv_primary_if_get_selected(bat_priv);
32532ae9b22SMarek Lindner 		if (!primary_if)
326c6c8fea2SSven Eckelmann 			goto dropped;
327c6c8fea2SSven Eckelmann 
328c384ea3eSAntonio Quartulli 		/* in case of ARP request, we do not immediately broadcasti the
329c384ea3eSAntonio Quartulli 		 * packet, instead we first wait for DAT to try to retrieve the
330c384ea3eSAntonio Quartulli 		 * correct ARP entry
331c384ea3eSAntonio Quartulli 		 */
332c384ea3eSAntonio Quartulli 		if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb))
333c384ea3eSAntonio Quartulli 			brd_delay = msecs_to_jiffies(ARP_REQ_DELAY);
334c384ea3eSAntonio Quartulli 
33504b482a2SSven Eckelmann 		if (batadv_skb_head_push(skb, sizeof(*bcast_packet)) < 0)
336c6c8fea2SSven Eckelmann 			goto dropped;
337c6c8fea2SSven Eckelmann 
33896412690SSven Eckelmann 		bcast_packet = (struct batadv_bcast_packet *)skb->data;
339a40d9b07SSimon Wunderlich 		bcast_packet->version = BATADV_COMPAT_VERSION;
3403f693390SLinus Lüssing 		bcast_packet->ttl = BATADV_TTL - 1;
341c6c8fea2SSven Eckelmann 
342c6c8fea2SSven Eckelmann 		/* batman packet type: broadcast */
343a40d9b07SSimon Wunderlich 		bcast_packet->packet_type = BATADV_BCAST;
344162d549cSSven Eckelmann 		bcast_packet->reserved = 0;
345c6c8fea2SSven Eckelmann 
346c6c8fea2SSven Eckelmann 		/* hw address of first interface is the orig mac because only
3479cfc7bd6SSven Eckelmann 		 * this mac is known throughout the mesh
3489cfc7bd6SSven Eckelmann 		 */
3498fdd0153SAntonio Quartulli 		ether_addr_copy(bcast_packet->orig,
3508fdd0153SAntonio Quartulli 				primary_if->net_dev->dev_addr);
351c6c8fea2SSven Eckelmann 
352c6c8fea2SSven Eckelmann 		/* set broadcast sequence number */
353bbb1f90eSSven Eckelmann 		seqno = atomic_inc_return(&bat_priv->bcast_seqno);
354bbb1f90eSSven Eckelmann 		bcast_packet->seqno = htonl(seqno);
355c6c8fea2SSven Eckelmann 
3563f693390SLinus Lüssing 		batadv_send_bcast_packet(bat_priv, skb, brd_delay, true);
357c6c8fea2SSven Eckelmann 	/* unicast packet */
358c6c8fea2SSven Eckelmann 	} else {
3596c413b1cSAntonio Quartulli 		/* DHCP packets going to a server will use the GW feature */
3606c413b1cSAntonio Quartulli 		if (dhcp_rcp == BATADV_DHCP_TO_SERVER) {
3619d2c9488SLinus Lüssing 			ret = batadv_gw_out_of_range(bat_priv, skb);
362be7af5cfSMarek Lindner 			if (ret)
363be7af5cfSMarek Lindner 				goto dropped;
3646c413b1cSAntonio Quartulli 			ret = batadv_send_skb_via_gw(bat_priv, skb, vid);
365e7d6127bSLinus Lüssing 		} else if (forw_mode == BATADV_FORW_UCASTS) {
366938f2e0bSLinus Lüssing 			ret = batadv_mcast_forw_send(bat_priv, skb, vid,
367938f2e0bSLinus Lüssing 						     mcast_is_routable);
3686c413b1cSAntonio Quartulli 		} else {
3696c413b1cSAntonio Quartulli 			if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
3706c413b1cSAntonio Quartulli 								  skb))
371c384ea3eSAntonio Quartulli 				goto dropped;
372c384ea3eSAntonio Quartulli 
373c384ea3eSAntonio Quartulli 			batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
374c384ea3eSAntonio Quartulli 
3756c413b1cSAntonio Quartulli 			ret = batadv_send_skb_via_tt(bat_priv, skb, dst_hint,
3766c413b1cSAntonio Quartulli 						     vid);
3776c413b1cSAntonio Quartulli 		}
378eaac2c87SSven Eckelmann 		if (ret != NET_XMIT_SUCCESS)
379c6c8fea2SSven Eckelmann 			goto dropped_freed;
380c6c8fea2SSven Eckelmann 	}
381c6c8fea2SSven Eckelmann 
3821c9b0550SMarek Lindner 	batadv_inc_counter(bat_priv, BATADV_CNT_TX);
3831c9b0550SMarek Lindner 	batadv_add_counter(bat_priv, BATADV_CNT_TX_BYTES, data_len);
384c6c8fea2SSven Eckelmann 	goto end;
385c6c8fea2SSven Eckelmann 
386c6c8fea2SSven Eckelmann dropped:
387c6c8fea2SSven Eckelmann 	kfree_skb(skb);
388c6c8fea2SSven Eckelmann dropped_freed:
3891c9b0550SMarek Lindner 	batadv_inc_counter(bat_priv, BATADV_CNT_TX_DROPPED);
390c6c8fea2SSven Eckelmann end:
39182047ad7SSven Eckelmann 	batadv_hardif_put(primary_if);
392c6c8fea2SSven Eckelmann 	return NETDEV_TX_OK;
393c6c8fea2SSven Eckelmann }
394c6c8fea2SSven Eckelmann 
395f298cb94SSven Eckelmann /**
3967e9a8c2cSSven Eckelmann  * batadv_interface_rx() - receive ethernet frame on local batman-adv interface
397f298cb94SSven Eckelmann  * @soft_iface: local interface which will receive the ethernet frame
398f298cb94SSven Eckelmann  * @skb: ethernet frame for @soft_iface
399f298cb94SSven Eckelmann  * @hdr_size: size of already parsed batman-adv header
400f298cb94SSven Eckelmann  * @orig_node: originator from which the batman-adv packet was sent
401f298cb94SSven Eckelmann  *
402bccb48c8SSven Eckelmann  * Sends an ethernet frame to the receive path of the local @soft_iface.
403f298cb94SSven Eckelmann  * skb->data has still point to the batman-adv header with the size @hdr_size.
404f298cb94SSven Eckelmann  * The caller has to have parsed this header already and made sure that at least
405f298cb94SSven Eckelmann  * @hdr_size bytes are still available for pull in @skb.
406f298cb94SSven Eckelmann  *
407f298cb94SSven Eckelmann  * The packet may still get dropped. This can happen when the encapsulated
408f298cb94SSven Eckelmann  * ethernet frame is invalid or contains again an batman-adv packet. Also
409f298cb94SSven Eckelmann  * unicast packets will be dropped directly when it was sent between two
410f298cb94SSven Eckelmann  * isolated clients.
411f298cb94SSven Eckelmann  */
batadv_interface_rx(struct net_device * soft_iface,struct sk_buff * skb,int hdr_size,struct batadv_orig_node * orig_node)41204b482a2SSven Eckelmann void batadv_interface_rx(struct net_device *soft_iface,
4136535db56SSven Eckelmann 			 struct sk_buff *skb, int hdr_size,
4146535db56SSven Eckelmann 			 struct batadv_orig_node *orig_node)
415c6c8fea2SSven Eckelmann {
416a40d9b07SSimon Wunderlich 	struct batadv_bcast_packet *batadv_bcast_packet;
417c018ad3dSAntonio Quartulli 	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
418c018ad3dSAntonio Quartulli 	struct vlan_ethhdr *vhdr;
419c018ad3dSAntonio Quartulli 	struct ethhdr *ethhdr;
420c018ad3dSAntonio Quartulli 	unsigned short vid;
42174c09b72SLinus Lüssing 	int packet_type;
4222d3f6cccSSimon Wunderlich 
423a40d9b07SSimon Wunderlich 	batadv_bcast_packet = (struct batadv_bcast_packet *)skb->data;
42474c09b72SLinus Lüssing 	packet_type = batadv_bcast_packet->packet_type;
425c6c8fea2SSven Eckelmann 
426c6c8fea2SSven Eckelmann 	skb_pull_rcsum(skb, hdr_size);
427c6c8fea2SSven Eckelmann 	skb_reset_mac_header(skb);
428c6c8fea2SSven Eckelmann 
42955883fd1SAntonio Quartulli 	/* clean the netfilter state now that the batman-adv header has been
43055883fd1SAntonio Quartulli 	 * removed
43155883fd1SAntonio Quartulli 	 */
432895b5c9fSFlorian Westphal 	nf_reset_ct(skb);
43355883fd1SAntonio Quartulli 
434c7829666SSven Eckelmann 	if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
435c7829666SSven Eckelmann 		goto dropped;
436c7829666SSven Eckelmann 
4372b1e2cb3SAntonio Quartulli 	vid = batadv_get_vid(skb, 0);
4387ed4be95SAntonio Quartulli 	ethhdr = eth_hdr(skb);
439c6c8fea2SSven Eckelmann 
440c6c8fea2SSven Eckelmann 	switch (ntohs(ethhdr->h_proto)) {
441c6c8fea2SSven Eckelmann 	case ETH_P_8021Q:
442c7829666SSven Eckelmann 		if (!pskb_may_pull(skb, VLAN_ETH_HLEN))
443c7829666SSven Eckelmann 			goto dropped;
444c7829666SSven Eckelmann 
4451f5020acSVladimir Oltean 		vhdr = skb_vlan_eth_hdr(skb);
446c6c8fea2SSven Eckelmann 
4479d1601efSMarek Lindner 		/* drop batman-in-batman packets to prevent loops */
4489d1601efSMarek Lindner 		if (vhdr->h_vlan_encapsulated_proto != htons(ETH_P_BATMAN))
449c6c8fea2SSven Eckelmann 			break;
450c6c8fea2SSven Eckelmann 
451a7757d31SSven Eckelmann 		fallthrough;
452af5d4f77SAntonio Quartulli 	case ETH_P_BATMAN:
453c6c8fea2SSven Eckelmann 		goto dropped;
454c6c8fea2SSven Eckelmann 	}
455c6c8fea2SSven Eckelmann 
456c6c8fea2SSven Eckelmann 	/* skb->dev & skb->pkt_type are set here */
457c6c8fea2SSven Eckelmann 	skb->protocol = eth_type_trans(skb, soft_iface);
458abd63605SMatthias Schiffer 	skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
459c6c8fea2SSven Eckelmann 
4601c9b0550SMarek Lindner 	batadv_inc_counter(bat_priv, BATADV_CNT_RX);
4611c9b0550SMarek Lindner 	batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,
4621c9b0550SMarek Lindner 			   skb->len + ETH_HLEN);
463c6c8fea2SSven Eckelmann 
46474490f96SAntonio Quartulli 	/* Let the bridge loop avoidance check the packet. If will
46574490f96SAntonio Quartulli 	 * not handle it, we can safely push it up.
46674490f96SAntonio Quartulli 	 */
46774c09b72SLinus Lüssing 	if (batadv_bla_rx(bat_priv, skb, vid, packet_type))
46874490f96SAntonio Quartulli 		goto out;
46974490f96SAntonio Quartulli 
47037135173SAntonio Quartulli 	if (orig_node)
47137135173SAntonio Quartulli 		batadv_tt_add_temporary_global_entry(bat_priv, orig_node,
472c018ad3dSAntonio Quartulli 						     ethhdr->h_source, vid);
47337135173SAntonio Quartulli 
47442cb0befSAntonio Quartulli 	if (is_multicast_ether_addr(ethhdr->h_dest)) {
47542cb0befSAntonio Quartulli 		/* set the mark on broadcast packets if AP isolation is ON and
47642cb0befSAntonio Quartulli 		 * the packet is coming from an "isolated" client
47742cb0befSAntonio Quartulli 		 */
47842cb0befSAntonio Quartulli 		if (batadv_vlan_ap_isola_get(bat_priv, vid) &&
47942cb0befSAntonio Quartulli 		    batadv_tt_global_is_isolated(bat_priv, ethhdr->h_source,
48042cb0befSAntonio Quartulli 						 vid)) {
48142cb0befSAntonio Quartulli 			/* save bits in skb->mark not covered by the mask and
48242cb0befSAntonio Quartulli 			 * apply the mark on the rest
48342cb0befSAntonio Quartulli 			 */
48442cb0befSAntonio Quartulli 			skb->mark &= ~bat_priv->isolation_mark_mask;
48542cb0befSAntonio Quartulli 			skb->mark |= bat_priv->isolation_mark;
48642cb0befSAntonio Quartulli 		}
48742cb0befSAntonio Quartulli 	} else if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source,
48842cb0befSAntonio Quartulli 					 ethhdr->h_dest, vid)) {
48959b699cdSAntonio Quartulli 		goto dropped;
49042cb0befSAntonio Quartulli 	}
49159b699cdSAntonio Quartulli 
492c6c8fea2SSven Eckelmann 	netif_rx(skb);
493ba85fac2SSimon Wunderlich 	goto out;
494c6c8fea2SSven Eckelmann 
495c6c8fea2SSven Eckelmann dropped:
496c6c8fea2SSven Eckelmann 	kfree_skb(skb);
497c6c8fea2SSven Eckelmann out:
498c6c8fea2SSven Eckelmann 	return;
499c6c8fea2SSven Eckelmann }
500c6c8fea2SSven Eckelmann 
5015d2c05b2SAntonio Quartulli /**
5027e9a8c2cSSven Eckelmann  * batadv_softif_vlan_release() - release vlan from lists and queue for free
5037e9a8c2cSSven Eckelmann  *  after rcu grace period
5046be4d30cSSven Eckelmann  * @ref: kref pointer of the vlan object
5056be4d30cSSven Eckelmann  */
batadv_softif_vlan_release(struct kref * ref)5066340dcbdSSven Eckelmann void batadv_softif_vlan_release(struct kref *ref)
5076be4d30cSSven Eckelmann {
5086be4d30cSSven Eckelmann 	struct batadv_softif_vlan *vlan;
5096be4d30cSSven Eckelmann 
5106be4d30cSSven Eckelmann 	vlan = container_of(ref, struct batadv_softif_vlan, refcount);
5116be4d30cSSven Eckelmann 
5126be4d30cSSven Eckelmann 	spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock);
5136be4d30cSSven Eckelmann 	hlist_del_rcu(&vlan->list);
5146be4d30cSSven Eckelmann 	spin_unlock_bh(&vlan->bat_priv->softif_vlan_list_lock);
5156be4d30cSSven Eckelmann 
5166be4d30cSSven Eckelmann 	kfree_rcu(vlan, rcu);
5176be4d30cSSven Eckelmann }
5186be4d30cSSven Eckelmann 
5196be4d30cSSven Eckelmann /**
5207e9a8c2cSSven Eckelmann  * batadv_softif_vlan_get() - get the vlan object for a specific vid
5215d2c05b2SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
5225d2c05b2SAntonio Quartulli  * @vid: the identifier of the vlan object to retrieve
5235d2c05b2SAntonio Quartulli  *
52462fe710fSSven Eckelmann  * Return: the private data of the vlan matching the vid passed as argument or
5255d2c05b2SAntonio Quartulli  * NULL otherwise. The refcounter of the returned object is incremented by 1.
5265d2c05b2SAntonio Quartulli  */
batadv_softif_vlan_get(struct batadv_priv * bat_priv,unsigned short vid)52790f4435dSAntonio Quartulli struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv,
52890f4435dSAntonio Quartulli 						  unsigned short vid)
5295d2c05b2SAntonio Quartulli {
5305d2c05b2SAntonio Quartulli 	struct batadv_softif_vlan *vlan_tmp, *vlan = NULL;
5315d2c05b2SAntonio Quartulli 
5325d2c05b2SAntonio Quartulli 	rcu_read_lock();
5335d2c05b2SAntonio Quartulli 	hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) {
5345d2c05b2SAntonio Quartulli 		if (vlan_tmp->vid != vid)
5355d2c05b2SAntonio Quartulli 			continue;
5365d2c05b2SAntonio Quartulli 
5376be4d30cSSven Eckelmann 		if (!kref_get_unless_zero(&vlan_tmp->refcount))
5385d2c05b2SAntonio Quartulli 			continue;
5395d2c05b2SAntonio Quartulli 
5405d2c05b2SAntonio Quartulli 		vlan = vlan_tmp;
5415d2c05b2SAntonio Quartulli 		break;
5425d2c05b2SAntonio Quartulli 	}
5435d2c05b2SAntonio Quartulli 	rcu_read_unlock();
5445d2c05b2SAntonio Quartulli 
5455d2c05b2SAntonio Quartulli 	return vlan;
5465d2c05b2SAntonio Quartulli }
5475d2c05b2SAntonio Quartulli 
5485d2c05b2SAntonio Quartulli /**
5497e9a8c2cSSven Eckelmann  * batadv_softif_create_vlan() - allocate the needed resources for a new vlan
5505d2c05b2SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
5515d2c05b2SAntonio Quartulli  * @vid: the VLAN identifier
5525d2c05b2SAntonio Quartulli  *
55362fe710fSSven Eckelmann  * Return: 0 on success, a negative error otherwise.
5545d2c05b2SAntonio Quartulli  */
batadv_softif_create_vlan(struct batadv_priv * bat_priv,unsigned short vid)5555d2c05b2SAntonio Quartulli int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
5565d2c05b2SAntonio Quartulli {
5575d2c05b2SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
5585d2c05b2SAntonio Quartulli 
55994cb82f5SSven Eckelmann 	spin_lock_bh(&bat_priv->softif_vlan_list_lock);
56094cb82f5SSven Eckelmann 
5615d2c05b2SAntonio Quartulli 	vlan = batadv_softif_vlan_get(bat_priv, vid);
5625d2c05b2SAntonio Quartulli 	if (vlan) {
5639c3bf081SSven Eckelmann 		batadv_softif_vlan_put(vlan);
56494cb82f5SSven Eckelmann 		spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
5655d2c05b2SAntonio Quartulli 		return -EEXIST;
5665d2c05b2SAntonio Quartulli 	}
5675d2c05b2SAntonio Quartulli 
5685d2c05b2SAntonio Quartulli 	vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
56994cb82f5SSven Eckelmann 	if (!vlan) {
57094cb82f5SSven Eckelmann 		spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
5715d2c05b2SAntonio Quartulli 		return -ENOMEM;
57294cb82f5SSven Eckelmann 	}
5735d2c05b2SAntonio Quartulli 
57435df3b29SAntonio Quartulli 	vlan->bat_priv = bat_priv;
5755d2c05b2SAntonio Quartulli 	vlan->vid = vid;
5766be4d30cSSven Eckelmann 	kref_init(&vlan->refcount);
5775d2c05b2SAntonio Quartulli 
578b8cbd81dSAntonio Quartulli 	atomic_set(&vlan->ap_isolation, 0);
579b8cbd81dSAntonio Quartulli 
580df28ca6bSSven Eckelmann 	kref_get(&vlan->refcount);
58135df3b29SAntonio Quartulli 	hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list);
58235df3b29SAntonio Quartulli 	spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
58335df3b29SAntonio Quartulli 
5845d2c05b2SAntonio Quartulli 	/* add a new TT local entry. This one will be marked with the NOPURGE
5855d2c05b2SAntonio Quartulli 	 * flag
5865d2c05b2SAntonio Quartulli 	 */
5875d2c05b2SAntonio Quartulli 	batadv_tt_local_add(bat_priv->soft_iface,
5885d2c05b2SAntonio Quartulli 			    bat_priv->soft_iface->dev_addr, vid,
5899464d071SAntonio Quartulli 			    BATADV_NULL_IFINDEX, BATADV_NO_MARK);
5905d2c05b2SAntonio Quartulli 
591df28ca6bSSven Eckelmann 	/* don't return reference to new softif_vlan */
592df28ca6bSSven Eckelmann 	batadv_softif_vlan_put(vlan);
593df28ca6bSSven Eckelmann 
5945d2c05b2SAntonio Quartulli 	return 0;
5955d2c05b2SAntonio Quartulli }
5965d2c05b2SAntonio Quartulli 
5975d2c05b2SAntonio Quartulli /**
5987e9a8c2cSSven Eckelmann  * batadv_softif_destroy_vlan() - remove and destroy a softif_vlan object
5995d2c05b2SAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
6005d2c05b2SAntonio Quartulli  * @vlan: the object to remove
6015d2c05b2SAntonio Quartulli  */
batadv_softif_destroy_vlan(struct batadv_priv * bat_priv,struct batadv_softif_vlan * vlan)6025d2c05b2SAntonio Quartulli static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv,
6035d2c05b2SAntonio Quartulli 				       struct batadv_softif_vlan *vlan)
6045d2c05b2SAntonio Quartulli {
6055d2c05b2SAntonio Quartulli 	/* explicitly remove the associated TT local entry because it is marked
6065d2c05b2SAntonio Quartulli 	 * with the NOPURGE flag
6075d2c05b2SAntonio Quartulli 	 */
6085d2c05b2SAntonio Quartulli 	batadv_tt_local_remove(bat_priv, bat_priv->soft_iface->dev_addr,
6095d2c05b2SAntonio Quartulli 			       vlan->vid, "vlan interface destroyed", false);
6105d2c05b2SAntonio Quartulli 
6119c3bf081SSven Eckelmann 	batadv_softif_vlan_put(vlan);
6125d2c05b2SAntonio Quartulli }
6135d2c05b2SAntonio Quartulli 
6145d2c05b2SAntonio Quartulli /**
6157e9a8c2cSSven Eckelmann  * batadv_interface_add_vid() - ndo_add_vid API implementation
6165d2c05b2SAntonio Quartulli  * @dev: the netdev of the mesh interface
61721ba5ab2SSven Eckelmann  * @proto: protocol of the vlan id
6185d2c05b2SAntonio Quartulli  * @vid: identifier of the new vlan
6195d2c05b2SAntonio Quartulli  *
6205d2c05b2SAntonio Quartulli  * Set up all the internal structures for handling the new vlan on top of the
6215d2c05b2SAntonio Quartulli  * mesh interface
6225d2c05b2SAntonio Quartulli  *
62362fe710fSSven Eckelmann  * Return: 0 on success or a negative error code in case of failure.
6245d2c05b2SAntonio Quartulli  */
batadv_interface_add_vid(struct net_device * dev,__be16 proto,unsigned short vid)6255d2c05b2SAntonio Quartulli static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
6265d2c05b2SAntonio Quartulli 				    unsigned short vid)
6275d2c05b2SAntonio Quartulli {
6285d2c05b2SAntonio Quartulli 	struct batadv_priv *bat_priv = netdev_priv(dev);
62935df3b29SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
6305d2c05b2SAntonio Quartulli 
6315d2c05b2SAntonio Quartulli 	/* only 802.1Q vlans are supported.
6325d2c05b2SAntonio Quartulli 	 * batman-adv does not know how to handle other types
6335d2c05b2SAntonio Quartulli 	 */
6345d2c05b2SAntonio Quartulli 	if (proto != htons(ETH_P_8021Q))
6355d2c05b2SAntonio Quartulli 		return -EINVAL;
6365d2c05b2SAntonio Quartulli 
6375d2c05b2SAntonio Quartulli 	vid |= BATADV_VLAN_HAS_TAG;
6385d2c05b2SAntonio Quartulli 
63935df3b29SAntonio Quartulli 	/* if a new vlan is getting created and it already exists, it means that
64035df3b29SAntonio Quartulli 	 * it was not deleted yet. batadv_softif_vlan_get() increases the
64135df3b29SAntonio Quartulli 	 * refcount in order to revive the object.
64235df3b29SAntonio Quartulli 	 *
64335df3b29SAntonio Quartulli 	 * if it does not exist then create it.
64435df3b29SAntonio Quartulli 	 */
64535df3b29SAntonio Quartulli 	vlan = batadv_softif_vlan_get(bat_priv, vid);
64635df3b29SAntonio Quartulli 	if (!vlan)
6475d2c05b2SAntonio Quartulli 		return batadv_softif_create_vlan(bat_priv, vid);
64835df3b29SAntonio Quartulli 
64935df3b29SAntonio Quartulli 	/* add a new TT local entry. This one will be marked with the NOPURGE
65035df3b29SAntonio Quartulli 	 * flag. This must be added again, even if the vlan object already
65135df3b29SAntonio Quartulli 	 * exists, because the entry was deleted by kill_vid()
65235df3b29SAntonio Quartulli 	 */
65335df3b29SAntonio Quartulli 	batadv_tt_local_add(bat_priv->soft_iface,
65435df3b29SAntonio Quartulli 			    bat_priv->soft_iface->dev_addr, vid,
65535df3b29SAntonio Quartulli 			    BATADV_NULL_IFINDEX, BATADV_NO_MARK);
65635df3b29SAntonio Quartulli 
65735df3b29SAntonio Quartulli 	return 0;
6585d2c05b2SAntonio Quartulli }
6595d2c05b2SAntonio Quartulli 
6605d2c05b2SAntonio Quartulli /**
6617e9a8c2cSSven Eckelmann  * batadv_interface_kill_vid() - ndo_kill_vid API implementation
6625d2c05b2SAntonio Quartulli  * @dev: the netdev of the mesh interface
66321ba5ab2SSven Eckelmann  * @proto: protocol of the vlan id
6645d2c05b2SAntonio Quartulli  * @vid: identifier of the deleted vlan
6655d2c05b2SAntonio Quartulli  *
6665d2c05b2SAntonio Quartulli  * Destroy all the internal structures used to handle the vlan identified by vid
6675d2c05b2SAntonio Quartulli  * on top of the mesh interface
6685d2c05b2SAntonio Quartulli  *
66962fe710fSSven Eckelmann  * Return: 0 on success, -EINVAL if the specified prototype is not ETH_P_8021Q
6705d2c05b2SAntonio Quartulli  * or -ENOENT if the specified vlan id wasn't registered.
6715d2c05b2SAntonio Quartulli  */
batadv_interface_kill_vid(struct net_device * dev,__be16 proto,unsigned short vid)6725d2c05b2SAntonio Quartulli static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
6735d2c05b2SAntonio Quartulli 				     unsigned short vid)
6745d2c05b2SAntonio Quartulli {
6755d2c05b2SAntonio Quartulli 	struct batadv_priv *bat_priv = netdev_priv(dev);
6765d2c05b2SAntonio Quartulli 	struct batadv_softif_vlan *vlan;
6775d2c05b2SAntonio Quartulli 
6785d2c05b2SAntonio Quartulli 	/* only 802.1Q vlans are supported. batman-adv does not know how to
6795d2c05b2SAntonio Quartulli 	 * handle other types
6805d2c05b2SAntonio Quartulli 	 */
6815d2c05b2SAntonio Quartulli 	if (proto != htons(ETH_P_8021Q))
6825d2c05b2SAntonio Quartulli 		return -EINVAL;
6835d2c05b2SAntonio Quartulli 
6845d2c05b2SAntonio Quartulli 	vlan = batadv_softif_vlan_get(bat_priv, vid | BATADV_VLAN_HAS_TAG);
6855d2c05b2SAntonio Quartulli 	if (!vlan)
6865d2c05b2SAntonio Quartulli 		return -ENOENT;
6875d2c05b2SAntonio Quartulli 
6885d2c05b2SAntonio Quartulli 	batadv_softif_destroy_vlan(bat_priv, vlan);
6895d2c05b2SAntonio Quartulli 
6905d2c05b2SAntonio Quartulli 	/* finally free the vlan object */
6919c3bf081SSven Eckelmann 	batadv_softif_vlan_put(vlan);
6925d2c05b2SAntonio Quartulli 
6935d2c05b2SAntonio Quartulli 	return 0;
6945d2c05b2SAntonio Quartulli }
6955d2c05b2SAntonio Quartulli 
6961a33e10eSCong Wang /* batman-adv network devices have devices nesting below it and are a special
6971a33e10eSCong Wang  * "super class" of normal network devices; split their locks off into a
6981a33e10eSCong Wang  * separate class since they always nest.
6991a33e10eSCong Wang  */
7001a33e10eSCong Wang static struct lock_class_key batadv_netdev_xmit_lock_key;
701845e0ebbSCong Wang static struct lock_class_key batadv_netdev_addr_lock_key;
7021a33e10eSCong Wang 
7031a33e10eSCong Wang /**
7041a33e10eSCong Wang  * batadv_set_lockdep_class_one() - Set lockdep class for a single tx queue
7051a33e10eSCong Wang  * @dev: device which owns the tx queue
7061a33e10eSCong Wang  * @txq: tx queue to modify
7071a33e10eSCong Wang  * @_unused: always NULL
7081a33e10eSCong Wang  */
batadv_set_lockdep_class_one(struct net_device * dev,struct netdev_queue * txq,void * _unused)7091a33e10eSCong Wang static void batadv_set_lockdep_class_one(struct net_device *dev,
7101a33e10eSCong Wang 					 struct netdev_queue *txq,
7111a33e10eSCong Wang 					 void *_unused)
7121a33e10eSCong Wang {
7131a33e10eSCong Wang 	lockdep_set_class(&txq->_xmit_lock, &batadv_netdev_xmit_lock_key);
7141a33e10eSCong Wang }
7151a33e10eSCong Wang 
7161a33e10eSCong Wang /**
7171a33e10eSCong Wang  * batadv_set_lockdep_class() - Set txq and addr_list lockdep class
7181a33e10eSCong Wang  * @dev: network device to modify
7191a33e10eSCong Wang  */
batadv_set_lockdep_class(struct net_device * dev)7201a33e10eSCong Wang static void batadv_set_lockdep_class(struct net_device *dev)
7211a33e10eSCong Wang {
722845e0ebbSCong Wang 	lockdep_set_class(&dev->addr_list_lock, &batadv_netdev_addr_lock_key);
7231a33e10eSCong Wang 	netdev_for_each_tx_queue(dev, batadv_set_lockdep_class_one, NULL);
7241a33e10eSCong Wang }
7251a33e10eSCong Wang 
72636c1d153SSven Eckelmann /**
7277e9a8c2cSSven Eckelmann  * batadv_softif_init_late() - late stage initialization of soft interface
72837130293SSven Eckelmann  * @dev: registered network device to modify
72937130293SSven Eckelmann  *
73062fe710fSSven Eckelmann  * Return: error code on failures
73137130293SSven Eckelmann  */
batadv_softif_init_late(struct net_device * dev)73237130293SSven Eckelmann static int batadv_softif_init_late(struct net_device *dev)
733c6c8fea2SSven Eckelmann {
73456303d34SSven Eckelmann 	struct batadv_priv *bat_priv;
7356b5e971aSSven Eckelmann 	u32 random_seqno;
736c6c8fea2SSven Eckelmann 	int ret;
7376b5e971aSSven Eckelmann 	size_t cnt_len = sizeof(u64) * BATADV_CNT_NUM;
738c6c8fea2SSven Eckelmann 
7391a33e10eSCong Wang 	batadv_set_lockdep_class(dev);
7401a33e10eSCong Wang 
74137130293SSven Eckelmann 	bat_priv = netdev_priv(dev);
74237130293SSven Eckelmann 	bat_priv->soft_iface = dev;
7431c9b0550SMarek Lindner 
7441c9b0550SMarek Lindner 	/* batadv_interface_stats() needs to be available as soon as
7451c9b0550SMarek Lindner 	 * register_netdevice() has been called
7461c9b0550SMarek Lindner 	 */
7476b5e971aSSven Eckelmann 	bat_priv->bat_counters = __alloc_percpu(cnt_len, __alignof__(u64));
7481c9b0550SMarek Lindner 	if (!bat_priv->bat_counters)
74937130293SSven Eckelmann 		return -ENOMEM;
750c6c8fea2SSven Eckelmann 
751c6c8fea2SSven Eckelmann 	atomic_set(&bat_priv->aggregated_ogms, 1);
752c6c8fea2SSven Eckelmann 	atomic_set(&bat_priv->bonding, 0);
753fa706554SAntonio Quartulli #ifdef CONFIG_BATMAN_ADV_BLA
754dab7b621SSven Eckelmann 	atomic_set(&bat_priv->bridge_loop_avoidance, 1);
755fa706554SAntonio Quartulli #endif
75633af49adSAntonio Quartulli #ifdef CONFIG_BATMAN_ADV_DAT
75733af49adSAntonio Quartulli 	atomic_set(&bat_priv->distributed_arp_table, 1);
75833af49adSAntonio Quartulli #endif
75960432d75SLinus Lüssing #ifdef CONFIG_BATMAN_ADV_MCAST
7601d8ab8d3SLinus Lüssing 	atomic_set(&bat_priv->multicast_mode, 1);
76132e72744SLinus Lüssing 	atomic_set(&bat_priv->multicast_fanout, 16);
762ab49886eSLinus Lüssing 	atomic_set(&bat_priv->mcast.num_want_all_unsnoopables, 0);
7634c8755d6SLinus Lüssing 	atomic_set(&bat_priv->mcast.num_want_all_ipv4, 0);
7644c8755d6SLinus Lüssing 	atomic_set(&bat_priv->mcast.num_want_all_ipv6, 0);
76560432d75SLinus Lüssing #endif
7663a24a63eSAntonio Quartulli 	atomic_set(&bat_priv->gw.mode, BATADV_GW_MODE_OFF);
767414254e3SMarek Lindner 	atomic_set(&bat_priv->gw.bandwidth_down, 100);
768414254e3SMarek Lindner 	atomic_set(&bat_priv->gw.bandwidth_up, 20);
769c6c8fea2SSven Eckelmann 	atomic_set(&bat_priv->orig_interval, 1000);
770e03366eaSSimon Wunderlich 	atomic_set(&bat_priv->hop_penalty, 30);
7710c430d0dSMarek Lindner #ifdef CONFIG_BATMAN_ADV_DEBUG
772c6c8fea2SSven Eckelmann 	atomic_set(&bat_priv->log_level, 0);
7730c430d0dSMarek Lindner #endif
774c6c8fea2SSven Eckelmann 	atomic_set(&bat_priv->fragmentation, 1);
775a19d3d85SMarek Lindner 	atomic_set(&bat_priv->packet_size_max, ETH_DATA_LEN);
77642d0b044SSven Eckelmann 	atomic_set(&bat_priv->bcast_queue_left, BATADV_BCAST_QUEUE_LEN);
77742d0b044SSven Eckelmann 	atomic_set(&bat_priv->batman_queue_left, BATADV_BATMAN_QUEUE_LEN);
778c6c8fea2SSven Eckelmann 
77939c75a51SSven Eckelmann 	atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE);
780c6c8fea2SSven Eckelmann 	atomic_set(&bat_priv->bcast_seqno, 1);
781807736f6SSven Eckelmann 	atomic_set(&bat_priv->tt.vn, 0);
782807736f6SSven Eckelmann 	atomic_set(&bat_priv->tt.local_changes, 0);
783807736f6SSven Eckelmann 	atomic_set(&bat_priv->tt.ogm_append_cnt, 0);
784807736f6SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_BLA
785807736f6SSven Eckelmann 	atomic_set(&bat_priv->bla.num_requests, 0);
786807736f6SSven Eckelmann #endif
78733a3bb4aSAntonio Quartulli 	atomic_set(&bat_priv->tp_num, 0);
78833a3bb4aSAntonio Quartulli 
789807736f6SSven Eckelmann 	bat_priv->tt.last_changeset = NULL;
790807736f6SSven Eckelmann 	bat_priv->tt.last_changeset_len = 0;
791c42edfe3SAntonio Quartulli 	bat_priv->isolation_mark = 0;
792c42edfe3SAntonio Quartulli 	bat_priv->isolation_mark_mask = 0;
793c6c8fea2SSven Eckelmann 
794ee75ed88SMartin Hundebøll 	/* randomize initial seqno to avoid collision */
795ee75ed88SMartin Hundebøll 	get_random_bytes(&random_seqno, sizeof(random_seqno));
796ee75ed88SMartin Hundebøll 	atomic_set(&bat_priv->frag_seqno, random_seqno);
797ee75ed88SMartin Hundebøll 
798c6c8fea2SSven Eckelmann 	bat_priv->primary_if = NULL;
799c6c8fea2SSven Eckelmann 
800d353d8d4SMartin Hundebøll 	batadv_nc_init_bat_priv(bat_priv);
801d353d8d4SMartin Hundebøll 
802a5ad457eSSven Eckelmann 	if (!bat_priv->algo_ops) {
80337130293SSven Eckelmann 		ret = batadv_algo_select(bat_priv, batadv_routing_algo);
804c6c8fea2SSven Eckelmann 		if (ret < 0)
80537130293SSven Eckelmann 			goto free_bat_counters;
806a5ad457eSSven Eckelmann 	}
807c6c8fea2SSven Eckelmann 
808aff6f5a6SSven Eckelmann 	ret = batadv_mesh_init(dev);
809c6c8fea2SSven Eckelmann 	if (ret < 0)
81037130293SSven Eckelmann 		goto free_bat_counters;
811c6c8fea2SSven Eckelmann 
81237130293SSven Eckelmann 	return 0;
813c6c8fea2SSven Eckelmann 
8141c9b0550SMarek Lindner free_bat_counters:
8151c9b0550SMarek Lindner 	free_percpu(bat_priv->bat_counters);
816f69ae770SMartin Hundebøll 	bat_priv->bat_counters = NULL;
81737130293SSven Eckelmann 
81837130293SSven Eckelmann 	return ret;
81937130293SSven Eckelmann }
82037130293SSven Eckelmann 
8213dbd550bSSven Eckelmann /**
8227e9a8c2cSSven Eckelmann  * batadv_softif_slave_add() - Add a slave interface to a batadv_soft_interface
8233dbd550bSSven Eckelmann  * @dev: batadv_soft_interface used as master interface
8243dbd550bSSven Eckelmann  * @slave_dev: net_device which should become the slave interface
825bad5680bSSven Eckelmann  * @extack: extended ACK report struct
8263dbd550bSSven Eckelmann  *
82762fe710fSSven Eckelmann  * Return: 0 if successful or error otherwise.
8283dbd550bSSven Eckelmann  */
batadv_softif_slave_add(struct net_device * dev,struct net_device * slave_dev,struct netlink_ext_ack * extack)8293dbd550bSSven Eckelmann static int batadv_softif_slave_add(struct net_device *dev,
83033eaf2a6SDavid Ahern 				   struct net_device *slave_dev,
83133eaf2a6SDavid Ahern 				   struct netlink_ext_ack *extack)
8323dbd550bSSven Eckelmann {
8333dbd550bSSven Eckelmann 	struct batadv_hard_iface *hard_iface;
8343dbd550bSSven Eckelmann 	int ret = -EINVAL;
8353dbd550bSSven Eckelmann 
8363dbd550bSSven Eckelmann 	hard_iface = batadv_hardif_get_by_netdev(slave_dev);
83700f548bfSMarek Lindner 	if (!hard_iface || hard_iface->soft_iface)
8383dbd550bSSven Eckelmann 		goto out;
8393dbd550bSSven Eckelmann 
840fa205602SSven Eckelmann 	ret = batadv_hardif_enable_interface(hard_iface, dev);
8413dbd550bSSven Eckelmann 
8423dbd550bSSven Eckelmann out:
84382047ad7SSven Eckelmann 	batadv_hardif_put(hard_iface);
8443dbd550bSSven Eckelmann 	return ret;
8453dbd550bSSven Eckelmann }
8463dbd550bSSven Eckelmann 
8473dbd550bSSven Eckelmann /**
8487e9a8c2cSSven Eckelmann  * batadv_softif_slave_del() - Delete a slave iface from a batadv_soft_interface
8493dbd550bSSven Eckelmann  * @dev: batadv_soft_interface used as master interface
8503dbd550bSSven Eckelmann  * @slave_dev: net_device which should be removed from the master interface
8513dbd550bSSven Eckelmann  *
85262fe710fSSven Eckelmann  * Return: 0 if successful or error otherwise.
8533dbd550bSSven Eckelmann  */
batadv_softif_slave_del(struct net_device * dev,struct net_device * slave_dev)8543dbd550bSSven Eckelmann static int batadv_softif_slave_del(struct net_device *dev,
8553dbd550bSSven Eckelmann 				   struct net_device *slave_dev)
8563dbd550bSSven Eckelmann {
8573dbd550bSSven Eckelmann 	struct batadv_hard_iface *hard_iface;
8583dbd550bSSven Eckelmann 	int ret = -EINVAL;
8593dbd550bSSven Eckelmann 
8603dbd550bSSven Eckelmann 	hard_iface = batadv_hardif_get_by_netdev(slave_dev);
8613dbd550bSSven Eckelmann 
8623dbd550bSSven Eckelmann 	if (!hard_iface || hard_iface->soft_iface != dev)
8633dbd550bSSven Eckelmann 		goto out;
8643dbd550bSSven Eckelmann 
865a962cb29SSven Eckelmann 	batadv_hardif_disable_interface(hard_iface);
8663dbd550bSSven Eckelmann 	ret = 0;
8673dbd550bSSven Eckelmann 
8683dbd550bSSven Eckelmann out:
86982047ad7SSven Eckelmann 	batadv_hardif_put(hard_iface);
8703dbd550bSSven Eckelmann 	return ret;
8713dbd550bSSven Eckelmann }
8723dbd550bSSven Eckelmann 
87337130293SSven Eckelmann static const struct net_device_ops batadv_netdev_ops = {
87437130293SSven Eckelmann 	.ndo_init = batadv_softif_init_late,
87537130293SSven Eckelmann 	.ndo_open = batadv_interface_open,
87637130293SSven Eckelmann 	.ndo_stop = batadv_interface_release,
87737130293SSven Eckelmann 	.ndo_get_stats = batadv_interface_stats,
8785d2c05b2SAntonio Quartulli 	.ndo_vlan_rx_add_vid = batadv_interface_add_vid,
8795d2c05b2SAntonio Quartulli 	.ndo_vlan_rx_kill_vid = batadv_interface_kill_vid,
88037130293SSven Eckelmann 	.ndo_set_mac_address = batadv_interface_set_mac_addr,
88137130293SSven Eckelmann 	.ndo_change_mtu = batadv_interface_change_mtu,
882a4deee1aSLinus Lüssing 	.ndo_set_rx_mode = batadv_interface_set_rx_mode,
88337130293SSven Eckelmann 	.ndo_start_xmit = batadv_interface_tx,
8843dbd550bSSven Eckelmann 	.ndo_validate_addr = eth_validate_addr,
8853dbd550bSSven Eckelmann 	.ndo_add_slave = batadv_softif_slave_add,
8863dbd550bSSven Eckelmann 	.ndo_del_slave = batadv_softif_slave_del,
88737130293SSven Eckelmann };
88837130293SSven Eckelmann 
batadv_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * info)8895405e19eSSven Eckelmann static void batadv_get_drvinfo(struct net_device *dev,
8905405e19eSSven Eckelmann 			       struct ethtool_drvinfo *info)
8915405e19eSSven Eckelmann {
892529a8f93SSven Eckelmann 	strscpy(info->driver, "B.A.T.M.A.N. advanced", sizeof(info->driver));
893529a8f93SSven Eckelmann 	strscpy(info->version, BATADV_SOURCE_VERSION, sizeof(info->version));
894529a8f93SSven Eckelmann 	strscpy(info->fw_version, "N/A", sizeof(info->fw_version));
895529a8f93SSven Eckelmann 	strscpy(info->bus_info, "batman", sizeof(info->bus_info));
8965405e19eSSven Eckelmann }
8975405e19eSSven Eckelmann 
8985405e19eSSven Eckelmann /* Inspired by drivers/net/ethernet/dlink/sundance.c:1702
8995405e19eSSven Eckelmann  * Declare each description string in struct.name[] to get fixed sized buffer
9005405e19eSSven Eckelmann  * and compile time checking for strings longer than ETH_GSTRING_LEN.
9015405e19eSSven Eckelmann  */
9025405e19eSSven Eckelmann static const struct {
9035405e19eSSven Eckelmann 	const char name[ETH_GSTRING_LEN];
9045405e19eSSven Eckelmann } batadv_counters_strings[] = {
9055405e19eSSven Eckelmann 	{ "tx" },
9065405e19eSSven Eckelmann 	{ "tx_bytes" },
9075405e19eSSven Eckelmann 	{ "tx_dropped" },
9085405e19eSSven Eckelmann 	{ "rx" },
9095405e19eSSven Eckelmann 	{ "rx_bytes" },
9105405e19eSSven Eckelmann 	{ "forward" },
9115405e19eSSven Eckelmann 	{ "forward_bytes" },
9125405e19eSSven Eckelmann 	{ "mgmt_tx" },
9135405e19eSSven Eckelmann 	{ "mgmt_tx_bytes" },
9145405e19eSSven Eckelmann 	{ "mgmt_rx" },
9155405e19eSSven Eckelmann 	{ "mgmt_rx_bytes" },
9165405e19eSSven Eckelmann 	{ "frag_tx" },
9175405e19eSSven Eckelmann 	{ "frag_tx_bytes" },
9185405e19eSSven Eckelmann 	{ "frag_rx" },
9195405e19eSSven Eckelmann 	{ "frag_rx_bytes" },
9205405e19eSSven Eckelmann 	{ "frag_fwd" },
9215405e19eSSven Eckelmann 	{ "frag_fwd_bytes" },
9225405e19eSSven Eckelmann 	{ "tt_request_tx" },
9235405e19eSSven Eckelmann 	{ "tt_request_rx" },
9245405e19eSSven Eckelmann 	{ "tt_response_tx" },
9255405e19eSSven Eckelmann 	{ "tt_response_rx" },
9265405e19eSSven Eckelmann 	{ "tt_roam_adv_tx" },
9275405e19eSSven Eckelmann 	{ "tt_roam_adv_rx" },
9285405e19eSSven Eckelmann #ifdef CONFIG_BATMAN_ADV_DAT
9295405e19eSSven Eckelmann 	{ "dat_get_tx" },
9305405e19eSSven Eckelmann 	{ "dat_get_rx" },
9315405e19eSSven Eckelmann 	{ "dat_put_tx" },
9325405e19eSSven Eckelmann 	{ "dat_put_rx" },
9335405e19eSSven Eckelmann 	{ "dat_cached_reply_tx" },
9345405e19eSSven Eckelmann #endif
9355405e19eSSven Eckelmann #ifdef CONFIG_BATMAN_ADV_NC
9365405e19eSSven Eckelmann 	{ "nc_code" },
9375405e19eSSven Eckelmann 	{ "nc_code_bytes" },
9385405e19eSSven Eckelmann 	{ "nc_recode" },
9395405e19eSSven Eckelmann 	{ "nc_recode_bytes" },
9405405e19eSSven Eckelmann 	{ "nc_buffer" },
9415405e19eSSven Eckelmann 	{ "nc_decode" },
9425405e19eSSven Eckelmann 	{ "nc_decode_bytes" },
9435405e19eSSven Eckelmann 	{ "nc_decode_failed" },
9445405e19eSSven Eckelmann 	{ "nc_sniffed" },
9455405e19eSSven Eckelmann #endif
9465405e19eSSven Eckelmann };
9475405e19eSSven Eckelmann 
batadv_get_strings(struct net_device * dev,u32 stringset,u8 * data)9485405e19eSSven Eckelmann static void batadv_get_strings(struct net_device *dev, u32 stringset, u8 *data)
9495405e19eSSven Eckelmann {
9505405e19eSSven Eckelmann 	if (stringset == ETH_SS_STATS)
9515405e19eSSven Eckelmann 		memcpy(data, batadv_counters_strings,
9525405e19eSSven Eckelmann 		       sizeof(batadv_counters_strings));
9535405e19eSSven Eckelmann }
9545405e19eSSven Eckelmann 
batadv_get_ethtool_stats(struct net_device * dev,struct ethtool_stats * stats,u64 * data)9555405e19eSSven Eckelmann static void batadv_get_ethtool_stats(struct net_device *dev,
9565405e19eSSven Eckelmann 				     struct ethtool_stats *stats, u64 *data)
9575405e19eSSven Eckelmann {
9585405e19eSSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(dev);
9595405e19eSSven Eckelmann 	int i;
9605405e19eSSven Eckelmann 
9615405e19eSSven Eckelmann 	for (i = 0; i < BATADV_CNT_NUM; i++)
9625405e19eSSven Eckelmann 		data[i] = batadv_sum_counter(bat_priv, i);
9635405e19eSSven Eckelmann }
9645405e19eSSven Eckelmann 
batadv_get_sset_count(struct net_device * dev,int stringset)9655405e19eSSven Eckelmann static int batadv_get_sset_count(struct net_device *dev, int stringset)
9665405e19eSSven Eckelmann {
9675405e19eSSven Eckelmann 	if (stringset == ETH_SS_STATS)
9685405e19eSSven Eckelmann 		return BATADV_CNT_NUM;
9695405e19eSSven Eckelmann 
9705405e19eSSven Eckelmann 	return -EOPNOTSUPP;
9715405e19eSSven Eckelmann }
9725405e19eSSven Eckelmann 
9735405e19eSSven Eckelmann static const struct ethtool_ops batadv_ethtool_ops = {
9745405e19eSSven Eckelmann 	.get_drvinfo = batadv_get_drvinfo,
9755405e19eSSven Eckelmann 	.get_link = ethtool_op_get_link,
9765405e19eSSven Eckelmann 	.get_strings = batadv_get_strings,
9775405e19eSSven Eckelmann 	.get_ethtool_stats = batadv_get_ethtool_stats,
9785405e19eSSven Eckelmann 	.get_sset_count = batadv_get_sset_count,
9795405e19eSSven Eckelmann };
9805405e19eSSven Eckelmann 
98137130293SSven Eckelmann /**
9827e9a8c2cSSven Eckelmann  * batadv_softif_free() - Deconstructor of batadv_soft_interface
983b3246020SSven Eckelmann  * @dev: Device to cleanup and remove
984b3246020SSven Eckelmann  */
batadv_softif_free(struct net_device * dev)985b3246020SSven Eckelmann static void batadv_softif_free(struct net_device *dev)
986b3246020SSven Eckelmann {
987b3246020SSven Eckelmann 	batadv_mesh_free(dev);
9880c501345SAntonio Quartulli 
9890c501345SAntonio Quartulli 	/* some scheduled RCU callbacks need the bat_priv struct to accomplish
9900c501345SAntonio Quartulli 	 * their tasks. Wait for them all to be finished before freeing the
9910c501345SAntonio Quartulli 	 * netdev and its private data (bat_priv)
9920c501345SAntonio Quartulli 	 */
9930c501345SAntonio Quartulli 	rcu_barrier();
994b3246020SSven Eckelmann }
995b3246020SSven Eckelmann 
996b3246020SSven Eckelmann /**
9977e9a8c2cSSven Eckelmann  * batadv_softif_init_early() - early stage initialization of soft interface
99837130293SSven Eckelmann  * @dev: registered network device to modify
99937130293SSven Eckelmann  */
batadv_softif_init_early(struct net_device * dev)100037130293SSven Eckelmann static void batadv_softif_init_early(struct net_device *dev)
100137130293SSven Eckelmann {
100237130293SSven Eckelmann 	ether_setup(dev);
100337130293SSven Eckelmann 
100437130293SSven Eckelmann 	dev->netdev_ops = &batadv_netdev_ops;
1005cf124db5SDavid S. Miller 	dev->needs_free_netdev = true;
1006cf124db5SDavid S. Miller 	dev->priv_destructor = batadv_softif_free;
10070d21cdaaSAndrew Lunn 	dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_NETNS_LOCAL;
1008a7ea49afSSven Eckelmann 	dev->features |= NETIF_F_LLTX;
1009cdf73703SPhil Sutter 	dev->priv_flags |= IFF_NO_QUEUE;
101037130293SSven Eckelmann 
101137130293SSven Eckelmann 	/* can't call min_mtu, because the needed variables
101237130293SSven Eckelmann 	 * have not been initialized yet
101337130293SSven Eckelmann 	 */
101437130293SSven Eckelmann 	dev->mtu = ETH_DATA_LEN;
101537130293SSven Eckelmann 
101637130293SSven Eckelmann 	/* generate random address */
101737130293SSven Eckelmann 	eth_hw_addr_random(dev);
101837130293SSven Eckelmann 
10197ad24ea4SWilfried Klaebe 	dev->ethtool_ops = &batadv_ethtool_ops;
102037130293SSven Eckelmann }
102137130293SSven Eckelmann 
1022ff15c27cSSven Eckelmann /**
1023128254ceSSven Eckelmann  * batadv_softif_validate() - validate configuration of new batadv link
1024128254ceSSven Eckelmann  * @tb: IFLA_INFO_DATA netlink attributes
1025128254ceSSven Eckelmann  * @data: enum batadv_ifla_attrs attributes
1026128254ceSSven Eckelmann  * @extack: extended ACK report struct
1027128254ceSSven Eckelmann  *
1028128254ceSSven Eckelmann  * Return: 0 if successful or error otherwise.
1029128254ceSSven Eckelmann  */
batadv_softif_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1030128254ceSSven Eckelmann static int batadv_softif_validate(struct nlattr *tb[], struct nlattr *data[],
1031128254ceSSven Eckelmann 				  struct netlink_ext_ack *extack)
1032128254ceSSven Eckelmann {
1033a5ad457eSSven Eckelmann 	struct batadv_algo_ops *algo_ops;
1034a5ad457eSSven Eckelmann 
1035a5ad457eSSven Eckelmann 	if (!data)
1036a5ad457eSSven Eckelmann 		return 0;
1037a5ad457eSSven Eckelmann 
1038a5ad457eSSven Eckelmann 	if (data[IFLA_BATADV_ALGO_NAME]) {
1039a5ad457eSSven Eckelmann 		algo_ops = batadv_algo_get(nla_data(data[IFLA_BATADV_ALGO_NAME]));
1040a5ad457eSSven Eckelmann 		if (!algo_ops)
1041a5ad457eSSven Eckelmann 			return -EINVAL;
1042a5ad457eSSven Eckelmann 	}
1043a5ad457eSSven Eckelmann 
1044128254ceSSven Eckelmann 	return 0;
1045128254ceSSven Eckelmann }
1046128254ceSSven Eckelmann 
1047128254ceSSven Eckelmann /**
1048128254ceSSven Eckelmann  * batadv_softif_newlink() - pre-initialize and register new batadv link
1049128254ceSSven Eckelmann  * @src_net: the applicable net namespace
1050128254ceSSven Eckelmann  * @dev: network device to register
1051128254ceSSven Eckelmann  * @tb: IFLA_INFO_DATA netlink attributes
1052128254ceSSven Eckelmann  * @data: enum batadv_ifla_attrs attributes
1053128254ceSSven Eckelmann  * @extack: extended ACK report struct
1054128254ceSSven Eckelmann  *
1055128254ceSSven Eckelmann  * Return: 0 if successful or error otherwise.
1056128254ceSSven Eckelmann  */
batadv_softif_newlink(struct net * src_net,struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1057128254ceSSven Eckelmann static int batadv_softif_newlink(struct net *src_net, struct net_device *dev,
1058128254ceSSven Eckelmann 				 struct nlattr *tb[], struct nlattr *data[],
1059128254ceSSven Eckelmann 				 struct netlink_ext_ack *extack)
1060128254ceSSven Eckelmann {
1061a5ad457eSSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(dev);
1062a5ad457eSSven Eckelmann 	const char *algo_name;
1063a5ad457eSSven Eckelmann 	int err;
1064a5ad457eSSven Eckelmann 
1065a5ad457eSSven Eckelmann 	if (data && data[IFLA_BATADV_ALGO_NAME]) {
1066a5ad457eSSven Eckelmann 		algo_name = nla_data(data[IFLA_BATADV_ALGO_NAME]);
1067a5ad457eSSven Eckelmann 		err = batadv_algo_select(bat_priv, algo_name);
1068a5ad457eSSven Eckelmann 		if (err)
1069a5ad457eSSven Eckelmann 			return -EINVAL;
1070a5ad457eSSven Eckelmann 	}
1071a5ad457eSSven Eckelmann 
1072128254ceSSven Eckelmann 	return register_netdevice(dev);
1073128254ceSSven Eckelmann }
1074128254ceSSven Eckelmann 
1075128254ceSSven Eckelmann /**
10767e9a8c2cSSven Eckelmann  * batadv_softif_destroy_netlink() - deletion of batadv_soft_interface via
10777e9a8c2cSSven Eckelmann  *  netlink
1078a4ac28c0SSven Eckelmann  * @soft_iface: the to-be-removed batman-adv interface
1079a4ac28c0SSven Eckelmann  * @head: list pointer
1080a4ac28c0SSven Eckelmann  */
batadv_softif_destroy_netlink(struct net_device * soft_iface,struct list_head * head)1081a4ac28c0SSven Eckelmann static void batadv_softif_destroy_netlink(struct net_device *soft_iface,
1082a4ac28c0SSven Eckelmann 					  struct list_head *head)
1083a4ac28c0SSven Eckelmann {
1084420cb1b7SSven Eckelmann 	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
1085a4ac28c0SSven Eckelmann 	struct batadv_hard_iface *hard_iface;
1086420cb1b7SSven Eckelmann 	struct batadv_softif_vlan *vlan;
1087a4ac28c0SSven Eckelmann 
1088a4ac28c0SSven Eckelmann 	list_for_each_entry(hard_iface, &batadv_hardif_list, list) {
1089a4ac28c0SSven Eckelmann 		if (hard_iface->soft_iface == soft_iface)
1090a962cb29SSven Eckelmann 			batadv_hardif_disable_interface(hard_iface);
1091a4ac28c0SSven Eckelmann 	}
1092a4ac28c0SSven Eckelmann 
1093420cb1b7SSven Eckelmann 	/* destroy the "untagged" VLAN */
1094420cb1b7SSven Eckelmann 	vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS);
1095420cb1b7SSven Eckelmann 	if (vlan) {
1096420cb1b7SSven Eckelmann 		batadv_softif_destroy_vlan(bat_priv, vlan);
1097420cb1b7SSven Eckelmann 		batadv_softif_vlan_put(vlan);
1098420cb1b7SSven Eckelmann 	}
1099420cb1b7SSven Eckelmann 
1100a4ac28c0SSven Eckelmann 	unregister_netdevice_queue(soft_iface, head);
1101a4ac28c0SSven Eckelmann }
1102a4ac28c0SSven Eckelmann 
1103ff15c27cSSven Eckelmann /**
1104ff15c27cSSven Eckelmann  * batadv_softif_is_valid() - Check whether device is a batadv soft interface
1105ff15c27cSSven Eckelmann  * @net_dev: device which should be checked
1106ff15c27cSSven Eckelmann  *
1107ff15c27cSSven Eckelmann  * Return: true when net_dev is a batman-adv interface, false otherwise
1108ff15c27cSSven Eckelmann  */
batadv_softif_is_valid(const struct net_device * net_dev)11094b426b10SSven Eckelmann bool batadv_softif_is_valid(const struct net_device *net_dev)
1110e44d8fe2SSven Eckelmann {
11110294ca0dSSven Eckelmann 	if (net_dev->netdev_ops->ndo_start_xmit == batadv_interface_tx)
11124b426b10SSven Eckelmann 		return true;
1113e44d8fe2SSven Eckelmann 
11144b426b10SSven Eckelmann 	return false;
1115e44d8fe2SSven Eckelmann }
1116e44d8fe2SSven Eckelmann 
1117128254ceSSven Eckelmann static const struct nla_policy batadv_ifla_policy[IFLA_BATADV_MAX + 1] = {
1118a5ad457eSSven Eckelmann 	[IFLA_BATADV_ALGO_NAME]	= { .type = NLA_NUL_STRING },
1119128254ceSSven Eckelmann };
1120128254ceSSven Eckelmann 
1121a4ac28c0SSven Eckelmann struct rtnl_link_ops batadv_link_ops __read_mostly = {
1122a4ac28c0SSven Eckelmann 	.kind		= "batadv",
1123a4ac28c0SSven Eckelmann 	.priv_size	= sizeof(struct batadv_priv),
1124a4ac28c0SSven Eckelmann 	.setup		= batadv_softif_init_early,
1125128254ceSSven Eckelmann 	.maxtype	= IFLA_BATADV_MAX,
1126128254ceSSven Eckelmann 	.policy		= batadv_ifla_policy,
1127128254ceSSven Eckelmann 	.validate	= batadv_softif_validate,
1128128254ceSSven Eckelmann 	.newlink	= batadv_softif_newlink,
1129a4ac28c0SSven Eckelmann 	.dellink	= batadv_softif_destroy_netlink,
1130a4ac28c0SSven Eckelmann };
1131