162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* -*- linux-c -*-
362306a36Sopenharmony_ci * INET		802.1Q VLAN
462306a36Sopenharmony_ci *		Ethernet-type device handling.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Authors:	Ben Greear <greearb@candelatech.com>
762306a36Sopenharmony_ci *              Please send support related email to: netdev@vger.kernel.org
862306a36Sopenharmony_ci *              VLAN Home Page: http://www.candelatech.com/~greear/vlan.html
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Fixes:       Mar 22 2001: Martin Bokaemper <mbokaemper@unispherenetworks.com>
1162306a36Sopenharmony_ci *                - reset skb->pkt_type on incoming packets when MAC was changed
1262306a36Sopenharmony_ci *                - see that changed MAC is saddr for outgoing packets
1362306a36Sopenharmony_ci *              Oct 20, 2001:  Ard van Breeman:
1462306a36Sopenharmony_ci *                - Fix MC-list, finally.
1562306a36Sopenharmony_ci *                - Flush MC-list on VLAN destroy.
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/slab.h>
2262306a36Sopenharmony_ci#include <linux/skbuff.h>
2362306a36Sopenharmony_ci#include <linux/netdevice.h>
2462306a36Sopenharmony_ci#include <linux/net_tstamp.h>
2562306a36Sopenharmony_ci#include <linux/etherdevice.h>
2662306a36Sopenharmony_ci#include <linux/ethtool.h>
2762306a36Sopenharmony_ci#include <linux/phy.h>
2862306a36Sopenharmony_ci#include <net/arp.h>
2962306a36Sopenharmony_ci#include <net/macsec.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include "vlan.h"
3262306a36Sopenharmony_ci#include "vlanproc.h"
3362306a36Sopenharmony_ci#include <linux/if_vlan.h>
3462306a36Sopenharmony_ci#include <linux/netpoll.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci *	Create the VLAN header for an arbitrary protocol layer
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci *	saddr=NULL	means use device source address
4062306a36Sopenharmony_ci *	daddr=NULL	means leave destination address (eg unresolved arp)
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci *  This is called when the SKB is moving down the stack towards the
4362306a36Sopenharmony_ci *  physical devices.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_cistatic int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
4662306a36Sopenharmony_ci				unsigned short type,
4762306a36Sopenharmony_ci				const void *daddr, const void *saddr,
4862306a36Sopenharmony_ci				unsigned int len)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
5162306a36Sopenharmony_ci	struct vlan_hdr *vhdr;
5262306a36Sopenharmony_ci	unsigned int vhdrlen = 0;
5362306a36Sopenharmony_ci	u16 vlan_tci = 0;
5462306a36Sopenharmony_ci	int rc;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (!(vlan->flags & VLAN_FLAG_REORDER_HDR)) {
5762306a36Sopenharmony_ci		vhdr = skb_push(skb, VLAN_HLEN);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci		vlan_tci = vlan->vlan_id;
6062306a36Sopenharmony_ci		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb->priority);
6162306a36Sopenharmony_ci		vhdr->h_vlan_TCI = htons(vlan_tci);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		/*
6462306a36Sopenharmony_ci		 *  Set the protocol type. For a packet of type ETH_P_802_3/2 we
6562306a36Sopenharmony_ci		 *  put the length in here instead.
6662306a36Sopenharmony_ci		 */
6762306a36Sopenharmony_ci		if (type != ETH_P_802_3 && type != ETH_P_802_2)
6862306a36Sopenharmony_ci			vhdr->h_vlan_encapsulated_proto = htons(type);
6962306a36Sopenharmony_ci		else
7062306a36Sopenharmony_ci			vhdr->h_vlan_encapsulated_proto = htons(len);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci		skb->protocol = vlan->vlan_proto;
7362306a36Sopenharmony_ci		type = ntohs(vlan->vlan_proto);
7462306a36Sopenharmony_ci		vhdrlen = VLAN_HLEN;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/* Before delegating work to the lower layer, enter our MAC-address */
7862306a36Sopenharmony_ci	if (saddr == NULL)
7962306a36Sopenharmony_ci		saddr = dev->dev_addr;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/* Now make the underlying real hard header */
8262306a36Sopenharmony_ci	dev = vlan->real_dev;
8362306a36Sopenharmony_ci	rc = dev_hard_header(skb, dev, type, daddr, saddr, len + vhdrlen);
8462306a36Sopenharmony_ci	if (rc > 0)
8562306a36Sopenharmony_ci		rc += vhdrlen;
8662306a36Sopenharmony_ci	return rc;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic inline netdev_tx_t vlan_netpoll_send_skb(struct vlan_dev_priv *vlan, struct sk_buff *skb)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
9262306a36Sopenharmony_ci	return netpoll_send_skb(vlan->netpoll, skb);
9362306a36Sopenharmony_ci#else
9462306a36Sopenharmony_ci	BUG();
9562306a36Sopenharmony_ci	return NETDEV_TX_OK;
9662306a36Sopenharmony_ci#endif
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
10062306a36Sopenharmony_ci					    struct net_device *dev)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
10362306a36Sopenharmony_ci	struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data);
10462306a36Sopenharmony_ci	unsigned int len;
10562306a36Sopenharmony_ci	int ret;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/* Handle non-VLAN frames if they are sent to us, for example by DHCP.
10862306a36Sopenharmony_ci	 *
10962306a36Sopenharmony_ci	 * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING
11062306a36Sopenharmony_ci	 * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs...
11162306a36Sopenharmony_ci	 */
11262306a36Sopenharmony_ci	if (vlan->flags & VLAN_FLAG_REORDER_HDR ||
11362306a36Sopenharmony_ci	    veth->h_vlan_proto != vlan->vlan_proto) {
11462306a36Sopenharmony_ci		u16 vlan_tci;
11562306a36Sopenharmony_ci		vlan_tci = vlan->vlan_id;
11662306a36Sopenharmony_ci		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb->priority);
11762306a36Sopenharmony_ci		__vlan_hwaccel_put_tag(skb, vlan->vlan_proto, vlan_tci);
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	skb->dev = vlan->real_dev;
12162306a36Sopenharmony_ci	len = skb->len;
12262306a36Sopenharmony_ci	if (unlikely(netpoll_tx_running(dev)))
12362306a36Sopenharmony_ci		return vlan_netpoll_send_skb(vlan, skb);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	ret = dev_queue_xmit(skb);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
12862306a36Sopenharmony_ci		struct vlan_pcpu_stats *stats;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		stats = this_cpu_ptr(vlan->vlan_pcpu_stats);
13162306a36Sopenharmony_ci		u64_stats_update_begin(&stats->syncp);
13262306a36Sopenharmony_ci		u64_stats_inc(&stats->tx_packets);
13362306a36Sopenharmony_ci		u64_stats_add(&stats->tx_bytes, len);
13462306a36Sopenharmony_ci		u64_stats_update_end(&stats->syncp);
13562306a36Sopenharmony_ci	} else {
13662306a36Sopenharmony_ci		this_cpu_inc(vlan->vlan_pcpu_stats->tx_dropped);
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return ret;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int vlan_dev_change_mtu(struct net_device *dev, int new_mtu)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
14562306a36Sopenharmony_ci	unsigned int max_mtu = real_dev->mtu;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (netif_reduces_vlan_mtu(real_dev))
14862306a36Sopenharmony_ci		max_mtu -= VLAN_HLEN;
14962306a36Sopenharmony_ci	if (max_mtu < new_mtu)
15062306a36Sopenharmony_ci		return -ERANGE;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	dev->mtu = new_mtu;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	return 0;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_civoid vlan_dev_set_ingress_priority(const struct net_device *dev,
15862306a36Sopenharmony_ci				   u32 skb_prio, u16 vlan_prio)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	if (vlan->ingress_priority_map[vlan_prio & 0x7] && !skb_prio)
16362306a36Sopenharmony_ci		vlan->nr_ingress_mappings--;
16462306a36Sopenharmony_ci	else if (!vlan->ingress_priority_map[vlan_prio & 0x7] && skb_prio)
16562306a36Sopenharmony_ci		vlan->nr_ingress_mappings++;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	vlan->ingress_priority_map[vlan_prio & 0x7] = skb_prio;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ciint vlan_dev_set_egress_priority(const struct net_device *dev,
17162306a36Sopenharmony_ci				 u32 skb_prio, u16 vlan_prio)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
17462306a36Sopenharmony_ci	struct vlan_priority_tci_mapping *mp = NULL;
17562306a36Sopenharmony_ci	struct vlan_priority_tci_mapping *np;
17662306a36Sopenharmony_ci	u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* See if a priority mapping exists.. */
17962306a36Sopenharmony_ci	mp = vlan->egress_priority_map[skb_prio & 0xF];
18062306a36Sopenharmony_ci	while (mp) {
18162306a36Sopenharmony_ci		if (mp->priority == skb_prio) {
18262306a36Sopenharmony_ci			if (mp->vlan_qos && !vlan_qos)
18362306a36Sopenharmony_ci				vlan->nr_egress_mappings--;
18462306a36Sopenharmony_ci			else if (!mp->vlan_qos && vlan_qos)
18562306a36Sopenharmony_ci				vlan->nr_egress_mappings++;
18662306a36Sopenharmony_ci			mp->vlan_qos = vlan_qos;
18762306a36Sopenharmony_ci			return 0;
18862306a36Sopenharmony_ci		}
18962306a36Sopenharmony_ci		mp = mp->next;
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/* Create a new mapping then. */
19362306a36Sopenharmony_ci	mp = vlan->egress_priority_map[skb_prio & 0xF];
19462306a36Sopenharmony_ci	np = kmalloc(sizeof(struct vlan_priority_tci_mapping), GFP_KERNEL);
19562306a36Sopenharmony_ci	if (!np)
19662306a36Sopenharmony_ci		return -ENOBUFS;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	np->next = mp;
19962306a36Sopenharmony_ci	np->priority = skb_prio;
20062306a36Sopenharmony_ci	np->vlan_qos = vlan_qos;
20162306a36Sopenharmony_ci	/* Before inserting this element in hash table, make sure all its fields
20262306a36Sopenharmony_ci	 * are committed to memory.
20362306a36Sopenharmony_ci	 * coupled with smp_rmb() in vlan_dev_get_egress_qos_mask()
20462306a36Sopenharmony_ci	 */
20562306a36Sopenharmony_ci	smp_wmb();
20662306a36Sopenharmony_ci	vlan->egress_priority_map[skb_prio & 0xF] = np;
20762306a36Sopenharmony_ci	if (vlan_qos)
20862306a36Sopenharmony_ci		vlan->nr_egress_mappings++;
20962306a36Sopenharmony_ci	return 0;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci/* Flags are defined in the vlan_flags enum in
21362306a36Sopenharmony_ci * include/uapi/linux/if_vlan.h file.
21462306a36Sopenharmony_ci */
21562306a36Sopenharmony_ciint vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
21862306a36Sopenharmony_ci	u32 old_flags = vlan->flags;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
22162306a36Sopenharmony_ci		     VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP |
22262306a36Sopenharmony_ci		     VLAN_FLAG_BRIDGE_BINDING))
22362306a36Sopenharmony_ci		return -EINVAL;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	vlan->flags = (old_flags & ~mask) | (flags & mask);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (netif_running(dev) && (vlan->flags ^ old_flags) & VLAN_FLAG_GVRP) {
22862306a36Sopenharmony_ci		if (vlan->flags & VLAN_FLAG_GVRP)
22962306a36Sopenharmony_ci			vlan_gvrp_request_join(dev);
23062306a36Sopenharmony_ci		else
23162306a36Sopenharmony_ci			vlan_gvrp_request_leave(dev);
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (netif_running(dev) && (vlan->flags ^ old_flags) & VLAN_FLAG_MVRP) {
23562306a36Sopenharmony_ci		if (vlan->flags & VLAN_FLAG_MVRP)
23662306a36Sopenharmony_ci			vlan_mvrp_request_join(dev);
23762306a36Sopenharmony_ci		else
23862306a36Sopenharmony_ci			vlan_mvrp_request_leave(dev);
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci	return 0;
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_civoid vlan_dev_get_realdev_name(const struct net_device *dev, char *result, size_t size)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	strscpy_pad(result, vlan_dev_priv(dev)->real_dev->name, size);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cibool vlan_dev_inherit_address(struct net_device *dev,
24962306a36Sopenharmony_ci			      struct net_device *real_dev)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	if (dev->addr_assign_type != NET_ADDR_STOLEN)
25262306a36Sopenharmony_ci		return false;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	eth_hw_addr_set(dev, real_dev->dev_addr);
25562306a36Sopenharmony_ci	call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
25662306a36Sopenharmony_ci	return true;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic int vlan_dev_open(struct net_device *dev)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
26262306a36Sopenharmony_ci	struct net_device *real_dev = vlan->real_dev;
26362306a36Sopenharmony_ci	int err;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (!(real_dev->flags & IFF_UP) &&
26662306a36Sopenharmony_ci	    !(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
26762306a36Sopenharmony_ci		return -ENETDOWN;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr) &&
27062306a36Sopenharmony_ci	    !vlan_dev_inherit_address(dev, real_dev)) {
27162306a36Sopenharmony_ci		err = dev_uc_add(real_dev, dev->dev_addr);
27262306a36Sopenharmony_ci		if (err < 0)
27362306a36Sopenharmony_ci			goto out;
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (dev->flags & IFF_ALLMULTI) {
27762306a36Sopenharmony_ci		err = dev_set_allmulti(real_dev, 1);
27862306a36Sopenharmony_ci		if (err < 0)
27962306a36Sopenharmony_ci			goto del_unicast;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {
28262306a36Sopenharmony_ci		err = dev_set_promiscuity(real_dev, 1);
28362306a36Sopenharmony_ci		if (err < 0)
28462306a36Sopenharmony_ci			goto clear_allmulti;
28562306a36Sopenharmony_ci	}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	ether_addr_copy(vlan->real_dev_addr, real_dev->dev_addr);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (vlan->flags & VLAN_FLAG_GVRP)
29062306a36Sopenharmony_ci		vlan_gvrp_request_join(dev);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (vlan->flags & VLAN_FLAG_MVRP)
29362306a36Sopenharmony_ci		vlan_mvrp_request_join(dev);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (netif_carrier_ok(real_dev) &&
29662306a36Sopenharmony_ci	    !(vlan->flags & VLAN_FLAG_BRIDGE_BINDING))
29762306a36Sopenharmony_ci		netif_carrier_on(dev);
29862306a36Sopenharmony_ci	return 0;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ciclear_allmulti:
30162306a36Sopenharmony_ci	if (dev->flags & IFF_ALLMULTI)
30262306a36Sopenharmony_ci		dev_set_allmulti(real_dev, -1);
30362306a36Sopenharmony_cidel_unicast:
30462306a36Sopenharmony_ci	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
30562306a36Sopenharmony_ci		dev_uc_del(real_dev, dev->dev_addr);
30662306a36Sopenharmony_ciout:
30762306a36Sopenharmony_ci	netif_carrier_off(dev);
30862306a36Sopenharmony_ci	return err;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int vlan_dev_stop(struct net_device *dev)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
31462306a36Sopenharmony_ci	struct net_device *real_dev = vlan->real_dev;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	dev_mc_unsync(real_dev, dev);
31762306a36Sopenharmony_ci	dev_uc_unsync(real_dev, dev);
31862306a36Sopenharmony_ci	if (dev->flags & IFF_ALLMULTI)
31962306a36Sopenharmony_ci		dev_set_allmulti(real_dev, -1);
32062306a36Sopenharmony_ci	if (dev->flags & IFF_PROMISC)
32162306a36Sopenharmony_ci		dev_set_promiscuity(real_dev, -1);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
32462306a36Sopenharmony_ci		dev_uc_del(real_dev, dev->dev_addr);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	if (!(vlan->flags & VLAN_FLAG_BRIDGE_BINDING))
32762306a36Sopenharmony_ci		netif_carrier_off(dev);
32862306a36Sopenharmony_ci	return 0;
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic int vlan_dev_set_mac_address(struct net_device *dev, void *p)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
33462306a36Sopenharmony_ci	struct sockaddr *addr = p;
33562306a36Sopenharmony_ci	int err;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	if (!is_valid_ether_addr(addr->sa_data))
33862306a36Sopenharmony_ci		return -EADDRNOTAVAIL;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (!(dev->flags & IFF_UP))
34162306a36Sopenharmony_ci		goto out;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (!ether_addr_equal(addr->sa_data, real_dev->dev_addr)) {
34462306a36Sopenharmony_ci		err = dev_uc_add(real_dev, addr->sa_data);
34562306a36Sopenharmony_ci		if (err < 0)
34662306a36Sopenharmony_ci			return err;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
35062306a36Sopenharmony_ci		dev_uc_del(real_dev, dev->dev_addr);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ciout:
35362306a36Sopenharmony_ci	eth_hw_addr_set(dev, addr->sa_data);
35462306a36Sopenharmony_ci	return 0;
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic int vlan_hwtstamp_get(struct net_device *dev,
35862306a36Sopenharmony_ci			     struct kernel_hwtstamp_config *cfg)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	return generic_hwtstamp_get_lower(real_dev, cfg);
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic int vlan_hwtstamp_set(struct net_device *dev,
36662306a36Sopenharmony_ci			     struct kernel_hwtstamp_config *cfg,
36762306a36Sopenharmony_ci			     struct netlink_ext_ack *extack)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (!net_eq(dev_net(dev), dev_net(real_dev)))
37262306a36Sopenharmony_ci		return -EOPNOTSUPP;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	return generic_hwtstamp_set_lower(real_dev, cfg, extack);
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
38062306a36Sopenharmony_ci	const struct net_device_ops *ops = real_dev->netdev_ops;
38162306a36Sopenharmony_ci	struct ifreq ifrr;
38262306a36Sopenharmony_ci	int err = -EOPNOTSUPP;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	strscpy_pad(ifrr.ifr_name, real_dev->name, IFNAMSIZ);
38562306a36Sopenharmony_ci	ifrr.ifr_ifru = ifr->ifr_ifru;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	switch (cmd) {
38862306a36Sopenharmony_ci	case SIOCGMIIPHY:
38962306a36Sopenharmony_ci	case SIOCGMIIREG:
39062306a36Sopenharmony_ci	case SIOCSMIIREG:
39162306a36Sopenharmony_ci		if (netif_device_present(real_dev) && ops->ndo_eth_ioctl)
39262306a36Sopenharmony_ci			err = ops->ndo_eth_ioctl(real_dev, &ifrr, cmd);
39362306a36Sopenharmony_ci		break;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (!err)
39762306a36Sopenharmony_ci		ifr->ifr_ifru = ifrr.ifr_ifru;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	return err;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic int vlan_dev_neigh_setup(struct net_device *dev, struct neigh_parms *pa)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
40562306a36Sopenharmony_ci	const struct net_device_ops *ops = real_dev->netdev_ops;
40662306a36Sopenharmony_ci	int err = 0;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (netif_device_present(real_dev) && ops->ndo_neigh_setup)
40962306a36Sopenharmony_ci		err = ops->ndo_neigh_setup(real_dev, pa);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	return err;
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_FCOE)
41562306a36Sopenharmony_cistatic int vlan_dev_fcoe_ddp_setup(struct net_device *dev, u16 xid,
41662306a36Sopenharmony_ci				   struct scatterlist *sgl, unsigned int sgc)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
41962306a36Sopenharmony_ci	const struct net_device_ops *ops = real_dev->netdev_ops;
42062306a36Sopenharmony_ci	int rc = 0;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	if (ops->ndo_fcoe_ddp_setup)
42362306a36Sopenharmony_ci		rc = ops->ndo_fcoe_ddp_setup(real_dev, xid, sgl, sgc);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	return rc;
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic int vlan_dev_fcoe_ddp_done(struct net_device *dev, u16 xid)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
43162306a36Sopenharmony_ci	const struct net_device_ops *ops = real_dev->netdev_ops;
43262306a36Sopenharmony_ci	int len = 0;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (ops->ndo_fcoe_ddp_done)
43562306a36Sopenharmony_ci		len = ops->ndo_fcoe_ddp_done(real_dev, xid);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	return len;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic int vlan_dev_fcoe_enable(struct net_device *dev)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
44362306a36Sopenharmony_ci	const struct net_device_ops *ops = real_dev->netdev_ops;
44462306a36Sopenharmony_ci	int rc = -EINVAL;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	if (ops->ndo_fcoe_enable)
44762306a36Sopenharmony_ci		rc = ops->ndo_fcoe_enable(real_dev);
44862306a36Sopenharmony_ci	return rc;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic int vlan_dev_fcoe_disable(struct net_device *dev)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
45462306a36Sopenharmony_ci	const struct net_device_ops *ops = real_dev->netdev_ops;
45562306a36Sopenharmony_ci	int rc = -EINVAL;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (ops->ndo_fcoe_disable)
45862306a36Sopenharmony_ci		rc = ops->ndo_fcoe_disable(real_dev);
45962306a36Sopenharmony_ci	return rc;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic int vlan_dev_fcoe_ddp_target(struct net_device *dev, u16 xid,
46362306a36Sopenharmony_ci				    struct scatterlist *sgl, unsigned int sgc)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
46662306a36Sopenharmony_ci	const struct net_device_ops *ops = real_dev->netdev_ops;
46762306a36Sopenharmony_ci	int rc = 0;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (ops->ndo_fcoe_ddp_target)
47062306a36Sopenharmony_ci		rc = ops->ndo_fcoe_ddp_target(real_dev, xid, sgl, sgc);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	return rc;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci#endif
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci#ifdef NETDEV_FCOE_WWNN
47762306a36Sopenharmony_cistatic int vlan_dev_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
48062306a36Sopenharmony_ci	const struct net_device_ops *ops = real_dev->netdev_ops;
48162306a36Sopenharmony_ci	int rc = -EINVAL;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (ops->ndo_fcoe_get_wwn)
48462306a36Sopenharmony_ci		rc = ops->ndo_fcoe_get_wwn(real_dev, wwn, type);
48562306a36Sopenharmony_ci	return rc;
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci#endif
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic void vlan_dev_change_rx_flags(struct net_device *dev, int change)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	if (dev->flags & IFF_UP) {
49462306a36Sopenharmony_ci		if (change & IFF_ALLMULTI)
49562306a36Sopenharmony_ci			dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1);
49662306a36Sopenharmony_ci		if (change & IFF_PROMISC)
49762306a36Sopenharmony_ci			dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1);
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic void vlan_dev_set_rx_mode(struct net_device *vlan_dev)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	dev_mc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev);
50462306a36Sopenharmony_ci	dev_uc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev);
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci/*
50862306a36Sopenharmony_ci * vlan network devices have devices nesting below it, and are a special
50962306a36Sopenharmony_ci * "super class" of normal network devices; split their locks off into a
51062306a36Sopenharmony_ci * separate class since they always nest.
51162306a36Sopenharmony_ci */
51262306a36Sopenharmony_cistatic struct lock_class_key vlan_netdev_xmit_lock_key;
51362306a36Sopenharmony_cistatic struct lock_class_key vlan_netdev_addr_lock_key;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistatic void vlan_dev_set_lockdep_one(struct net_device *dev,
51662306a36Sopenharmony_ci				     struct netdev_queue *txq,
51762306a36Sopenharmony_ci				     void *unused)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	lockdep_set_class(&txq->_xmit_lock, &vlan_netdev_xmit_lock_key);
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic void vlan_dev_set_lockdep_class(struct net_device *dev)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	lockdep_set_class(&dev->addr_list_lock,
52562306a36Sopenharmony_ci			  &vlan_netdev_addr_lock_key);
52662306a36Sopenharmony_ci	netdev_for_each_tx_queue(dev, vlan_dev_set_lockdep_one, NULL);
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic __be16 vlan_parse_protocol(const struct sk_buff *skb)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	return __vlan_get_protocol(skb, veth->h_vlan_proto, NULL);
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic const struct header_ops vlan_header_ops = {
53762306a36Sopenharmony_ci	.create	 = vlan_dev_hard_header,
53862306a36Sopenharmony_ci	.parse	 = eth_header_parse,
53962306a36Sopenharmony_ci	.parse_protocol = vlan_parse_protocol,
54062306a36Sopenharmony_ci};
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic int vlan_passthru_hard_header(struct sk_buff *skb, struct net_device *dev,
54362306a36Sopenharmony_ci				     unsigned short type,
54462306a36Sopenharmony_ci				     const void *daddr, const void *saddr,
54562306a36Sopenharmony_ci				     unsigned int len)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
54862306a36Sopenharmony_ci	struct net_device *real_dev = vlan->real_dev;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (saddr == NULL)
55162306a36Sopenharmony_ci		saddr = dev->dev_addr;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	return dev_hard_header(skb, real_dev, type, daddr, saddr, len);
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic const struct header_ops vlan_passthru_header_ops = {
55762306a36Sopenharmony_ci	.create	 = vlan_passthru_hard_header,
55862306a36Sopenharmony_ci	.parse	 = eth_header_parse,
55962306a36Sopenharmony_ci	.parse_protocol = vlan_parse_protocol,
56062306a36Sopenharmony_ci};
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic struct device_type vlan_type = {
56362306a36Sopenharmony_ci	.name	= "vlan",
56462306a36Sopenharmony_ci};
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic const struct net_device_ops vlan_netdev_ops;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cistatic int vlan_dev_init(struct net_device *dev)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
57162306a36Sopenharmony_ci	struct net_device *real_dev = vlan->real_dev;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	netif_carrier_off(dev);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	/* IFF_BROADCAST|IFF_MULTICAST; ??? */
57662306a36Sopenharmony_ci	dev->flags  = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI |
57762306a36Sopenharmony_ci					  IFF_MASTER | IFF_SLAVE);
57862306a36Sopenharmony_ci	dev->state  = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) |
57962306a36Sopenharmony_ci					  (1<<__LINK_STATE_DORMANT))) |
58062306a36Sopenharmony_ci		      (1<<__LINK_STATE_PRESENT);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	if (vlan->flags & VLAN_FLAG_BRIDGE_BINDING)
58362306a36Sopenharmony_ci		dev->state |= (1 << __LINK_STATE_NOCARRIER);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG |
58662306a36Sopenharmony_ci			   NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE |
58762306a36Sopenharmony_ci			   NETIF_F_GSO_ENCAP_ALL |
58862306a36Sopenharmony_ci			   NETIF_F_HIGHDMA | NETIF_F_SCTP_CRC |
58962306a36Sopenharmony_ci			   NETIF_F_ALL_FCOE;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (real_dev->vlan_features & NETIF_F_HW_MACSEC)
59262306a36Sopenharmony_ci		dev->hw_features |= NETIF_F_HW_MACSEC;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	dev->features |= dev->hw_features | NETIF_F_LLTX;
59562306a36Sopenharmony_ci	netif_inherit_tso_max(dev, real_dev);
59662306a36Sopenharmony_ci	if (dev->features & NETIF_F_VLAN_FEATURES)
59762306a36Sopenharmony_ci		netdev_warn(real_dev, "VLAN features are set incorrectly.  Q-in-Q configurations may not work correctly.\n");
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	dev->vlan_features = real_dev->vlan_features & ~NETIF_F_ALL_FCOE;
60062306a36Sopenharmony_ci	dev->hw_enc_features = vlan_tnl_features(real_dev);
60162306a36Sopenharmony_ci	dev->mpls_features = real_dev->mpls_features;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	/* ipv6 shared card related stuff */
60462306a36Sopenharmony_ci	dev->dev_id = real_dev->dev_id;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	if (is_zero_ether_addr(dev->dev_addr)) {
60762306a36Sopenharmony_ci		eth_hw_addr_set(dev, real_dev->dev_addr);
60862306a36Sopenharmony_ci		dev->addr_assign_type = NET_ADDR_STOLEN;
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci	if (is_zero_ether_addr(dev->broadcast))
61162306a36Sopenharmony_ci		memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_FCOE)
61462306a36Sopenharmony_ci	dev->fcoe_ddp_xid = real_dev->fcoe_ddp_xid;
61562306a36Sopenharmony_ci#endif
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	dev->needed_headroom = real_dev->needed_headroom;
61862306a36Sopenharmony_ci	if (vlan_hw_offload_capable(real_dev->features, vlan->vlan_proto)) {
61962306a36Sopenharmony_ci		dev->header_ops      = &vlan_passthru_header_ops;
62062306a36Sopenharmony_ci		dev->hard_header_len = real_dev->hard_header_len;
62162306a36Sopenharmony_ci	} else {
62262306a36Sopenharmony_ci		dev->header_ops      = &vlan_header_ops;
62362306a36Sopenharmony_ci		dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;
62462306a36Sopenharmony_ci	}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	dev->netdev_ops = &vlan_netdev_ops;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	SET_NETDEV_DEVTYPE(dev, &vlan_type);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	vlan_dev_set_lockdep_class(dev);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	vlan->vlan_pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
63362306a36Sopenharmony_ci	if (!vlan->vlan_pcpu_stats)
63462306a36Sopenharmony_ci		return -ENOMEM;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	/* Get vlan's reference to real_dev */
63762306a36Sopenharmony_ci	netdev_hold(real_dev, &vlan->dev_tracker, GFP_KERNEL);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	return 0;
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci/* Note: this function might be called multiple times for the same device. */
64362306a36Sopenharmony_civoid vlan_dev_free_egress_priority(const struct net_device *dev)
64462306a36Sopenharmony_ci{
64562306a36Sopenharmony_ci	struct vlan_priority_tci_mapping *pm;
64662306a36Sopenharmony_ci	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
64762306a36Sopenharmony_ci	int i;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
65062306a36Sopenharmony_ci		while ((pm = vlan->egress_priority_map[i]) != NULL) {
65162306a36Sopenharmony_ci			vlan->egress_priority_map[i] = pm->next;
65262306a36Sopenharmony_ci			kfree(pm);
65362306a36Sopenharmony_ci		}
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic void vlan_dev_uninit(struct net_device *dev)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	vlan_dev_free_egress_priority(dev);
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic netdev_features_t vlan_dev_fix_features(struct net_device *dev,
66362306a36Sopenharmony_ci	netdev_features_t features)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
66662306a36Sopenharmony_ci	netdev_features_t old_features = features;
66762306a36Sopenharmony_ci	netdev_features_t lower_features;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	lower_features = netdev_intersect_features((real_dev->vlan_features |
67062306a36Sopenharmony_ci						    NETIF_F_RXCSUM),
67162306a36Sopenharmony_ci						   real_dev->features);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	/* Add HW_CSUM setting to preserve user ability to control
67462306a36Sopenharmony_ci	 * checksum offload on the vlan device.
67562306a36Sopenharmony_ci	 */
67662306a36Sopenharmony_ci	if (lower_features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))
67762306a36Sopenharmony_ci		lower_features |= NETIF_F_HW_CSUM;
67862306a36Sopenharmony_ci	features = netdev_intersect_features(features, lower_features);
67962306a36Sopenharmony_ci	features |= old_features & (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE);
68062306a36Sopenharmony_ci	features |= NETIF_F_LLTX;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	return features;
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_cistatic int vlan_ethtool_get_link_ksettings(struct net_device *dev,
68662306a36Sopenharmony_ci					   struct ethtool_link_ksettings *cmd)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	return __ethtool_get_link_ksettings(vlan->real_dev, cmd);
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cistatic void vlan_ethtool_get_drvinfo(struct net_device *dev,
69462306a36Sopenharmony_ci				     struct ethtool_drvinfo *info)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	strscpy(info->driver, vlan_fullname, sizeof(info->driver));
69762306a36Sopenharmony_ci	strscpy(info->version, vlan_version, sizeof(info->version));
69862306a36Sopenharmony_ci	strscpy(info->fw_version, "N/A", sizeof(info->fw_version));
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_cistatic int vlan_ethtool_get_ts_info(struct net_device *dev,
70262306a36Sopenharmony_ci				    struct ethtool_ts_info *info)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
70562306a36Sopenharmony_ci	const struct ethtool_ops *ops = vlan->real_dev->ethtool_ops;
70662306a36Sopenharmony_ci	struct phy_device *phydev = vlan->real_dev->phydev;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	if (phy_has_tsinfo(phydev)) {
70962306a36Sopenharmony_ci		return phy_ts_info(phydev, info);
71062306a36Sopenharmony_ci	} else if (ops->get_ts_info) {
71162306a36Sopenharmony_ci		return ops->get_ts_info(vlan->real_dev, info);
71262306a36Sopenharmony_ci	} else {
71362306a36Sopenharmony_ci		info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
71462306a36Sopenharmony_ci			SOF_TIMESTAMPING_SOFTWARE;
71562306a36Sopenharmony_ci		info->phc_index = -1;
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	return 0;
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_cistatic void vlan_dev_get_stats64(struct net_device *dev,
72262306a36Sopenharmony_ci				 struct rtnl_link_stats64 *stats)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci	struct vlan_pcpu_stats *p;
72562306a36Sopenharmony_ci	u32 rx_errors = 0, tx_dropped = 0;
72662306a36Sopenharmony_ci	int i;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	for_each_possible_cpu(i) {
72962306a36Sopenharmony_ci		u64 rxpackets, rxbytes, rxmulticast, txpackets, txbytes;
73062306a36Sopenharmony_ci		unsigned int start;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci		p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i);
73362306a36Sopenharmony_ci		do {
73462306a36Sopenharmony_ci			start = u64_stats_fetch_begin(&p->syncp);
73562306a36Sopenharmony_ci			rxpackets	= u64_stats_read(&p->rx_packets);
73662306a36Sopenharmony_ci			rxbytes		= u64_stats_read(&p->rx_bytes);
73762306a36Sopenharmony_ci			rxmulticast	= u64_stats_read(&p->rx_multicast);
73862306a36Sopenharmony_ci			txpackets	= u64_stats_read(&p->tx_packets);
73962306a36Sopenharmony_ci			txbytes		= u64_stats_read(&p->tx_bytes);
74062306a36Sopenharmony_ci		} while (u64_stats_fetch_retry(&p->syncp, start));
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci		stats->rx_packets	+= rxpackets;
74362306a36Sopenharmony_ci		stats->rx_bytes		+= rxbytes;
74462306a36Sopenharmony_ci		stats->multicast	+= rxmulticast;
74562306a36Sopenharmony_ci		stats->tx_packets	+= txpackets;
74662306a36Sopenharmony_ci		stats->tx_bytes		+= txbytes;
74762306a36Sopenharmony_ci		/* rx_errors & tx_dropped are u32 */
74862306a36Sopenharmony_ci		rx_errors	+= READ_ONCE(p->rx_errors);
74962306a36Sopenharmony_ci		tx_dropped	+= READ_ONCE(p->tx_dropped);
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci	stats->rx_errors  = rx_errors;
75262306a36Sopenharmony_ci	stats->tx_dropped = tx_dropped;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
75662306a36Sopenharmony_cistatic void vlan_dev_poll_controller(struct net_device *dev)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	return;
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_cistatic int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo)
76262306a36Sopenharmony_ci{
76362306a36Sopenharmony_ci	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
76462306a36Sopenharmony_ci	struct net_device *real_dev = vlan->real_dev;
76562306a36Sopenharmony_ci	struct netpoll *netpoll;
76662306a36Sopenharmony_ci	int err = 0;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);
76962306a36Sopenharmony_ci	err = -ENOMEM;
77062306a36Sopenharmony_ci	if (!netpoll)
77162306a36Sopenharmony_ci		goto out;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	err = __netpoll_setup(netpoll, real_dev);
77462306a36Sopenharmony_ci	if (err) {
77562306a36Sopenharmony_ci		kfree(netpoll);
77662306a36Sopenharmony_ci		goto out;
77762306a36Sopenharmony_ci	}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	vlan->netpoll = netpoll;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ciout:
78262306a36Sopenharmony_ci	return err;
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_cistatic void vlan_dev_netpoll_cleanup(struct net_device *dev)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	struct vlan_dev_priv *vlan= vlan_dev_priv(dev);
78862306a36Sopenharmony_ci	struct netpoll *netpoll = vlan->netpoll;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	if (!netpoll)
79162306a36Sopenharmony_ci		return;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	vlan->netpoll = NULL;
79462306a36Sopenharmony_ci	__netpoll_free(netpoll);
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci#endif /* CONFIG_NET_POLL_CONTROLLER */
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_cistatic int vlan_dev_get_iflink(const struct net_device *dev)
79962306a36Sopenharmony_ci{
80062306a36Sopenharmony_ci	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	return real_dev->ifindex;
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_cistatic int vlan_dev_fill_forward_path(struct net_device_path_ctx *ctx,
80662306a36Sopenharmony_ci				      struct net_device_path *path)
80762306a36Sopenharmony_ci{
80862306a36Sopenharmony_ci	struct vlan_dev_priv *vlan = vlan_dev_priv(ctx->dev);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	path->type = DEV_PATH_VLAN;
81162306a36Sopenharmony_ci	path->encap.id = vlan->vlan_id;
81262306a36Sopenharmony_ci	path->encap.proto = vlan->vlan_proto;
81362306a36Sopenharmony_ci	path->dev = ctx->dev;
81462306a36Sopenharmony_ci	ctx->dev = vlan->real_dev;
81562306a36Sopenharmony_ci	if (ctx->num_vlans >= ARRAY_SIZE(ctx->vlan))
81662306a36Sopenharmony_ci		return -ENOSPC;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	ctx->vlan[ctx->num_vlans].id = vlan->vlan_id;
81962306a36Sopenharmony_ci	ctx->vlan[ctx->num_vlans].proto = vlan->vlan_proto;
82062306a36Sopenharmony_ci	ctx->num_vlans++;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	return 0;
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MACSEC)
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_cistatic const struct macsec_ops *vlan_get_macsec_ops(const struct macsec_context *ctx)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	return vlan_dev_priv(ctx->netdev)->real_dev->macsec_ops;
83062306a36Sopenharmony_ci}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cistatic int vlan_macsec_offload(int (* const func)(struct macsec_context *),
83362306a36Sopenharmony_ci			       struct macsec_context *ctx)
83462306a36Sopenharmony_ci{
83562306a36Sopenharmony_ci	if (unlikely(!func))
83662306a36Sopenharmony_ci		return 0;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	return (*func)(ctx);
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic int vlan_macsec_dev_open(struct macsec_context *ctx)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	if (!ops)
84662306a36Sopenharmony_ci		return -EOPNOTSUPP;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_dev_open, ctx);
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_cistatic int vlan_macsec_dev_stop(struct macsec_context *ctx)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	if (!ops)
85662306a36Sopenharmony_ci		return -EOPNOTSUPP;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_dev_stop, ctx);
85962306a36Sopenharmony_ci}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_cistatic int vlan_macsec_add_secy(struct macsec_context *ctx)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	if (!ops)
86662306a36Sopenharmony_ci		return -EOPNOTSUPP;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_add_secy, ctx);
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_cistatic int vlan_macsec_upd_secy(struct macsec_context *ctx)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	if (!ops)
87662306a36Sopenharmony_ci		return -EOPNOTSUPP;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_upd_secy, ctx);
87962306a36Sopenharmony_ci}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_cistatic int vlan_macsec_del_secy(struct macsec_context *ctx)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	if (!ops)
88662306a36Sopenharmony_ci		return -EOPNOTSUPP;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_del_secy, ctx);
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cistatic int vlan_macsec_add_rxsc(struct macsec_context *ctx)
89262306a36Sopenharmony_ci{
89362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	if (!ops)
89662306a36Sopenharmony_ci		return -EOPNOTSUPP;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_add_rxsc, ctx);
89962306a36Sopenharmony_ci}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_cistatic int vlan_macsec_upd_rxsc(struct macsec_context *ctx)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	if (!ops)
90662306a36Sopenharmony_ci		return -EOPNOTSUPP;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_upd_rxsc, ctx);
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cistatic int vlan_macsec_del_rxsc(struct macsec_context *ctx)
91262306a36Sopenharmony_ci{
91362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if (!ops)
91662306a36Sopenharmony_ci		return -EOPNOTSUPP;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_del_rxsc, ctx);
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_cistatic int vlan_macsec_add_rxsa(struct macsec_context *ctx)
92262306a36Sopenharmony_ci{
92362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	if (!ops)
92662306a36Sopenharmony_ci		return -EOPNOTSUPP;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_add_rxsa, ctx);
92962306a36Sopenharmony_ci}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_cistatic int vlan_macsec_upd_rxsa(struct macsec_context *ctx)
93262306a36Sopenharmony_ci{
93362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	if (!ops)
93662306a36Sopenharmony_ci		return -EOPNOTSUPP;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_upd_rxsa, ctx);
93962306a36Sopenharmony_ci}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_cistatic int vlan_macsec_del_rxsa(struct macsec_context *ctx)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	if (!ops)
94662306a36Sopenharmony_ci		return -EOPNOTSUPP;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_del_rxsa, ctx);
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cistatic int vlan_macsec_add_txsa(struct macsec_context *ctx)
95262306a36Sopenharmony_ci{
95362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	if (!ops)
95662306a36Sopenharmony_ci		return -EOPNOTSUPP;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_add_txsa, ctx);
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cistatic int vlan_macsec_upd_txsa(struct macsec_context *ctx)
96262306a36Sopenharmony_ci{
96362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	if (!ops)
96662306a36Sopenharmony_ci		return -EOPNOTSUPP;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_upd_txsa, ctx);
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cistatic int vlan_macsec_del_txsa(struct macsec_context *ctx)
97262306a36Sopenharmony_ci{
97362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (!ops)
97662306a36Sopenharmony_ci		return -EOPNOTSUPP;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_del_txsa, ctx);
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cistatic int vlan_macsec_get_dev_stats(struct macsec_context *ctx)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	if (!ops)
98662306a36Sopenharmony_ci		return -EOPNOTSUPP;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_get_dev_stats, ctx);
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_cistatic int vlan_macsec_get_tx_sc_stats(struct macsec_context *ctx)
99262306a36Sopenharmony_ci{
99362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	if (!ops)
99662306a36Sopenharmony_ci		return -EOPNOTSUPP;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_get_tx_sc_stats, ctx);
99962306a36Sopenharmony_ci}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_cistatic int vlan_macsec_get_tx_sa_stats(struct macsec_context *ctx)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	if (!ops)
100662306a36Sopenharmony_ci		return -EOPNOTSUPP;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_get_tx_sa_stats, ctx);
100962306a36Sopenharmony_ci}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_cistatic int vlan_macsec_get_rx_sc_stats(struct macsec_context *ctx)
101262306a36Sopenharmony_ci{
101362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	if (!ops)
101662306a36Sopenharmony_ci		return -EOPNOTSUPP;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_get_rx_sc_stats, ctx);
101962306a36Sopenharmony_ci}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_cistatic int vlan_macsec_get_rx_sa_stats(struct macsec_context *ctx)
102262306a36Sopenharmony_ci{
102362306a36Sopenharmony_ci	const struct macsec_ops *ops = vlan_get_macsec_ops(ctx);
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	if (!ops)
102662306a36Sopenharmony_ci		return -EOPNOTSUPP;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	return vlan_macsec_offload(ops->mdo_get_rx_sa_stats, ctx);
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cistatic const struct macsec_ops macsec_offload_ops = {
103262306a36Sopenharmony_ci	/* Device wide */
103362306a36Sopenharmony_ci	.mdo_dev_open = vlan_macsec_dev_open,
103462306a36Sopenharmony_ci	.mdo_dev_stop = vlan_macsec_dev_stop,
103562306a36Sopenharmony_ci	/* SecY */
103662306a36Sopenharmony_ci	.mdo_add_secy = vlan_macsec_add_secy,
103762306a36Sopenharmony_ci	.mdo_upd_secy = vlan_macsec_upd_secy,
103862306a36Sopenharmony_ci	.mdo_del_secy = vlan_macsec_del_secy,
103962306a36Sopenharmony_ci	/* Security channels */
104062306a36Sopenharmony_ci	.mdo_add_rxsc = vlan_macsec_add_rxsc,
104162306a36Sopenharmony_ci	.mdo_upd_rxsc = vlan_macsec_upd_rxsc,
104262306a36Sopenharmony_ci	.mdo_del_rxsc = vlan_macsec_del_rxsc,
104362306a36Sopenharmony_ci	/* Security associations */
104462306a36Sopenharmony_ci	.mdo_add_rxsa = vlan_macsec_add_rxsa,
104562306a36Sopenharmony_ci	.mdo_upd_rxsa = vlan_macsec_upd_rxsa,
104662306a36Sopenharmony_ci	.mdo_del_rxsa = vlan_macsec_del_rxsa,
104762306a36Sopenharmony_ci	.mdo_add_txsa = vlan_macsec_add_txsa,
104862306a36Sopenharmony_ci	.mdo_upd_txsa = vlan_macsec_upd_txsa,
104962306a36Sopenharmony_ci	.mdo_del_txsa = vlan_macsec_del_txsa,
105062306a36Sopenharmony_ci	/* Statistics */
105162306a36Sopenharmony_ci	.mdo_get_dev_stats = vlan_macsec_get_dev_stats,
105262306a36Sopenharmony_ci	.mdo_get_tx_sc_stats = vlan_macsec_get_tx_sc_stats,
105362306a36Sopenharmony_ci	.mdo_get_tx_sa_stats = vlan_macsec_get_tx_sa_stats,
105462306a36Sopenharmony_ci	.mdo_get_rx_sc_stats = vlan_macsec_get_rx_sc_stats,
105562306a36Sopenharmony_ci	.mdo_get_rx_sa_stats = vlan_macsec_get_rx_sa_stats,
105662306a36Sopenharmony_ci};
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci#endif
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_cistatic const struct ethtool_ops vlan_ethtool_ops = {
106162306a36Sopenharmony_ci	.get_link_ksettings	= vlan_ethtool_get_link_ksettings,
106262306a36Sopenharmony_ci	.get_drvinfo	        = vlan_ethtool_get_drvinfo,
106362306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
106462306a36Sopenharmony_ci	.get_ts_info		= vlan_ethtool_get_ts_info,
106562306a36Sopenharmony_ci};
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_cistatic const struct net_device_ops vlan_netdev_ops = {
106862306a36Sopenharmony_ci	.ndo_change_mtu		= vlan_dev_change_mtu,
106962306a36Sopenharmony_ci	.ndo_init		= vlan_dev_init,
107062306a36Sopenharmony_ci	.ndo_uninit		= vlan_dev_uninit,
107162306a36Sopenharmony_ci	.ndo_open		= vlan_dev_open,
107262306a36Sopenharmony_ci	.ndo_stop		= vlan_dev_stop,
107362306a36Sopenharmony_ci	.ndo_start_xmit =  vlan_dev_hard_start_xmit,
107462306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
107562306a36Sopenharmony_ci	.ndo_set_mac_address	= vlan_dev_set_mac_address,
107662306a36Sopenharmony_ci	.ndo_set_rx_mode	= vlan_dev_set_rx_mode,
107762306a36Sopenharmony_ci	.ndo_change_rx_flags	= vlan_dev_change_rx_flags,
107862306a36Sopenharmony_ci	.ndo_eth_ioctl		= vlan_dev_ioctl,
107962306a36Sopenharmony_ci	.ndo_neigh_setup	= vlan_dev_neigh_setup,
108062306a36Sopenharmony_ci	.ndo_get_stats64	= vlan_dev_get_stats64,
108162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_FCOE)
108262306a36Sopenharmony_ci	.ndo_fcoe_ddp_setup	= vlan_dev_fcoe_ddp_setup,
108362306a36Sopenharmony_ci	.ndo_fcoe_ddp_done	= vlan_dev_fcoe_ddp_done,
108462306a36Sopenharmony_ci	.ndo_fcoe_enable	= vlan_dev_fcoe_enable,
108562306a36Sopenharmony_ci	.ndo_fcoe_disable	= vlan_dev_fcoe_disable,
108662306a36Sopenharmony_ci	.ndo_fcoe_ddp_target	= vlan_dev_fcoe_ddp_target,
108762306a36Sopenharmony_ci#endif
108862306a36Sopenharmony_ci#ifdef NETDEV_FCOE_WWNN
108962306a36Sopenharmony_ci	.ndo_fcoe_get_wwn	= vlan_dev_fcoe_get_wwn,
109062306a36Sopenharmony_ci#endif
109162306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
109262306a36Sopenharmony_ci	.ndo_poll_controller	= vlan_dev_poll_controller,
109362306a36Sopenharmony_ci	.ndo_netpoll_setup	= vlan_dev_netpoll_setup,
109462306a36Sopenharmony_ci	.ndo_netpoll_cleanup	= vlan_dev_netpoll_cleanup,
109562306a36Sopenharmony_ci#endif
109662306a36Sopenharmony_ci	.ndo_fix_features	= vlan_dev_fix_features,
109762306a36Sopenharmony_ci	.ndo_get_iflink		= vlan_dev_get_iflink,
109862306a36Sopenharmony_ci	.ndo_fill_forward_path	= vlan_dev_fill_forward_path,
109962306a36Sopenharmony_ci	.ndo_hwtstamp_get	= vlan_hwtstamp_get,
110062306a36Sopenharmony_ci	.ndo_hwtstamp_set	= vlan_hwtstamp_set,
110162306a36Sopenharmony_ci};
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_cistatic void vlan_dev_free(struct net_device *dev)
110462306a36Sopenharmony_ci{
110562306a36Sopenharmony_ci	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	free_percpu(vlan->vlan_pcpu_stats);
110862306a36Sopenharmony_ci	vlan->vlan_pcpu_stats = NULL;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	/* Get rid of the vlan's reference to real_dev */
111162306a36Sopenharmony_ci	netdev_put(vlan->real_dev, &vlan->dev_tracker);
111262306a36Sopenharmony_ci}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_civoid vlan_setup(struct net_device *dev)
111562306a36Sopenharmony_ci{
111662306a36Sopenharmony_ci	ether_setup(dev);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	dev->priv_flags		|= IFF_802_1Q_VLAN | IFF_NO_QUEUE;
111962306a36Sopenharmony_ci	dev->priv_flags		|= IFF_UNICAST_FLT;
112062306a36Sopenharmony_ci	dev->priv_flags		&= ~IFF_TX_SKB_SHARING;
112162306a36Sopenharmony_ci	netif_keep_dst(dev);
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	dev->netdev_ops		= &vlan_netdev_ops;
112462306a36Sopenharmony_ci	dev->needs_free_netdev	= true;
112562306a36Sopenharmony_ci	dev->priv_destructor	= vlan_dev_free;
112662306a36Sopenharmony_ci	dev->ethtool_ops	= &vlan_ethtool_ops;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MACSEC)
112962306a36Sopenharmony_ci	dev->macsec_ops		= &macsec_offload_ops;
113062306a36Sopenharmony_ci#endif
113162306a36Sopenharmony_ci	dev->min_mtu		= 0;
113262306a36Sopenharmony_ci	dev->max_mtu		= ETH_MAX_MTU;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	eth_zero_addr(dev->broadcast);
113562306a36Sopenharmony_ci}
1136