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