xref: /openbmc/linux/net/8021q/vlan_dev.c (revision 65c9fde1)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /* -*- linux-c -*-
31da177e4SLinus Torvalds  * INET		802.1Q VLAN
41da177e4SLinus Torvalds  *		Ethernet-type device handling.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Authors:	Ben Greear <greearb@candelatech.com>
7ad712087SPatrick McHardy  *              Please send support related email to: netdev@vger.kernel.org
81da177e4SLinus Torvalds  *              VLAN Home Page: http://www.candelatech.com/~greear/vlan.html
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * Fixes:       Mar 22 2001: Martin Bokaemper <mbokaemper@unispherenetworks.com>
111da177e4SLinus Torvalds  *                - reset skb->pkt_type on incoming packets when MAC was changed
121da177e4SLinus Torvalds  *                - see that changed MAC is saddr for outgoing packets
131da177e4SLinus Torvalds  *              Oct 20, 2001:  Ard van Breeman:
141da177e4SLinus Torvalds  *                - Fix MC-list, finally.
151da177e4SLinus Torvalds  *                - Flush MC-list on VLAN destroy.
161da177e4SLinus Torvalds  */
171da177e4SLinus Torvalds 
18afab2d29SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19afab2d29SJoe Perches 
201da177e4SLinus Torvalds #include <linux/module.h>
215a0e3ad6STejun Heo #include <linux/slab.h>
221da177e4SLinus Torvalds #include <linux/skbuff.h>
231da177e4SLinus Torvalds #include <linux/netdevice.h>
2437dd9255SRichard Cochran #include <linux/net_tstamp.h>
251da177e4SLinus Torvalds #include <linux/etherdevice.h>
2675b8846aSPatrick McHardy #include <linux/ethtool.h>
27ec1d8ccbSHangbin Liu #include <linux/phy.h>
281da177e4SLinus Torvalds #include <net/arp.h>
29abff3e5eSEmeel Hakim #include <net/macsec.h>
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds #include "vlan.h"
321da177e4SLinus Torvalds #include "vlanproc.h"
331da177e4SLinus Torvalds #include <linux/if_vlan.h>
346d4cdf47SBenjamin LaHaise #include <linux/netpoll.h>
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds /*
371da177e4SLinus Torvalds  *	Create the VLAN header for an arbitrary protocol layer
381da177e4SLinus Torvalds  *
391da177e4SLinus Torvalds  *	saddr=NULL	means use device source address
401da177e4SLinus Torvalds  *	daddr=NULL	means leave destination address (eg unresolved arp)
411da177e4SLinus Torvalds  *
421da177e4SLinus Torvalds  *  This is called when the SKB is moving down the stack towards the
431da177e4SLinus Torvalds  *  physical devices.
441da177e4SLinus Torvalds  */
vlan_dev_hard_header(struct sk_buff * skb,struct net_device * dev,unsigned short type,const void * daddr,const void * saddr,unsigned int len)45ef3eb3e5SPatrick McHardy static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
463b04dddeSStephen Hemminger 				unsigned short type,
47ef3eb3e5SPatrick McHardy 				const void *daddr, const void *saddr,
48ef3eb3e5SPatrick McHardy 				unsigned int len)
491da177e4SLinus Torvalds {
501fd9b1fcSPatrick McHardy 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
511da177e4SLinus Torvalds 	struct vlan_hdr *vhdr;
521349fe9aSPatrick McHardy 	unsigned int vhdrlen = 0;
539bb8582eSPatrick McHardy 	u16 vlan_tci = 0;
541349fe9aSPatrick McHardy 	int rc;
551da177e4SLinus Torvalds 
560c0667a8SWang Sheng-Hui 	if (!(vlan->flags & VLAN_FLAG_REORDER_HDR)) {
57d58ff351SJohannes Berg 		vhdr = skb_push(skb, VLAN_HLEN);
581da177e4SLinus Torvalds 
590c0667a8SWang Sheng-Hui 		vlan_tci = vlan->vlan_id;
60e267cb96SDavid S. Miller 		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb->priority);
619bb8582eSPatrick McHardy 		vhdr->h_vlan_TCI = htons(vlan_tci);
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 		/*
64bf9ae538SOctavian Purdila 		 *  Set the protocol type. For a packet of type ETH_P_802_3/2 we
65bf9ae538SOctavian Purdila 		 *  put the length in here instead.
661da177e4SLinus Torvalds 		 */
67bf9ae538SOctavian Purdila 		if (type != ETH_P_802_3 && type != ETH_P_802_2)
681da177e4SLinus Torvalds 			vhdr->h_vlan_encapsulated_proto = htons(type);
692029cc2cSPatrick McHardy 		else
701da177e4SLinus Torvalds 			vhdr->h_vlan_encapsulated_proto = htons(len);
71279e172aSJerome Borsboom 
721fd9b1fcSPatrick McHardy 		skb->protocol = vlan->vlan_proto;
731fd9b1fcSPatrick McHardy 		type = ntohs(vlan->vlan_proto);
741349fe9aSPatrick McHardy 		vhdrlen = VLAN_HLEN;
751da177e4SLinus Torvalds 	}
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 	/* Before delegating work to the lower layer, enter our MAC-address */
781da177e4SLinus Torvalds 	if (saddr == NULL)
791da177e4SLinus Torvalds 		saddr = dev->dev_addr;
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds 	/* Now make the underlying real hard header */
820c0667a8SWang Sheng-Hui 	dev = vlan->real_dev;
831349fe9aSPatrick McHardy 	rc = dev_hard_header(skb, dev, type, daddr, saddr, len + vhdrlen);
840c4e8581SStephen Hemminger 	if (rc > 0)
851349fe9aSPatrick McHardy 		rc += vhdrlen;
861da177e4SLinus Torvalds 	return rc;
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds 
vlan_netpoll_send_skb(struct vlan_dev_priv * vlan,struct sk_buff * skb)896eacf8adSAmerigo Wang static inline netdev_tx_t vlan_netpoll_send_skb(struct vlan_dev_priv *vlan, struct sk_buff *skb)
906eacf8adSAmerigo Wang {
916eacf8adSAmerigo Wang #ifdef CONFIG_NET_POLL_CONTROLLER
92f78ed220SEric Dumazet 	return netpoll_send_skb(vlan->netpoll, skb);
936eacf8adSAmerigo Wang #else
946eacf8adSAmerigo Wang 	BUG();
956eacf8adSAmerigo Wang 	return NETDEV_TX_OK;
96f78ed220SEric Dumazet #endif
976eacf8adSAmerigo Wang }
986eacf8adSAmerigo Wang 
vlan_dev_hard_start_xmit(struct sk_buff * skb,struct net_device * dev)996fef4c0cSStephen Hemminger static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
1006fef4c0cSStephen Hemminger 					    struct net_device *dev)
1011da177e4SLinus Torvalds {
1026eacf8adSAmerigo Wang 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
1031da177e4SLinus Torvalds 	struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data);
1041a123a31SEric Dumazet 	unsigned int len;
1051a123a31SEric Dumazet 	int ret;
10655b01e86SDavid S. Miller 
1071da177e4SLinus Torvalds 	/* Handle non-VLAN frames if they are sent to us, for example by DHCP.
1081da177e4SLinus Torvalds 	 *
1091da177e4SLinus Torvalds 	 * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING
1101da177e4SLinus Torvalds 	 * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs...
1111da177e4SLinus Torvalds 	 */
112dacab578SEric Dumazet 	if (vlan->flags & VLAN_FLAG_REORDER_HDR ||
113dacab578SEric Dumazet 	    veth->h_vlan_proto != vlan->vlan_proto) {
1149bb8582eSPatrick McHardy 		u16 vlan_tci;
1156eacf8adSAmerigo Wang 		vlan_tci = vlan->vlan_id;
116e267cb96SDavid S. Miller 		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb->priority);
117b960a0acSJiri Pirko 		__vlan_hwaccel_put_tag(skb, vlan->vlan_proto, vlan_tci);
118636e19a3SJohn Fastabend 	}
1191da177e4SLinus Torvalds 
1206eacf8adSAmerigo Wang 	skb->dev = vlan->real_dev;
1211a123a31SEric Dumazet 	len = skb->len;
1226eacf8adSAmerigo Wang 	if (unlikely(netpoll_tx_running(dev)))
1236eacf8adSAmerigo Wang 		return vlan_netpoll_send_skb(vlan, skb);
1246eacf8adSAmerigo Wang 
1251a123a31SEric Dumazet 	ret = dev_queue_xmit(skb);
1261a123a31SEric Dumazet 
1272d6c9ffcSEric Dumazet 	if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
1284af429d2SEric Dumazet 		struct vlan_pcpu_stats *stats;
1294af429d2SEric Dumazet 
1306eacf8adSAmerigo Wang 		stats = this_cpu_ptr(vlan->vlan_pcpu_stats);
1314af429d2SEric Dumazet 		u64_stats_update_begin(&stats->syncp);
13209cca53cSEric Dumazet 		u64_stats_inc(&stats->tx_packets);
13309cca53cSEric Dumazet 		u64_stats_add(&stats->tx_bytes, len);
134307f73dfSWei Yongjun 		u64_stats_update_end(&stats->syncp);
1354af429d2SEric Dumazet 	} else {
1366eacf8adSAmerigo Wang 		this_cpu_inc(vlan->vlan_pcpu_stats->tx_dropped);
1374af429d2SEric Dumazet 	}
1381a123a31SEric Dumazet 
139cbbef5e1SPatrick McHardy 	return ret;
1401da177e4SLinus Torvalds }
1411da177e4SLinus Torvalds 
vlan_dev_change_mtu(struct net_device * dev,int new_mtu)142ef3eb3e5SPatrick McHardy static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu)
1431da177e4SLinus Torvalds {
14418d3df3eSPaolo Abeni 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
14518d3df3eSPaolo Abeni 	unsigned int max_mtu = real_dev->mtu;
14618d3df3eSPaolo Abeni 
14718d3df3eSPaolo Abeni 	if (netif_reduces_vlan_mtu(real_dev))
14818d3df3eSPaolo Abeni 		max_mtu -= VLAN_HLEN;
14918d3df3eSPaolo Abeni 	if (max_mtu < new_mtu)
1501da177e4SLinus Torvalds 		return -ERANGE;
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 	dev->mtu = new_mtu;
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 	return 0;
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds 
vlan_dev_set_ingress_priority(const struct net_device * dev,u32 skb_prio,u16 vlan_prio)157c17d8874SPatrick McHardy void vlan_dev_set_ingress_priority(const struct net_device *dev,
1589bb8582eSPatrick McHardy 				   u32 skb_prio, u16 vlan_prio)
1591da177e4SLinus Torvalds {
1607da82c06SJiri Pirko 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
161b020cb48SPatrick McHardy 
162b020cb48SPatrick McHardy 	if (vlan->ingress_priority_map[vlan_prio & 0x7] && !skb_prio)
163b020cb48SPatrick McHardy 		vlan->nr_ingress_mappings--;
164b020cb48SPatrick McHardy 	else if (!vlan->ingress_priority_map[vlan_prio & 0x7] && skb_prio)
165b020cb48SPatrick McHardy 		vlan->nr_ingress_mappings++;
166b020cb48SPatrick McHardy 
167b020cb48SPatrick McHardy 	vlan->ingress_priority_map[vlan_prio & 0x7] = skb_prio;
1681da177e4SLinus Torvalds }
1691da177e4SLinus Torvalds 
vlan_dev_set_egress_priority(const struct net_device * dev,u32 skb_prio,u16 vlan_prio)170c17d8874SPatrick McHardy int vlan_dev_set_egress_priority(const struct net_device *dev,
1719bb8582eSPatrick McHardy 				 u32 skb_prio, u16 vlan_prio)
1721da177e4SLinus Torvalds {
1737da82c06SJiri Pirko 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
1741da177e4SLinus Torvalds 	struct vlan_priority_tci_mapping *mp = NULL;
1751da177e4SLinus Torvalds 	struct vlan_priority_tci_mapping *np;
17605423b24SEric Dumazet 	u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK;
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds 	/* See if a priority mapping exists.. */
179b020cb48SPatrick McHardy 	mp = vlan->egress_priority_map[skb_prio & 0xF];
1801da177e4SLinus Torvalds 	while (mp) {
1811da177e4SLinus Torvalds 		if (mp->priority == skb_prio) {
182b020cb48SPatrick McHardy 			if (mp->vlan_qos && !vlan_qos)
183b020cb48SPatrick McHardy 				vlan->nr_egress_mappings--;
184b020cb48SPatrick McHardy 			else if (!mp->vlan_qos && vlan_qos)
185b020cb48SPatrick McHardy 				vlan->nr_egress_mappings++;
186b020cb48SPatrick McHardy 			mp->vlan_qos = vlan_qos;
1871da177e4SLinus Torvalds 			return 0;
1881da177e4SLinus Torvalds 		}
1891da177e4SLinus Torvalds 		mp = mp->next;
1901da177e4SLinus Torvalds 	}
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds 	/* Create a new mapping then. */
193b020cb48SPatrick McHardy 	mp = vlan->egress_priority_map[skb_prio & 0xF];
1941da177e4SLinus Torvalds 	np = kmalloc(sizeof(struct vlan_priority_tci_mapping), GFP_KERNEL);
195c17d8874SPatrick McHardy 	if (!np)
196c17d8874SPatrick McHardy 		return -ENOBUFS;
197c17d8874SPatrick McHardy 
1981da177e4SLinus Torvalds 	np->next = mp;
1991da177e4SLinus Torvalds 	np->priority = skb_prio;
200b020cb48SPatrick McHardy 	np->vlan_qos = vlan_qos;
2013e3aac49SEric Dumazet 	/* Before inserting this element in hash table, make sure all its fields
2023e3aac49SEric Dumazet 	 * are committed to memory.
203e267cb96SDavid S. Miller 	 * coupled with smp_rmb() in vlan_dev_get_egress_qos_mask()
2043e3aac49SEric Dumazet 	 */
2053e3aac49SEric Dumazet 	smp_wmb();
206b020cb48SPatrick McHardy 	vlan->egress_priority_map[skb_prio & 0xF] = np;
207b020cb48SPatrick McHardy 	if (vlan_qos)
208b020cb48SPatrick McHardy 		vlan->nr_egress_mappings++;
2091da177e4SLinus Torvalds 	return 0;
2101da177e4SLinus Torvalds }
2111da177e4SLinus Torvalds 
21284a2fba2SSun Lianwen /* Flags are defined in the vlan_flags enum in
21384a2fba2SSun Lianwen  * include/uapi/linux/if_vlan.h file.
21484a2fba2SSun Lianwen  */
vlan_dev_change_flags(const struct net_device * dev,u32 flags,u32 mask)215b3ce0325SPatrick McHardy int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask)
2161da177e4SLinus Torvalds {
2177da82c06SJiri Pirko 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
218b3ce0325SPatrick McHardy 	u32 old_flags = vlan->flags;
219b3ce0325SPatrick McHardy 
2205e756593SPatrick McHardy 	if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
2218c8b3458SMike Manning 		     VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP |
2228c8b3458SMike Manning 		     VLAN_FLAG_BRIDGE_BINDING))
2231da177e4SLinus Torvalds 		return -EINVAL;
224b3ce0325SPatrick McHardy 
225b3ce0325SPatrick McHardy 	vlan->flags = (old_flags & ~mask) | (flags & mask);
22670c03b49SPatrick McHardy 
22770c03b49SPatrick McHardy 	if (netif_running(dev) && (vlan->flags ^ old_flags) & VLAN_FLAG_GVRP) {
22870c03b49SPatrick McHardy 		if (vlan->flags & VLAN_FLAG_GVRP)
22970c03b49SPatrick McHardy 			vlan_gvrp_request_join(dev);
23070c03b49SPatrick McHardy 		else
23170c03b49SPatrick McHardy 			vlan_gvrp_request_leave(dev);
23270c03b49SPatrick McHardy 	}
23386fbe9bbSDavid Ward 
23486fbe9bbSDavid Ward 	if (netif_running(dev) && (vlan->flags ^ old_flags) & VLAN_FLAG_MVRP) {
23586fbe9bbSDavid Ward 		if (vlan->flags & VLAN_FLAG_MVRP)
23686fbe9bbSDavid Ward 			vlan_mvrp_request_join(dev);
23786fbe9bbSDavid Ward 		else
23886fbe9bbSDavid Ward 			vlan_mvrp_request_leave(dev);
23986fbe9bbSDavid Ward 	}
240b3ce0325SPatrick McHardy 	return 0;
2411da177e4SLinus Torvalds }
2421da177e4SLinus Torvalds 
vlan_dev_get_realdev_name(const struct net_device * dev,char * result,size_t size)2439c153d38SKees Cook void vlan_dev_get_realdev_name(const struct net_device *dev, char *result, size_t size)
2441da177e4SLinus Torvalds {
2459c153d38SKees Cook 	strscpy_pad(result, vlan_dev_priv(dev)->real_dev->name, size);
2461da177e4SLinus Torvalds }
2471da177e4SLinus Torvalds 
vlan_dev_inherit_address(struct net_device * dev,struct net_device * real_dev)248308453aaSMike Manning bool vlan_dev_inherit_address(struct net_device *dev,
249308453aaSMike Manning 			      struct net_device *real_dev)
250308453aaSMike Manning {
251308453aaSMike Manning 	if (dev->addr_assign_type != NET_ADDR_STOLEN)
252308453aaSMike Manning 		return false;
253308453aaSMike Manning 
254e35b8d7dSJakub Kicinski 	eth_hw_addr_set(dev, real_dev->dev_addr);
255308453aaSMike Manning 	call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
256308453aaSMike Manning 	return true;
257308453aaSMike Manning }
258308453aaSMike Manning 
vlan_dev_open(struct net_device * dev)259ef3eb3e5SPatrick McHardy static int vlan_dev_open(struct net_device *dev)
2601da177e4SLinus Torvalds {
2617da82c06SJiri Pirko 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
2628c979c26SPatrick McHardy 	struct net_device *real_dev = vlan->real_dev;
2638c979c26SPatrick McHardy 	int err;
2648c979c26SPatrick McHardy 
2655e756593SPatrick McHardy 	if (!(real_dev->flags & IFF_UP) &&
2665e756593SPatrick McHardy 	    !(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
2671da177e4SLinus Torvalds 		return -ENETDOWN;
2681da177e4SLinus Torvalds 
269308453aaSMike Manning 	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr) &&
270308453aaSMike Manning 	    !vlan_dev_inherit_address(dev, real_dev)) {
271a748ee24SJiri Pirko 		err = dev_uc_add(real_dev, dev->dev_addr);
2728c979c26SPatrick McHardy 		if (err < 0)
27389146504SWang Chen 			goto out;
2748c979c26SPatrick McHardy 	}
2758c979c26SPatrick McHardy 
27689146504SWang Chen 	if (dev->flags & IFF_ALLMULTI) {
27789146504SWang Chen 		err = dev_set_allmulti(real_dev, 1);
27889146504SWang Chen 		if (err < 0)
27989146504SWang Chen 			goto del_unicast;
28089146504SWang Chen 	}
28189146504SWang Chen 	if (dev->flags & IFF_PROMISC) {
28289146504SWang Chen 		err = dev_set_promiscuity(real_dev, 1);
28389146504SWang Chen 		if (err < 0)
28489146504SWang Chen 			goto clear_allmulti;
28589146504SWang Chen 	}
28689146504SWang Chen 
28707fc67beSJoe Perches 	ether_addr_copy(vlan->real_dev_addr, real_dev->dev_addr);
2886c78dcbdSPatrick McHardy 
28970c03b49SPatrick McHardy 	if (vlan->flags & VLAN_FLAG_GVRP)
29070c03b49SPatrick McHardy 		vlan_gvrp_request_join(dev);
29170c03b49SPatrick McHardy 
29286fbe9bbSDavid Ward 	if (vlan->flags & VLAN_FLAG_MVRP)
29386fbe9bbSDavid Ward 		vlan_mvrp_request_join(dev);
29486fbe9bbSDavid Ward 
29576052d8cSMike Manning 	if (netif_carrier_ok(real_dev) &&
29676052d8cSMike Manning 	    !(vlan->flags & VLAN_FLAG_BRIDGE_BINDING))
297adc667e8SJay Vosburgh 		netif_carrier_on(dev);
2981da177e4SLinus Torvalds 	return 0;
29989146504SWang Chen 
30089146504SWang Chen clear_allmulti:
30189146504SWang Chen 	if (dev->flags & IFF_ALLMULTI)
30289146504SWang Chen 		dev_set_allmulti(real_dev, -1);
30389146504SWang Chen del_unicast:
30453a2b3a1SJoe Perches 	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
305a748ee24SJiri Pirko 		dev_uc_del(real_dev, dev->dev_addr);
30689146504SWang Chen out:
307adc667e8SJay Vosburgh 	netif_carrier_off(dev);
30889146504SWang Chen 	return err;
3091da177e4SLinus Torvalds }
3101da177e4SLinus Torvalds 
vlan_dev_stop(struct net_device * dev)311ef3eb3e5SPatrick McHardy static int vlan_dev_stop(struct net_device *dev)
3121da177e4SLinus Torvalds {
3137da82c06SJiri Pirko 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
31470c03b49SPatrick McHardy 	struct net_device *real_dev = vlan->real_dev;
31570c03b49SPatrick McHardy 
31656addd6eSPatrick McHardy 	dev_mc_unsync(real_dev, dev);
317a748ee24SJiri Pirko 	dev_uc_unsync(real_dev, dev);
3186c78dcbdSPatrick McHardy 	if (dev->flags & IFF_ALLMULTI)
3196c78dcbdSPatrick McHardy 		dev_set_allmulti(real_dev, -1);
3206c78dcbdSPatrick McHardy 	if (dev->flags & IFF_PROMISC)
3216c78dcbdSPatrick McHardy 		dev_set_promiscuity(real_dev, -1);
3226c78dcbdSPatrick McHardy 
32353a2b3a1SJoe Perches 	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
324a748ee24SJiri Pirko 		dev_uc_del(real_dev, dev->dev_addr);
3258c979c26SPatrick McHardy 
32676052d8cSMike Manning 	if (!(vlan->flags & VLAN_FLAG_BRIDGE_BINDING))
327adc667e8SJay Vosburgh 		netif_carrier_off(dev);
3281da177e4SLinus Torvalds 	return 0;
3291da177e4SLinus Torvalds }
3301da177e4SLinus Torvalds 
vlan_dev_set_mac_address(struct net_device * dev,void * p)331ef3eb3e5SPatrick McHardy static int vlan_dev_set_mac_address(struct net_device *dev, void *p)
33239aaac11SPatrick McHardy {
3337da82c06SJiri Pirko 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
33439aaac11SPatrick McHardy 	struct sockaddr *addr = p;
33539aaac11SPatrick McHardy 	int err;
33639aaac11SPatrick McHardy 
33739aaac11SPatrick McHardy 	if (!is_valid_ether_addr(addr->sa_data))
33839aaac11SPatrick McHardy 		return -EADDRNOTAVAIL;
33939aaac11SPatrick McHardy 
34039aaac11SPatrick McHardy 	if (!(dev->flags & IFF_UP))
34139aaac11SPatrick McHardy 		goto out;
34239aaac11SPatrick McHardy 
34353a2b3a1SJoe Perches 	if (!ether_addr_equal(addr->sa_data, real_dev->dev_addr)) {
344a748ee24SJiri Pirko 		err = dev_uc_add(real_dev, addr->sa_data);
34539aaac11SPatrick McHardy 		if (err < 0)
34639aaac11SPatrick McHardy 			return err;
34739aaac11SPatrick McHardy 	}
34839aaac11SPatrick McHardy 
34953a2b3a1SJoe Perches 	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
350a748ee24SJiri Pirko 		dev_uc_del(real_dev, dev->dev_addr);
35139aaac11SPatrick McHardy 
35239aaac11SPatrick McHardy out:
353e35b8d7dSJakub Kicinski 	eth_hw_addr_set(dev, addr->sa_data);
35439aaac11SPatrick McHardy 	return 0;
35539aaac11SPatrick McHardy }
35639aaac11SPatrick McHardy 
vlan_hwtstamp_get(struct net_device * dev,struct kernel_hwtstamp_config * cfg)357*65c9fde1SMaxim Georgiev static int vlan_hwtstamp_get(struct net_device *dev,
358*65c9fde1SMaxim Georgiev 			     struct kernel_hwtstamp_config *cfg)
359*65c9fde1SMaxim Georgiev {
360*65c9fde1SMaxim Georgiev 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
361*65c9fde1SMaxim Georgiev 
362*65c9fde1SMaxim Georgiev 	return generic_hwtstamp_get_lower(real_dev, cfg);
363*65c9fde1SMaxim Georgiev }
364*65c9fde1SMaxim Georgiev 
vlan_hwtstamp_set(struct net_device * dev,struct kernel_hwtstamp_config * cfg,struct netlink_ext_ack * extack)365*65c9fde1SMaxim Georgiev static int vlan_hwtstamp_set(struct net_device *dev,
366*65c9fde1SMaxim Georgiev 			     struct kernel_hwtstamp_config *cfg,
367*65c9fde1SMaxim Georgiev 			     struct netlink_ext_ack *extack)
368*65c9fde1SMaxim Georgiev {
369*65c9fde1SMaxim Georgiev 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
370*65c9fde1SMaxim Georgiev 
371*65c9fde1SMaxim Georgiev 	if (!net_eq(dev_net(dev), dev_net(real_dev)))
372*65c9fde1SMaxim Georgiev 		return -EOPNOTSUPP;
373*65c9fde1SMaxim Georgiev 
374*65c9fde1SMaxim Georgiev 	return generic_hwtstamp_set_lower(real_dev, cfg, extack);
375*65c9fde1SMaxim Georgiev }
376*65c9fde1SMaxim Georgiev 
vlan_dev_ioctl(struct net_device * dev,struct ifreq * ifr,int cmd)377ef3eb3e5SPatrick McHardy static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
3781da177e4SLinus Torvalds {
3797da82c06SJiri Pirko 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
380656299f7SStephen Hemminger 	const struct net_device_ops *ops = real_dev->netdev_ops;
3811da177e4SLinus Torvalds 	struct ifreq ifrr;
3821da177e4SLinus Torvalds 	int err = -EOPNOTSUPP;
3831da177e4SLinus Torvalds 
3849c153d38SKees Cook 	strscpy_pad(ifrr.ifr_name, real_dev->name, IFNAMSIZ);
3851da177e4SLinus Torvalds 	ifrr.ifr_ifru = ifr->ifr_ifru;
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds 	switch (cmd) {
3881da177e4SLinus Torvalds 	case SIOCGMIIPHY:
3891da177e4SLinus Torvalds 	case SIOCGMIIREG:
3901da177e4SLinus Torvalds 	case SIOCSMIIREG:
391a7605370SArnd Bergmann 		if (netif_device_present(real_dev) && ops->ndo_eth_ioctl)
392a7605370SArnd Bergmann 			err = ops->ndo_eth_ioctl(real_dev, &ifrr, cmd);
3931da177e4SLinus Torvalds 		break;
3941da177e4SLinus Torvalds 	}
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 	if (!err)
3971da177e4SLinus Torvalds 		ifr->ifr_ifru = ifrr.ifr_ifru;
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds 	return err;
4001da177e4SLinus Torvalds }
4011da177e4SLinus Torvalds 
vlan_dev_neigh_setup(struct net_device * dev,struct neigh_parms * pa)402cc883d16SFrank Blaschka static int vlan_dev_neigh_setup(struct net_device *dev, struct neigh_parms *pa)
403cc883d16SFrank Blaschka {
4047da82c06SJiri Pirko 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
405cc883d16SFrank Blaschka 	const struct net_device_ops *ops = real_dev->netdev_ops;
406cc883d16SFrank Blaschka 	int err = 0;
407cc883d16SFrank Blaschka 
408cc883d16SFrank Blaschka 	if (netif_device_present(real_dev) && ops->ndo_neigh_setup)
4099d40bbdaSDavid S. Miller 		err = ops->ndo_neigh_setup(real_dev, pa);
410cc883d16SFrank Blaschka 
411cc883d16SFrank Blaschka 	return err;
412cc883d16SFrank Blaschka }
413cc883d16SFrank Blaschka 
414f4d5392eSAmerigo Wang #if IS_ENABLED(CONFIG_FCOE)
vlan_dev_fcoe_ddp_setup(struct net_device * dev,u16 xid,struct scatterlist * sgl,unsigned int sgc)415b85daa53SVasu Dev static int vlan_dev_fcoe_ddp_setup(struct net_device *dev, u16 xid,
416b85daa53SVasu Dev 				   struct scatterlist *sgl, unsigned int sgc)
417b85daa53SVasu Dev {
4187da82c06SJiri Pirko 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
419b85daa53SVasu Dev 	const struct net_device_ops *ops = real_dev->netdev_ops;
420b85daa53SVasu Dev 	int rc = 0;
421b85daa53SVasu Dev 
422b85daa53SVasu Dev 	if (ops->ndo_fcoe_ddp_setup)
423b85daa53SVasu Dev 		rc = ops->ndo_fcoe_ddp_setup(real_dev, xid, sgl, sgc);
424b85daa53SVasu Dev 
425b85daa53SVasu Dev 	return rc;
426b85daa53SVasu Dev }
427b85daa53SVasu Dev 
vlan_dev_fcoe_ddp_done(struct net_device * dev,u16 xid)428b85daa53SVasu Dev static int vlan_dev_fcoe_ddp_done(struct net_device *dev, u16 xid)
429b85daa53SVasu Dev {
4307da82c06SJiri Pirko 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
431b85daa53SVasu Dev 	const struct net_device_ops *ops = real_dev->netdev_ops;
432b85daa53SVasu Dev 	int len = 0;
433b85daa53SVasu Dev 
434b85daa53SVasu Dev 	if (ops->ndo_fcoe_ddp_done)
435b85daa53SVasu Dev 		len = ops->ndo_fcoe_ddp_done(real_dev, xid);
436b85daa53SVasu Dev 
437b85daa53SVasu Dev 	return len;
438b85daa53SVasu Dev }
4390af46d99SYi Zou 
vlan_dev_fcoe_enable(struct net_device * dev)4400af46d99SYi Zou static int vlan_dev_fcoe_enable(struct net_device *dev)
4410af46d99SYi Zou {
4427da82c06SJiri Pirko 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
4430af46d99SYi Zou 	const struct net_device_ops *ops = real_dev->netdev_ops;
4440af46d99SYi Zou 	int rc = -EINVAL;
4450af46d99SYi Zou 
4460af46d99SYi Zou 	if (ops->ndo_fcoe_enable)
4470af46d99SYi Zou 		rc = ops->ndo_fcoe_enable(real_dev);
4480af46d99SYi Zou 	return rc;
4490af46d99SYi Zou }
4500af46d99SYi Zou 
vlan_dev_fcoe_disable(struct net_device * dev)4510af46d99SYi Zou static int vlan_dev_fcoe_disable(struct net_device *dev)
4520af46d99SYi Zou {
4537da82c06SJiri Pirko 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
4540af46d99SYi Zou 	const struct net_device_ops *ops = real_dev->netdev_ops;
4550af46d99SYi Zou 	int rc = -EINVAL;
4560af46d99SYi Zou 
4570af46d99SYi Zou 	if (ops->ndo_fcoe_disable)
4580af46d99SYi Zou 		rc = ops->ndo_fcoe_disable(real_dev);
4590af46d99SYi Zou 	return rc;
4600af46d99SYi Zou }
461d6534799SYi Zou 
vlan_dev_fcoe_ddp_target(struct net_device * dev,u16 xid,struct scatterlist * sgl,unsigned int sgc)4624ea09c9cSYi Zou static int vlan_dev_fcoe_ddp_target(struct net_device *dev, u16 xid,
4634ea09c9cSYi Zou 				    struct scatterlist *sgl, unsigned int sgc)
4644ea09c9cSYi Zou {
4657da82c06SJiri Pirko 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
4664ea09c9cSYi Zou 	const struct net_device_ops *ops = real_dev->netdev_ops;
4674ea09c9cSYi Zou 	int rc = 0;
4684ea09c9cSYi Zou 
4694ea09c9cSYi Zou 	if (ops->ndo_fcoe_ddp_target)
4704ea09c9cSYi Zou 		rc = ops->ndo_fcoe_ddp_target(real_dev, xid, sgl, sgc);
4714ea09c9cSYi Zou 
4724ea09c9cSYi Zou 	return rc;
4734ea09c9cSYi Zou }
474b85daa53SVasu Dev #endif
475b85daa53SVasu Dev 
4760a89eb92SChris Leech #ifdef NETDEV_FCOE_WWNN
vlan_dev_fcoe_get_wwn(struct net_device * dev,u64 * wwn,int type)4770a89eb92SChris Leech static int vlan_dev_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type)
4780a89eb92SChris Leech {
4790a89eb92SChris Leech 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
4800a89eb92SChris Leech 	const struct net_device_ops *ops = real_dev->netdev_ops;
4810a89eb92SChris Leech 	int rc = -EINVAL;
4820a89eb92SChris Leech 
4830a89eb92SChris Leech 	if (ops->ndo_fcoe_get_wwn)
4840a89eb92SChris Leech 		rc = ops->ndo_fcoe_get_wwn(real_dev, wwn, type);
4850a89eb92SChris Leech 	return rc;
4860a89eb92SChris Leech }
4870a89eb92SChris Leech #endif
4880a89eb92SChris Leech 
vlan_dev_change_rx_flags(struct net_device * dev,int change)489ef3eb3e5SPatrick McHardy static void vlan_dev_change_rx_flags(struct net_device *dev, int change)
4906c78dcbdSPatrick McHardy {
4917da82c06SJiri Pirko 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
4926c78dcbdSPatrick McHardy 
493deede2faSMatthijs Kooijman 	if (dev->flags & IFF_UP) {
4946c78dcbdSPatrick McHardy 		if (change & IFF_ALLMULTI)
4956c78dcbdSPatrick McHardy 			dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1);
4966c78dcbdSPatrick McHardy 		if (change & IFF_PROMISC)
4976c78dcbdSPatrick McHardy 			dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1);
4986c78dcbdSPatrick McHardy 	}
499deede2faSMatthijs Kooijman }
5006c78dcbdSPatrick McHardy 
vlan_dev_set_rx_mode(struct net_device * vlan_dev)501e83a2ea8SChris Leech static void vlan_dev_set_rx_mode(struct net_device *vlan_dev)
5021da177e4SLinus Torvalds {
503d38569abSVlad Yasevich 	dev_mc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev);
504d38569abSVlad Yasevich 	dev_uc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev);
5051da177e4SLinus Torvalds }
506ef3eb3e5SPatrick McHardy 
5071a33e10eSCong Wang /*
5081a33e10eSCong Wang  * vlan network devices have devices nesting below it, and are a special
5091a33e10eSCong Wang  * "super class" of normal network devices; split their locks off into a
5101a33e10eSCong Wang  * separate class since they always nest.
5111a33e10eSCong Wang  */
5121a33e10eSCong Wang static struct lock_class_key vlan_netdev_xmit_lock_key;
513845e0ebbSCong Wang static struct lock_class_key vlan_netdev_addr_lock_key;
5141a33e10eSCong Wang 
vlan_dev_set_lockdep_one(struct net_device * dev,struct netdev_queue * txq,void * unused)5151a33e10eSCong Wang static void vlan_dev_set_lockdep_one(struct net_device *dev,
5161a33e10eSCong Wang 				     struct netdev_queue *txq,
5171a33e10eSCong Wang 				     void *unused)
5181a33e10eSCong Wang {
5191a33e10eSCong Wang 	lockdep_set_class(&txq->_xmit_lock, &vlan_netdev_xmit_lock_key);
5201a33e10eSCong Wang }
5211a33e10eSCong Wang 
vlan_dev_set_lockdep_class(struct net_device * dev)522be74294fSCong Wang static void vlan_dev_set_lockdep_class(struct net_device *dev)
5231a33e10eSCong Wang {
524be74294fSCong Wang 	lockdep_set_class(&dev->addr_list_lock,
525be74294fSCong Wang 			  &vlan_netdev_addr_lock_key);
5261a33e10eSCong Wang 	netdev_for_each_tx_queue(dev, vlan_dev_set_lockdep_one, NULL);
5271a33e10eSCong Wang }
5281a33e10eSCong Wang 
vlan_parse_protocol(const struct sk_buff * skb)52971854255SEran Ben Elisha static __be16 vlan_parse_protocol(const struct sk_buff *skb)
53071854255SEran Ben Elisha {
53171854255SEran Ben Elisha 	struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data);
53271854255SEran Ben Elisha 
53371854255SEran Ben Elisha 	return __vlan_get_protocol(skb, veth->h_vlan_proto, NULL);
53471854255SEran Ben Elisha }
53571854255SEran Ben Elisha 
536ef3eb3e5SPatrick McHardy static const struct header_ops vlan_header_ops = {
537ef3eb3e5SPatrick McHardy 	.create	 = vlan_dev_hard_header,
538ef3eb3e5SPatrick McHardy 	.parse	 = eth_header_parse,
53971854255SEran Ben Elisha 	.parse_protocol = vlan_parse_protocol,
540ef3eb3e5SPatrick McHardy };
541ef3eb3e5SPatrick McHardy 
vlan_passthru_hard_header(struct sk_buff * skb,struct net_device * dev,unsigned short type,const void * daddr,const void * saddr,unsigned int len)5422205369aSDavid S. Miller static int vlan_passthru_hard_header(struct sk_buff *skb, struct net_device *dev,
5432205369aSDavid S. Miller 				     unsigned short type,
5442205369aSDavid S. Miller 				     const void *daddr, const void *saddr,
5452205369aSDavid S. Miller 				     unsigned int len)
5462205369aSDavid S. Miller {
5472205369aSDavid S. Miller 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
5482205369aSDavid S. Miller 	struct net_device *real_dev = vlan->real_dev;
5492205369aSDavid S. Miller 
550dd38743bSPeter Boström 	if (saddr == NULL)
551dd38743bSPeter Boström 		saddr = dev->dev_addr;
552dd38743bSPeter Boström 
5532205369aSDavid S. Miller 	return dev_hard_header(skb, real_dev, type, daddr, saddr, len);
5542205369aSDavid S. Miller }
5552205369aSDavid S. Miller 
5562205369aSDavid S. Miller static const struct header_ops vlan_passthru_header_ops = {
5572205369aSDavid S. Miller 	.create	 = vlan_passthru_hard_header,
5582205369aSDavid S. Miller 	.parse	 = eth_header_parse,
55971854255SEran Ben Elisha 	.parse_protocol = vlan_parse_protocol,
5602205369aSDavid S. Miller };
5612205369aSDavid S. Miller 
562e949b09bSDoug Goldstein static struct device_type vlan_type = {
563e949b09bSDoug Goldstein 	.name	= "vlan",
564e949b09bSDoug Goldstein };
565e949b09bSDoug Goldstein 
566213b15caSEric Dumazet static const struct net_device_ops vlan_netdev_ops;
567f7d1b9f5SEric Dumazet 
vlan_dev_init(struct net_device * dev)568ef3eb3e5SPatrick McHardy static int vlan_dev_init(struct net_device *dev)
569ef3eb3e5SPatrick McHardy {
57076052d8cSMike Manning 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
57176052d8cSMike Manning 	struct net_device *real_dev = vlan->real_dev;
572ef3eb3e5SPatrick McHardy 
573adc667e8SJay Vosburgh 	netif_carrier_off(dev);
574adc667e8SJay Vosburgh 
575ef3eb3e5SPatrick McHardy 	/* IFF_BROADCAST|IFF_MULTICAST; ??? */
576194dbcc8SJohn Fastabend 	dev->flags  = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI |
577194dbcc8SJohn Fastabend 					  IFF_MASTER | IFF_SLAVE);
578ef3eb3e5SPatrick McHardy 	dev->state  = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) |
579ef3eb3e5SPatrick McHardy 					  (1<<__LINK_STATE_DORMANT))) |
580ef3eb3e5SPatrick McHardy 		      (1<<__LINK_STATE_PRESENT);
581ef3eb3e5SPatrick McHardy 
58276052d8cSMike Manning 	if (vlan->flags & VLAN_FLAG_BRIDGE_BINDING)
58376052d8cSMike Manning 		dev->state |= (1 << __LINK_STATE_NOCARRIER);
58476052d8cSMike Manning 
585a188222bSTom Herbert 	dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG |
58653f6b708SToshiaki Makita 			   NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE |
5877dad9937SDavide Caratti 			   NETIF_F_GSO_ENCAP_ALL |
58853692b1dSTom Herbert 			   NETIF_F_HIGHDMA | NETIF_F_SCTP_CRC |
58962f2a3a4SMichał Mirosław 			   NETIF_F_ALL_FCOE;
59062f2a3a4SMichał Mirosław 
591abff3e5eSEmeel Hakim 	if (real_dev->vlan_features & NETIF_F_HW_MACSEC)
592abff3e5eSEmeel Hakim 		dev->hw_features |= NETIF_F_HW_MACSEC;
593abff3e5eSEmeel Hakim 
59488997e42SAndrey Vagin 	dev->features |= dev->hw_features | NETIF_F_LLTX;
5956df6398fSJakub Kicinski 	netif_inherit_tso_max(dev, real_dev);
5962adb956bSVlad Yasevich 	if (dev->features & NETIF_F_VLAN_FEATURES)
5972adb956bSVlad Yasevich 		netdev_warn(real_dev, "VLAN features are set incorrectly.  Q-in-Q configurations may not work correctly.\n");
5982adb956bSVlad Yasevich 
5998d463504SToshiaki Makita 	dev->vlan_features = real_dev->vlan_features & ~NETIF_F_ALL_FCOE;
6007dad9937SDavide Caratti 	dev->hw_enc_features = vlan_tnl_features(real_dev);
6018b6912a5SAriel Levkovich 	dev->mpls_features = real_dev->mpls_features;
6025fb13570SPatrick McHardy 
603ef3eb3e5SPatrick McHardy 	/* ipv6 shared card related stuff */
604ef3eb3e5SPatrick McHardy 	dev->dev_id = real_dev->dev_id;
605ef3eb3e5SPatrick McHardy 
606308453aaSMike Manning 	if (is_zero_ether_addr(dev->dev_addr)) {
607e35b8d7dSJakub Kicinski 		eth_hw_addr_set(dev, real_dev->dev_addr);
608308453aaSMike Manning 		dev->addr_assign_type = NET_ADDR_STOLEN;
609308453aaSMike Manning 	}
610ef3eb3e5SPatrick McHardy 	if (is_zero_ether_addr(dev->broadcast))
611ef3eb3e5SPatrick McHardy 		memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len);
612ef3eb3e5SPatrick McHardy 
613f4d5392eSAmerigo Wang #if IS_ENABLED(CONFIG_FCOE)
614b85daa53SVasu Dev 	dev->fcoe_ddp_xid = real_dev->fcoe_ddp_xid;
615b85daa53SVasu Dev #endif
616b85daa53SVasu Dev 
617d870bfb9SEric Dumazet 	dev->needed_headroom = real_dev->needed_headroom;
61876052d8cSMike Manning 	if (vlan_hw_offload_capable(real_dev->features, vlan->vlan_proto)) {
6192205369aSDavid S. Miller 		dev->header_ops      = &vlan_passthru_header_ops;
620ef3eb3e5SPatrick McHardy 		dev->hard_header_len = real_dev->hard_header_len;
621ef3eb3e5SPatrick McHardy 	} else {
622ef3eb3e5SPatrick McHardy 		dev->header_ops      = &vlan_header_ops;
623ef3eb3e5SPatrick McHardy 		dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;
624636e19a3SJohn Fastabend 	}
625636e19a3SJohn Fastabend 
626f7d1b9f5SEric Dumazet 	dev->netdev_ops = &vlan_netdev_ops;
627ef3eb3e5SPatrick McHardy 
628e949b09bSDoug Goldstein 	SET_NETDEV_DEVTYPE(dev, &vlan_type);
629e949b09bSDoug Goldstein 
630be74294fSCong Wang 	vlan_dev_set_lockdep_class(dev);
6311a33e10eSCong Wang 
63276052d8cSMike Manning 	vlan->vlan_pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
63376052d8cSMike Manning 	if (!vlan->vlan_pcpu_stats)
6349793241fSEric Dumazet 		return -ENOMEM;
6359793241fSEric Dumazet 
63601d9cc2dSZiyang Xuan 	/* Get vlan's reference to real_dev */
637d62607c3SJakub Kicinski 	netdev_hold(real_dev, &vlan->dev_tracker, GFP_KERNEL);
63801d9cc2dSZiyang Xuan 
639ef3eb3e5SPatrick McHardy 	return 0;
640ef3eb3e5SPatrick McHardy }
641ef3eb3e5SPatrick McHardy 
6429bbd917eSEric Dumazet /* Note: this function might be called multiple times for the same device. */
vlan_dev_free_egress_priority(const struct net_device * dev)64337aa50c5SXin Long void vlan_dev_free_egress_priority(const struct net_device *dev)
64423556323SPavel Emelyanov {
64523556323SPavel Emelyanov 	struct vlan_priority_tci_mapping *pm;
6467da82c06SJiri Pirko 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
64723556323SPavel Emelyanov 	int i;
64823556323SPavel Emelyanov 
64923556323SPavel Emelyanov 	for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
65023556323SPavel Emelyanov 		while ((pm = vlan->egress_priority_map[i]) != NULL) {
65123556323SPavel Emelyanov 			vlan->egress_priority_map[i] = pm->next;
65223556323SPavel Emelyanov 			kfree(pm);
65323556323SPavel Emelyanov 		}
65423556323SPavel Emelyanov 	}
65523556323SPavel Emelyanov }
65623556323SPavel Emelyanov 
vlan_dev_uninit(struct net_device * dev)65737aa50c5SXin Long static void vlan_dev_uninit(struct net_device *dev)
65837aa50c5SXin Long {
65937aa50c5SXin Long 	vlan_dev_free_egress_priority(dev);
66037aa50c5SXin Long }
66137aa50c5SXin Long 
vlan_dev_fix_features(struct net_device * dev,netdev_features_t features)662c8f44affSMichał Mirosław static netdev_features_t vlan_dev_fix_features(struct net_device *dev,
663c8f44affSMichał Mirosław 	netdev_features_t features)
6648a0427bbSMichał Mirosław {
6657da82c06SJiri Pirko 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
666b29d3145SBjørn Mork 	netdev_features_t old_features = features;
6678403debeSVlad Yasevich 	netdev_features_t lower_features;
6688a0427bbSMichał Mirosław 
6698403debeSVlad Yasevich 	lower_features = netdev_intersect_features((real_dev->vlan_features |
6708403debeSVlad Yasevich 						    NETIF_F_RXCSUM),
6718403debeSVlad Yasevich 						   real_dev->features);
672712ae51aSShan Wei 
6738403debeSVlad Yasevich 	/* Add HW_CSUM setting to preserve user ability to control
6748403debeSVlad Yasevich 	 * checksum offload on the vlan device.
6758403debeSVlad Yasevich 	 */
6768403debeSVlad Yasevich 	if (lower_features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))
6778403debeSVlad Yasevich 		lower_features |= NETIF_F_HW_CSUM;
6788403debeSVlad Yasevich 	features = netdev_intersect_features(features, lower_features);
67953f6b708SToshiaki Makita 	features |= old_features & (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE);
680f0a619ccSMichał Mirosław 	features |= NETIF_F_LLTX;
6818a0427bbSMichał Mirosław 
6828a0427bbSMichał Mirosław 	return features;
6838a0427bbSMichał Mirosław }
6848a0427bbSMichał Mirosław 
vlan_ethtool_get_link_ksettings(struct net_device * dev,struct ethtool_link_ksettings * cmd)68557709798SDavid Decotigny static int vlan_ethtool_get_link_ksettings(struct net_device *dev,
68657709798SDavid Decotigny 					   struct ethtool_link_ksettings *cmd)
687b3020061SStephen Hemminger {
6887da82c06SJiri Pirko 	const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
6894bc71cb9SJiri Pirko 
69057709798SDavid Decotigny 	return __ethtool_get_link_ksettings(vlan->real_dev, cmd);
691b3020061SStephen Hemminger }
692b3020061SStephen Hemminger 
vlan_ethtool_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * info)693b3020061SStephen Hemminger static void vlan_ethtool_get_drvinfo(struct net_device *dev,
694b3020061SStephen Hemminger 				     struct ethtool_drvinfo *info)
695b3020061SStephen Hemminger {
696bb4d15dfSWolfram Sang 	strscpy(info->driver, vlan_fullname, sizeof(info->driver));
697bb4d15dfSWolfram Sang 	strscpy(info->version, vlan_version, sizeof(info->version));
698bb4d15dfSWolfram Sang 	strscpy(info->fw_version, "N/A", sizeof(info->fw_version));
699b3020061SStephen Hemminger }
700b3020061SStephen Hemminger 
vlan_ethtool_get_ts_info(struct net_device * dev,struct ethtool_ts_info * info)70137dd9255SRichard Cochran static int vlan_ethtool_get_ts_info(struct net_device *dev,
70237dd9255SRichard Cochran 				    struct ethtool_ts_info *info)
70337dd9255SRichard Cochran {
70437dd9255SRichard Cochran 	const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
70537dd9255SRichard Cochran 	const struct ethtool_ops *ops = vlan->real_dev->ethtool_ops;
706ec1d8ccbSHangbin Liu 	struct phy_device *phydev = vlan->real_dev->phydev;
70737dd9255SRichard Cochran 
708dfe6d68fSRichard Cochran 	if (phy_has_tsinfo(phydev)) {
709dfe6d68fSRichard Cochran 		return phy_ts_info(phydev, info);
710ec1d8ccbSHangbin Liu 	} else if (ops->get_ts_info) {
71137dd9255SRichard Cochran 		return ops->get_ts_info(vlan->real_dev, info);
71237dd9255SRichard Cochran 	} else {
71337dd9255SRichard Cochran 		info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
71437dd9255SRichard Cochran 			SOF_TIMESTAMPING_SOFTWARE;
71537dd9255SRichard Cochran 		info->phc_index = -1;
71637dd9255SRichard Cochran 	}
71737dd9255SRichard Cochran 
71837dd9255SRichard Cochran 	return 0;
71937dd9255SRichard Cochran }
72037dd9255SRichard Cochran 
vlan_dev_get_stats64(struct net_device * dev,struct rtnl_link_stats64 * stats)721bc1f4470Sstephen hemminger static void vlan_dev_get_stats64(struct net_device *dev,
722bc1f4470Sstephen hemminger 				 struct rtnl_link_stats64 *stats)
7239793241fSEric Dumazet {
7244af429d2SEric Dumazet 	struct vlan_pcpu_stats *p;
7254af429d2SEric Dumazet 	u32 rx_errors = 0, tx_dropped = 0;
7269793241fSEric Dumazet 	int i;
7279793241fSEric Dumazet 
7289793241fSEric Dumazet 	for_each_possible_cpu(i) {
7294af429d2SEric Dumazet 		u64 rxpackets, rxbytes, rxmulticast, txpackets, txbytes;
7309618e2ffSEric Dumazet 		unsigned int start;
7319618e2ffSEric Dumazet 
7327da82c06SJiri Pirko 		p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i);
7339618e2ffSEric Dumazet 		do {
734d120d1a6SThomas Gleixner 			start = u64_stats_fetch_begin(&p->syncp);
73509cca53cSEric Dumazet 			rxpackets	= u64_stats_read(&p->rx_packets);
73609cca53cSEric Dumazet 			rxbytes		= u64_stats_read(&p->rx_bytes);
73709cca53cSEric Dumazet 			rxmulticast	= u64_stats_read(&p->rx_multicast);
73809cca53cSEric Dumazet 			txpackets	= u64_stats_read(&p->tx_packets);
73909cca53cSEric Dumazet 			txbytes		= u64_stats_read(&p->tx_bytes);
740d120d1a6SThomas Gleixner 		} while (u64_stats_fetch_retry(&p->syncp, start));
7414af429d2SEric Dumazet 
7424af429d2SEric Dumazet 		stats->rx_packets	+= rxpackets;
7434af429d2SEric Dumazet 		stats->rx_bytes		+= rxbytes;
7444af429d2SEric Dumazet 		stats->multicast	+= rxmulticast;
7454af429d2SEric Dumazet 		stats->tx_packets	+= txpackets;
7464af429d2SEric Dumazet 		stats->tx_bytes		+= txbytes;
7474af429d2SEric Dumazet 		/* rx_errors & tx_dropped are u32 */
74809cca53cSEric Dumazet 		rx_errors	+= READ_ONCE(p->rx_errors);
74909cca53cSEric Dumazet 		tx_dropped	+= READ_ONCE(p->tx_dropped);
7509793241fSEric Dumazet 	}
7514af429d2SEric Dumazet 	stats->rx_errors  = rx_errors;
7524af429d2SEric Dumazet 	stats->tx_dropped = tx_dropped;
7539793241fSEric Dumazet }
7549793241fSEric Dumazet 
7556d4cdf47SBenjamin LaHaise #ifdef CONFIG_NET_POLL_CONTROLLER
vlan_dev_poll_controller(struct net_device * dev)756de93cb2eSEric Dumazet static void vlan_dev_poll_controller(struct net_device *dev)
7576d4cdf47SBenjamin LaHaise {
7586d4cdf47SBenjamin LaHaise 	return;
7596d4cdf47SBenjamin LaHaise }
7606d4cdf47SBenjamin LaHaise 
vlan_dev_netpoll_setup(struct net_device * dev,struct netpoll_info * npinfo)761a8779ec1SEric W. Biederman static int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo)
7626d4cdf47SBenjamin LaHaise {
763f3da3893SAmerigo Wang 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
764f3da3893SAmerigo Wang 	struct net_device *real_dev = vlan->real_dev;
7656d4cdf47SBenjamin LaHaise 	struct netpoll *netpoll;
7666d4cdf47SBenjamin LaHaise 	int err = 0;
7676d4cdf47SBenjamin LaHaise 
768a8779ec1SEric W. Biederman 	netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);
7696d4cdf47SBenjamin LaHaise 	err = -ENOMEM;
7706d4cdf47SBenjamin LaHaise 	if (!netpoll)
7716d4cdf47SBenjamin LaHaise 		goto out;
7726d4cdf47SBenjamin LaHaise 
773a8779ec1SEric W. Biederman 	err = __netpoll_setup(netpoll, real_dev);
7746d4cdf47SBenjamin LaHaise 	if (err) {
7756d4cdf47SBenjamin LaHaise 		kfree(netpoll);
7766d4cdf47SBenjamin LaHaise 		goto out;
7776d4cdf47SBenjamin LaHaise 	}
7786d4cdf47SBenjamin LaHaise 
779f3da3893SAmerigo Wang 	vlan->netpoll = netpoll;
7806d4cdf47SBenjamin LaHaise 
7816d4cdf47SBenjamin LaHaise out:
7826d4cdf47SBenjamin LaHaise 	return err;
7836d4cdf47SBenjamin LaHaise }
7846d4cdf47SBenjamin LaHaise 
vlan_dev_netpoll_cleanup(struct net_device * dev)785de93cb2eSEric Dumazet static void vlan_dev_netpoll_cleanup(struct net_device *dev)
7866d4cdf47SBenjamin LaHaise {
787f3da3893SAmerigo Wang 	struct vlan_dev_priv *vlan= vlan_dev_priv(dev);
788f3da3893SAmerigo Wang 	struct netpoll *netpoll = vlan->netpoll;
7896d4cdf47SBenjamin LaHaise 
7906d4cdf47SBenjamin LaHaise 	if (!netpoll)
7916d4cdf47SBenjamin LaHaise 		return;
7926d4cdf47SBenjamin LaHaise 
793f3da3893SAmerigo Wang 	vlan->netpoll = NULL;
794c9fbd71fSDebabrata Banerjee 	__netpoll_free(netpoll);
7956d4cdf47SBenjamin LaHaise }
7966d4cdf47SBenjamin LaHaise #endif /* CONFIG_NET_POLL_CONTROLLER */
7976d4cdf47SBenjamin LaHaise 
vlan_dev_get_iflink(const struct net_device * dev)7982dbf6b50SNicolas Dichtel static int vlan_dev_get_iflink(const struct net_device *dev)
7992dbf6b50SNicolas Dichtel {
8002dbf6b50SNicolas Dichtel 	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
8012dbf6b50SNicolas Dichtel 
8022dbf6b50SNicolas Dichtel 	return real_dev->ifindex;
8032dbf6b50SNicolas Dichtel }
8042dbf6b50SNicolas Dichtel 
vlan_dev_fill_forward_path(struct net_device_path_ctx * ctx,struct net_device_path * path)805e4417d69SPablo Neira Ayuso static int vlan_dev_fill_forward_path(struct net_device_path_ctx *ctx,
806e4417d69SPablo Neira Ayuso 				      struct net_device_path *path)
807e4417d69SPablo Neira Ayuso {
808e4417d69SPablo Neira Ayuso 	struct vlan_dev_priv *vlan = vlan_dev_priv(ctx->dev);
809e4417d69SPablo Neira Ayuso 
810e4417d69SPablo Neira Ayuso 	path->type = DEV_PATH_VLAN;
811e4417d69SPablo Neira Ayuso 	path->encap.id = vlan->vlan_id;
812e4417d69SPablo Neira Ayuso 	path->encap.proto = vlan->vlan_proto;
813e4417d69SPablo Neira Ayuso 	path->dev = ctx->dev;
814e4417d69SPablo Neira Ayuso 	ctx->dev = vlan->real_dev;
815bcf2766bSFelix Fietkau 	if (ctx->num_vlans >= ARRAY_SIZE(ctx->vlan))
816bcf2766bSFelix Fietkau 		return -ENOSPC;
817bcf2766bSFelix Fietkau 
818bcf2766bSFelix Fietkau 	ctx->vlan[ctx->num_vlans].id = vlan->vlan_id;
819bcf2766bSFelix Fietkau 	ctx->vlan[ctx->num_vlans].proto = vlan->vlan_proto;
820bcf2766bSFelix Fietkau 	ctx->num_vlans++;
821e4417d69SPablo Neira Ayuso 
822e4417d69SPablo Neira Ayuso 	return 0;
823e4417d69SPablo Neira Ayuso }
824e4417d69SPablo Neira Ayuso 
825abff3e5eSEmeel Hakim #if IS_ENABLED(CONFIG_MACSEC)
826abff3e5eSEmeel Hakim 
vlan_get_macsec_ops(const struct macsec_context * ctx)827abff3e5eSEmeel Hakim static const struct macsec_ops *vlan_get_macsec_ops(const struct macsec_context *ctx)
828abff3e5eSEmeel Hakim {
829abff3e5eSEmeel Hakim 	return vlan_dev_priv(ctx->netdev)->real_dev->macsec_ops;
830abff3e5eSEmeel Hakim }
831abff3e5eSEmeel Hakim 
vlan_macsec_offload(int (* const func)(struct macsec_context *),struct macsec_context * ctx)832abff3e5eSEmeel Hakim static int vlan_macsec_offload(int (* const func)(struct macsec_context *),
833abff3e5eSEmeel Hakim 			       struct macsec_context *ctx)
834abff3e5eSEmeel Hakim {
835abff3e5eSEmeel Hakim 	if (unlikely(!func))
836abff3e5eSEmeel Hakim 		return 0;
837abff3e5eSEmeel Hakim 
838abff3e5eSEmeel Hakim 	return (*func)(ctx);
839abff3e5eSEmeel Hakim }
840abff3e5eSEmeel Hakim 
vlan_macsec_dev_open(struct macsec_context * ctx)841abff3e5eSEmeel Hakim static int vlan_macsec_dev_open(struct macsec_context *ctx)
842abff3e5eSEmeel Hakim {
843abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
844abff3e5eSEmeel Hakim 
845abff3e5eSEmeel Hakim 	if (!ops)
846abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
847abff3e5eSEmeel Hakim 
848abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_dev_open, ctx);
849abff3e5eSEmeel Hakim }
850abff3e5eSEmeel Hakim 
vlan_macsec_dev_stop(struct macsec_context * ctx)851abff3e5eSEmeel Hakim static int vlan_macsec_dev_stop(struct macsec_context *ctx)
852abff3e5eSEmeel Hakim {
853abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
854abff3e5eSEmeel Hakim 
855abff3e5eSEmeel Hakim 	if (!ops)
856abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
857abff3e5eSEmeel Hakim 
858abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_dev_stop, ctx);
859abff3e5eSEmeel Hakim }
860abff3e5eSEmeel Hakim 
vlan_macsec_add_secy(struct macsec_context * ctx)861abff3e5eSEmeel Hakim static int vlan_macsec_add_secy(struct macsec_context *ctx)
862abff3e5eSEmeel Hakim {
863abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
864abff3e5eSEmeel Hakim 
865abff3e5eSEmeel Hakim 	if (!ops)
866abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
867abff3e5eSEmeel Hakim 
868abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_add_secy, ctx);
869abff3e5eSEmeel Hakim }
870abff3e5eSEmeel Hakim 
vlan_macsec_upd_secy(struct macsec_context * ctx)871abff3e5eSEmeel Hakim static int vlan_macsec_upd_secy(struct macsec_context *ctx)
872abff3e5eSEmeel Hakim {
873abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
874abff3e5eSEmeel Hakim 
875abff3e5eSEmeel Hakim 	if (!ops)
876abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
877abff3e5eSEmeel Hakim 
878abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_upd_secy, ctx);
879abff3e5eSEmeel Hakim }
880abff3e5eSEmeel Hakim 
vlan_macsec_del_secy(struct macsec_context * ctx)881abff3e5eSEmeel Hakim static int vlan_macsec_del_secy(struct macsec_context *ctx)
882abff3e5eSEmeel Hakim {
883abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
884abff3e5eSEmeel Hakim 
885abff3e5eSEmeel Hakim 	if (!ops)
886abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
887abff3e5eSEmeel Hakim 
888abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_del_secy, ctx);
889abff3e5eSEmeel Hakim }
890abff3e5eSEmeel Hakim 
vlan_macsec_add_rxsc(struct macsec_context * ctx)891abff3e5eSEmeel Hakim static int vlan_macsec_add_rxsc(struct macsec_context *ctx)
892abff3e5eSEmeel Hakim {
893abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
894abff3e5eSEmeel Hakim 
895abff3e5eSEmeel Hakim 	if (!ops)
896abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
897abff3e5eSEmeel Hakim 
898abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_add_rxsc, ctx);
899abff3e5eSEmeel Hakim }
900abff3e5eSEmeel Hakim 
vlan_macsec_upd_rxsc(struct macsec_context * ctx)901abff3e5eSEmeel Hakim static int vlan_macsec_upd_rxsc(struct macsec_context *ctx)
902abff3e5eSEmeel Hakim {
903abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
904abff3e5eSEmeel Hakim 
905abff3e5eSEmeel Hakim 	if (!ops)
906abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
907abff3e5eSEmeel Hakim 
908abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_upd_rxsc, ctx);
909abff3e5eSEmeel Hakim }
910abff3e5eSEmeel Hakim 
vlan_macsec_del_rxsc(struct macsec_context * ctx)911abff3e5eSEmeel Hakim static int vlan_macsec_del_rxsc(struct macsec_context *ctx)
912abff3e5eSEmeel Hakim {
913abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
914abff3e5eSEmeel Hakim 
915abff3e5eSEmeel Hakim 	if (!ops)
916abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
917abff3e5eSEmeel Hakim 
918abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_del_rxsc, ctx);
919abff3e5eSEmeel Hakim }
920abff3e5eSEmeel Hakim 
vlan_macsec_add_rxsa(struct macsec_context * ctx)921abff3e5eSEmeel Hakim static int vlan_macsec_add_rxsa(struct macsec_context *ctx)
922abff3e5eSEmeel Hakim {
923abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
924abff3e5eSEmeel Hakim 
925abff3e5eSEmeel Hakim 	if (!ops)
926abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
927abff3e5eSEmeel Hakim 
928abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_add_rxsa, ctx);
929abff3e5eSEmeel Hakim }
930abff3e5eSEmeel Hakim 
vlan_macsec_upd_rxsa(struct macsec_context * ctx)931abff3e5eSEmeel Hakim static int vlan_macsec_upd_rxsa(struct macsec_context *ctx)
932abff3e5eSEmeel Hakim {
933abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
934abff3e5eSEmeel Hakim 
935abff3e5eSEmeel Hakim 	if (!ops)
936abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
937abff3e5eSEmeel Hakim 
938abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_upd_rxsa, ctx);
939abff3e5eSEmeel Hakim }
940abff3e5eSEmeel Hakim 
vlan_macsec_del_rxsa(struct macsec_context * ctx)941abff3e5eSEmeel Hakim static int vlan_macsec_del_rxsa(struct macsec_context *ctx)
942abff3e5eSEmeel Hakim {
943abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
944abff3e5eSEmeel Hakim 
945abff3e5eSEmeel Hakim 	if (!ops)
946abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
947abff3e5eSEmeel Hakim 
948abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_del_rxsa, ctx);
949abff3e5eSEmeel Hakim }
950abff3e5eSEmeel Hakim 
vlan_macsec_add_txsa(struct macsec_context * ctx)951abff3e5eSEmeel Hakim static int vlan_macsec_add_txsa(struct macsec_context *ctx)
952abff3e5eSEmeel Hakim {
953abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
954abff3e5eSEmeel Hakim 
955abff3e5eSEmeel Hakim 	if (!ops)
956abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
957abff3e5eSEmeel Hakim 
958abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_add_txsa, ctx);
959abff3e5eSEmeel Hakim }
960abff3e5eSEmeel Hakim 
vlan_macsec_upd_txsa(struct macsec_context * ctx)961abff3e5eSEmeel Hakim static int vlan_macsec_upd_txsa(struct macsec_context *ctx)
962abff3e5eSEmeel Hakim {
963abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
964abff3e5eSEmeel Hakim 
965abff3e5eSEmeel Hakim 	if (!ops)
966abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
967abff3e5eSEmeel Hakim 
968abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_upd_txsa, ctx);
969abff3e5eSEmeel Hakim }
970abff3e5eSEmeel Hakim 
vlan_macsec_del_txsa(struct macsec_context * ctx)971abff3e5eSEmeel Hakim static int vlan_macsec_del_txsa(struct macsec_context *ctx)
972abff3e5eSEmeel Hakim {
973abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
974abff3e5eSEmeel Hakim 
975abff3e5eSEmeel Hakim 	if (!ops)
976abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
977abff3e5eSEmeel Hakim 
978abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_del_txsa, ctx);
979abff3e5eSEmeel Hakim }
980abff3e5eSEmeel Hakim 
vlan_macsec_get_dev_stats(struct macsec_context * ctx)981abff3e5eSEmeel Hakim static int vlan_macsec_get_dev_stats(struct macsec_context *ctx)
982abff3e5eSEmeel Hakim {
983abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
984abff3e5eSEmeel Hakim 
985abff3e5eSEmeel Hakim 	if (!ops)
986abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
987abff3e5eSEmeel Hakim 
988abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_get_dev_stats, ctx);
989abff3e5eSEmeel Hakim }
990abff3e5eSEmeel Hakim 
vlan_macsec_get_tx_sc_stats(struct macsec_context * ctx)991abff3e5eSEmeel Hakim static int vlan_macsec_get_tx_sc_stats(struct macsec_context *ctx)
992abff3e5eSEmeel Hakim {
993abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
994abff3e5eSEmeel Hakim 
995abff3e5eSEmeel Hakim 	if (!ops)
996abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
997abff3e5eSEmeel Hakim 
998abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_get_tx_sc_stats, ctx);
999abff3e5eSEmeel Hakim }
1000abff3e5eSEmeel Hakim 
vlan_macsec_get_tx_sa_stats(struct macsec_context * ctx)1001abff3e5eSEmeel Hakim static int vlan_macsec_get_tx_sa_stats(struct macsec_context *ctx)
1002abff3e5eSEmeel Hakim {
1003abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
1004abff3e5eSEmeel Hakim 
1005abff3e5eSEmeel Hakim 	if (!ops)
1006abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
1007abff3e5eSEmeel Hakim 
1008abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_get_tx_sa_stats, ctx);
1009abff3e5eSEmeel Hakim }
1010abff3e5eSEmeel Hakim 
vlan_macsec_get_rx_sc_stats(struct macsec_context * ctx)1011abff3e5eSEmeel Hakim static int vlan_macsec_get_rx_sc_stats(struct macsec_context *ctx)
1012abff3e5eSEmeel Hakim {
1013abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
1014abff3e5eSEmeel Hakim 
1015abff3e5eSEmeel Hakim 	if (!ops)
1016abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
1017abff3e5eSEmeel Hakim 
1018abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_get_rx_sc_stats, ctx);
1019abff3e5eSEmeel Hakim }
1020abff3e5eSEmeel Hakim 
vlan_macsec_get_rx_sa_stats(struct macsec_context * ctx)1021abff3e5eSEmeel Hakim static int vlan_macsec_get_rx_sa_stats(struct macsec_context *ctx)
1022abff3e5eSEmeel Hakim {
1023abff3e5eSEmeel Hakim 	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
1024abff3e5eSEmeel Hakim 
1025abff3e5eSEmeel Hakim 	if (!ops)
1026abff3e5eSEmeel Hakim 		return -EOPNOTSUPP;
1027abff3e5eSEmeel Hakim 
1028abff3e5eSEmeel Hakim 	return vlan_macsec_offload(ops->mdo_get_rx_sa_stats, ctx);
1029abff3e5eSEmeel Hakim }
1030abff3e5eSEmeel Hakim 
1031abff3e5eSEmeel Hakim static const struct macsec_ops macsec_offload_ops = {
1032abff3e5eSEmeel Hakim 	/* Device wide */
1033abff3e5eSEmeel Hakim 	.mdo_dev_open = vlan_macsec_dev_open,
1034abff3e5eSEmeel Hakim 	.mdo_dev_stop = vlan_macsec_dev_stop,
1035abff3e5eSEmeel Hakim 	/* SecY */
1036abff3e5eSEmeel Hakim 	.mdo_add_secy = vlan_macsec_add_secy,
1037abff3e5eSEmeel Hakim 	.mdo_upd_secy = vlan_macsec_upd_secy,
1038abff3e5eSEmeel Hakim 	.mdo_del_secy = vlan_macsec_del_secy,
1039abff3e5eSEmeel Hakim 	/* Security channels */
1040abff3e5eSEmeel Hakim 	.mdo_add_rxsc = vlan_macsec_add_rxsc,
1041abff3e5eSEmeel Hakim 	.mdo_upd_rxsc = vlan_macsec_upd_rxsc,
1042abff3e5eSEmeel Hakim 	.mdo_del_rxsc = vlan_macsec_del_rxsc,
1043abff3e5eSEmeel Hakim 	/* Security associations */
1044abff3e5eSEmeel Hakim 	.mdo_add_rxsa = vlan_macsec_add_rxsa,
1045abff3e5eSEmeel Hakim 	.mdo_upd_rxsa = vlan_macsec_upd_rxsa,
1046abff3e5eSEmeel Hakim 	.mdo_del_rxsa = vlan_macsec_del_rxsa,
1047abff3e5eSEmeel Hakim 	.mdo_add_txsa = vlan_macsec_add_txsa,
1048abff3e5eSEmeel Hakim 	.mdo_upd_txsa = vlan_macsec_upd_txsa,
1049abff3e5eSEmeel Hakim 	.mdo_del_txsa = vlan_macsec_del_txsa,
1050abff3e5eSEmeel Hakim 	/* Statistics */
1051abff3e5eSEmeel Hakim 	.mdo_get_dev_stats = vlan_macsec_get_dev_stats,
1052abff3e5eSEmeel Hakim 	.mdo_get_tx_sc_stats = vlan_macsec_get_tx_sc_stats,
1053abff3e5eSEmeel Hakim 	.mdo_get_tx_sa_stats = vlan_macsec_get_tx_sa_stats,
1054abff3e5eSEmeel Hakim 	.mdo_get_rx_sc_stats = vlan_macsec_get_rx_sc_stats,
1055abff3e5eSEmeel Hakim 	.mdo_get_rx_sa_stats = vlan_macsec_get_rx_sa_stats,
1056abff3e5eSEmeel Hakim };
1057abff3e5eSEmeel Hakim 
1058abff3e5eSEmeel Hakim #endif
1059abff3e5eSEmeel Hakim 
106075b8846aSPatrick McHardy static const struct ethtool_ops vlan_ethtool_ops = {
106157709798SDavid Decotigny 	.get_link_ksettings	= vlan_ethtool_get_link_ksettings,
1062b3020061SStephen Hemminger 	.get_drvinfo	        = vlan_ethtool_get_drvinfo,
106375b8846aSPatrick McHardy 	.get_link		= ethtool_op_get_link,
106437dd9255SRichard Cochran 	.get_ts_info		= vlan_ethtool_get_ts_info,
106575b8846aSPatrick McHardy };
106675b8846aSPatrick McHardy 
1067656299f7SStephen Hemminger static const struct net_device_ops vlan_netdev_ops = {
1068656299f7SStephen Hemminger 	.ndo_change_mtu		= vlan_dev_change_mtu,
1069656299f7SStephen Hemminger 	.ndo_init		= vlan_dev_init,
1070656299f7SStephen Hemminger 	.ndo_uninit		= vlan_dev_uninit,
1071656299f7SStephen Hemminger 	.ndo_open		= vlan_dev_open,
1072656299f7SStephen Hemminger 	.ndo_stop		= vlan_dev_stop,
1073f7d1b9f5SEric Dumazet 	.ndo_start_xmit =  vlan_dev_hard_start_xmit,
1074f7d1b9f5SEric Dumazet 	.ndo_validate_addr	= eth_validate_addr,
1075f7d1b9f5SEric Dumazet 	.ndo_set_mac_address	= vlan_dev_set_mac_address,
1076f7d1b9f5SEric Dumazet 	.ndo_set_rx_mode	= vlan_dev_set_rx_mode,
1077f7d1b9f5SEric Dumazet 	.ndo_change_rx_flags	= vlan_dev_change_rx_flags,
1078a7605370SArnd Bergmann 	.ndo_eth_ioctl		= vlan_dev_ioctl,
1079cc883d16SFrank Blaschka 	.ndo_neigh_setup	= vlan_dev_neigh_setup,
10809618e2ffSEric Dumazet 	.ndo_get_stats64	= vlan_dev_get_stats64,
1081f4d5392eSAmerigo Wang #if IS_ENABLED(CONFIG_FCOE)
1082b85daa53SVasu Dev 	.ndo_fcoe_ddp_setup	= vlan_dev_fcoe_ddp_setup,
1083b85daa53SVasu Dev 	.ndo_fcoe_ddp_done	= vlan_dev_fcoe_ddp_done,
10840af46d99SYi Zou 	.ndo_fcoe_enable	= vlan_dev_fcoe_enable,
10850af46d99SYi Zou 	.ndo_fcoe_disable	= vlan_dev_fcoe_disable,
10864ea09c9cSYi Zou 	.ndo_fcoe_ddp_target	= vlan_dev_fcoe_ddp_target,
1087b85daa53SVasu Dev #endif
10880a89eb92SChris Leech #ifdef NETDEV_FCOE_WWNN
10890a89eb92SChris Leech 	.ndo_fcoe_get_wwn	= vlan_dev_fcoe_get_wwn,
10900a89eb92SChris Leech #endif
10916d4cdf47SBenjamin LaHaise #ifdef CONFIG_NET_POLL_CONTROLLER
10926d4cdf47SBenjamin LaHaise 	.ndo_poll_controller	= vlan_dev_poll_controller,
10936d4cdf47SBenjamin LaHaise 	.ndo_netpoll_setup	= vlan_dev_netpoll_setup,
10946d4cdf47SBenjamin LaHaise 	.ndo_netpoll_cleanup	= vlan_dev_netpoll_cleanup,
10956d4cdf47SBenjamin LaHaise #endif
10968a0427bbSMichał Mirosław 	.ndo_fix_features	= vlan_dev_fix_features,
10972dbf6b50SNicolas Dichtel 	.ndo_get_iflink		= vlan_dev_get_iflink,
1098e4417d69SPablo Neira Ayuso 	.ndo_fill_forward_path	= vlan_dev_fill_forward_path,
1099*65c9fde1SMaxim Georgiev 	.ndo_hwtstamp_get	= vlan_hwtstamp_get,
1100*65c9fde1SMaxim Georgiev 	.ndo_hwtstamp_set	= vlan_hwtstamp_set,
1101f7d1b9f5SEric Dumazet };
1102f7d1b9f5SEric Dumazet 
vlan_dev_free(struct net_device * dev)1103a48e5fafSEric Dumazet static void vlan_dev_free(struct net_device *dev)
1104a48e5fafSEric Dumazet {
1105a48e5fafSEric Dumazet 	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
1106a48e5fafSEric Dumazet 
1107a48e5fafSEric Dumazet 	free_percpu(vlan->vlan_pcpu_stats);
1108a48e5fafSEric Dumazet 	vlan->vlan_pcpu_stats = NULL;
11096a47cdc3SXin Long 
11106a47cdc3SXin Long 	/* Get rid of the vlan's reference to real_dev */
1111d62607c3SJakub Kicinski 	netdev_put(vlan->real_dev, &vlan->dev_tracker);
1112a48e5fafSEric Dumazet }
1113a48e5fafSEric Dumazet 
vlan_setup(struct net_device * dev)1114ef3eb3e5SPatrick McHardy void vlan_setup(struct net_device *dev)
1115ef3eb3e5SPatrick McHardy {
1116ef3eb3e5SPatrick McHardy 	ether_setup(dev);
1117ef3eb3e5SPatrick McHardy 
11182e659c05SPhil Sutter 	dev->priv_flags		|= IFF_802_1Q_VLAN | IFF_NO_QUEUE;
1119e817af27SZhang Shengju 	dev->priv_flags		|= IFF_UNICAST_FLT;
112002875878SEric Dumazet 	dev->priv_flags		&= ~IFF_TX_SKB_SHARING;
112102875878SEric Dumazet 	netif_keep_dst(dev);
1122ef3eb3e5SPatrick McHardy 
1123656299f7SStephen Hemminger 	dev->netdev_ops		= &vlan_netdev_ops;
1124cf124db5SDavid S. Miller 	dev->needs_free_netdev	= true;
1125cf124db5SDavid S. Miller 	dev->priv_destructor	= vlan_dev_free;
112675b8846aSPatrick McHardy 	dev->ethtool_ops	= &vlan_ethtool_ops;
1127ef3eb3e5SPatrick McHardy 
1128abff3e5eSEmeel Hakim #if IS_ENABLED(CONFIG_MACSEC)
1129abff3e5eSEmeel Hakim 	dev->macsec_ops		= &macsec_offload_ops;
1130abff3e5eSEmeel Hakim #endif
113191572088SJarod Wilson 	dev->min_mtu		= 0;
113291572088SJarod Wilson 	dev->max_mtu		= ETH_MAX_MTU;
113391572088SJarod Wilson 
1134423049abSJoe Perches 	eth_zero_addr(dev->broadcast);
1135ef3eb3e5SPatrick McHardy }
1136