--- zzzz-none-000/linux-3.10.107/net/8021q/vlan_core.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/net/8021q/vlan_core.c 2021-02-04 17:41:59.000000000 +0000 @@ -5,11 +5,19 @@ #include #include "vlan.h" +#if defined(CONFIG_LTQ_ETH_OAM) || defined(CONFIG_LTQ_ETH_OAM_MODULE) +/* Support for ethernet OAM with VLAN */ +#include + +struct net_device * (*fp_ltq_eth_oam_dev)(void)=NULL; +EXPORT_SYMBOL(fp_ltq_eth_oam_dev); +#endif + bool vlan_do_receive(struct sk_buff **skbp) { struct sk_buff *skb = *skbp; __be16 vlan_proto = skb->vlan_proto; - u16 vlan_id = vlan_tx_tag_get_id(skb); + u16 vlan_id = skb_vlan_tag_get_id(skb); struct net_device *vlan_dev; struct vlan_pcpu_stats *rx_stats; @@ -22,15 +30,17 @@ return false; skb->dev = vlan_dev; - if (skb->pkt_type == PACKET_OTHERHOST) { + if (unlikely(skb->pkt_type == PACKET_OTHERHOST)) { /* Our lower layer thinks this is not local, let's make sure. * This allows the VLAN to have a different MAC than the * underlying device, and still route correctly. */ - if (ether_addr_equal(eth_hdr(skb)->h_dest, vlan_dev->dev_addr)) + if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, vlan_dev->dev_addr)) skb->pkt_type = PACKET_HOST; } - if (!(vlan_dev_priv(vlan_dev)->flags & VLAN_FLAG_REORDER_HDR)) { + if (!(vlan_dev_priv(vlan_dev)->flags & VLAN_FLAG_REORDER_HDR) && + !netif_is_macvlan_port(vlan_dev) && + !netif_is_bridge_port(vlan_dev)) { unsigned int offset = skb->data - skb_mac_header(skb); /* @@ -59,11 +69,56 @@ rx_stats->rx_multicast++; u64_stats_update_end(&rx_stats->syncp); +#if IS_ENABLED(CONFIG_LTQ_ETH_OAM) + if (skb->protocol == ETH_P_CFM && fp_ltq_eth_oam_dev != NULL) + skb->dev = fp_ltq_eth_oam_dev(); +#endif + return true; } +/* Update the VLAN device with statistics from network offload engines */ +void __vlan_dev_update_accel_stats(struct net_device *dev, + struct rtnl_link_stats64 *nlstats) +{ + struct vlan_pcpu_stats *stats; + + if (!is_vlan_dev(dev)) + return; + + stats = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, 0); + + u64_stats_update_begin(&stats->syncp); + stats->rx_packets += nlstats->rx_packets; + stats->rx_bytes += nlstats->rx_bytes; + stats->tx_packets += nlstats->tx_packets; + stats->tx_bytes += nlstats->tx_bytes; + u64_stats_update_end(&stats->syncp); +} +EXPORT_SYMBOL(__vlan_dev_update_accel_stats); + +/* Lookup the 802.1p egress_map table and return the 802.1p value */ +u16 vlan_dev_get_egress_prio(struct net_device *dev, u32 skb_prio) +{ + struct vlan_priority_tci_mapping *mp; + + mp = vlan_dev_priv(dev)->egress_priority_map[(skb_prio & 0xf)]; + while (mp) { + if (mp->priority == skb_prio) { + /* This should already be shifted + * to mask correctly with the + * VLAN's TCI + */ + return mp->vlan_qos; + } + mp = mp->next; + } + return 0; +} +EXPORT_SYMBOL(vlan_dev_get_egress_prio); + /* Must be invoked with rcu_read_lock. */ -struct net_device *__vlan_find_dev_deep(struct net_device *dev, +struct net_device *__vlan_find_dev_deep_rcu(struct net_device *dev, __be16 vlan_proto, u16 vlan_id) { struct vlan_info *vlan_info = rcu_dereference(dev->vlan_info); @@ -81,78 +136,42 @@ upper_dev = netdev_master_upper_dev_get_rcu(dev); if (upper_dev) - return __vlan_find_dev_deep(upper_dev, + return __vlan_find_dev_deep_rcu(upper_dev, vlan_proto, vlan_id); } return NULL; } -EXPORT_SYMBOL(__vlan_find_dev_deep); +EXPORT_SYMBOL(__vlan_find_dev_deep_rcu); struct net_device *vlan_dev_real_dev(const struct net_device *dev) { - return vlan_dev_priv(dev)->real_dev; + struct net_device *ret = vlan_dev_priv(dev)->real_dev; + + while (is_vlan_dev(ret)) + ret = vlan_dev_priv(ret)->real_dev; + + return ret; } EXPORT_SYMBOL(vlan_dev_real_dev); -u16 vlan_dev_vlan_id(const struct net_device *dev) +struct net_device *vlan_dev_next_dev(const struct net_device *dev) { - return vlan_dev_priv(dev)->vlan_id; + return vlan_dev_priv(dev)->real_dev; } -EXPORT_SYMBOL(vlan_dev_vlan_id); +EXPORT_SYMBOL(vlan_dev_next_dev); -static struct sk_buff *vlan_reorder_header(struct sk_buff *skb) +u16 vlan_dev_vlan_id(const struct net_device *dev) { - if (skb_cow(skb, skb_headroom(skb)) < 0) { - kfree_skb(skb); - return NULL; - } - - memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN); - skb->mac_header += VLAN_HLEN; - return skb; + return vlan_dev_priv(dev)->vlan_id; } +EXPORT_SYMBOL(vlan_dev_vlan_id); -struct sk_buff *vlan_untag(struct sk_buff *skb) +__be16 vlan_dev_vlan_proto(const struct net_device *dev) { - struct vlan_hdr *vhdr; - u16 vlan_tci; - - if (unlikely(vlan_tx_tag_present(skb))) { - /* vlan_tci is already set-up so leave this for another time */ - return skb; - } - - skb = skb_share_check(skb, GFP_ATOMIC); - if (unlikely(!skb)) - goto err_free; - - if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) - goto err_free; - - vhdr = (struct vlan_hdr *) skb->data; - vlan_tci = ntohs(vhdr->h_vlan_TCI); - __vlan_hwaccel_put_tag(skb, skb->protocol, vlan_tci); - - skb_pull_rcsum(skb, VLAN_HLEN); - vlan_set_encap_proto(skb, vhdr); - - skb = vlan_reorder_header(skb); - if (unlikely(!skb)) - goto err_free; - - skb_reset_network_header(skb); - skb_reset_transport_header(skb); - skb_reset_mac_len(skb); - - return skb; - -err_free: - kfree_skb(skb); - return NULL; + return vlan_dev_priv(dev)->vlan_proto; } -EXPORT_SYMBOL(vlan_untag); - +EXPORT_SYMBOL(vlan_dev_vlan_proto); /* * vlan info and vid list @@ -248,7 +267,10 @@ return -ENOMEM; if (vlan_hw_filter_capable(dev, vid_info)) { - err = ops->ndo_vlan_rx_add_vid(dev, proto, vid); + if (netif_device_present(dev)) + err = ops->ndo_vlan_rx_add_vid(dev, proto, vid); + else + err = -ENODEV; if (err) { kfree(vid_info); return err; @@ -306,7 +328,10 @@ int err; if (vlan_hw_filter_capable(dev, vid_info)) { - err = ops->ndo_vlan_rx_kill_vid(dev, proto, vid); + if (netif_device_present(dev)) + err = ops->ndo_vlan_rx_kill_vid(dev, proto, vid); + else + err = -ENODEV; if (err) { pr_warn("failed to kill vid %04x/%d for device %s\n", proto, vid, dev->name);