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