--- zzzz-none-000/linux-3.10.107/net/ethernet/eth.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/net/ethernet/eth.c 2021-02-04 17:41:59.000000000 +0000 @@ -58,7 +58,8 @@ #include #include #include -#include +#include +#include __setup("ether=", netdev_boot_setup); @@ -104,7 +105,7 @@ */ if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { - memset(eth->h_dest, 0, ETH_ALEN); + eth_zero_addr(eth->h_dest); return ETH_HLEN; } @@ -113,37 +114,43 @@ EXPORT_SYMBOL(eth_header); /** - * eth_rebuild_header- rebuild the Ethernet MAC header. - * @skb: socket buffer to update + * eth_get_headlen - determine the length of header for an ethernet frame + * @data: pointer to start of frame + * @len: total length of frame * - * This is called after an ARP or IPV6 ndisc it's resolution on this - * sk_buff. We now let protocol (ARP) fill in the other fields. - * - * This routine CANNOT use cached dst->neigh! - * Really, it is used only when dst->neigh is wrong. + * Make a best effort attempt to pull the length for all of the headers for + * a given frame in a linear buffer. */ -int eth_rebuild_header(struct sk_buff *skb) +u32 eth_get_headlen(void *data, unsigned int len) { - struct ethhdr *eth = (struct ethhdr *)skb->data; - struct net_device *dev = skb->dev; + const struct ethhdr *eth = (const struct ethhdr *)data; + struct flow_keys keys; - switch (eth->h_proto) { -#ifdef CONFIG_INET - case htons(ETH_P_IP): - return arp_find(eth->h_dest, skb); -#endif - default: - printk(KERN_DEBUG - "%s: unable to resolve type %X addresses.\n", - dev->name, ntohs(eth->h_proto)); + /* this should never happen, but better safe than sorry */ + if (unlikely(len < sizeof(*eth))) + return len; - memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); - break; - } + /* parse any remaining L2/L3 headers, check for L4 */ + if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto, + sizeof(*eth), len, 0)) + return max_t(u32, keys.control.thoff, sizeof(*eth)); - return 0; + /* parse for any L4 headers */ + return min_t(u32, __skb_get_poff(NULL, data, &keys, len), len); +} +EXPORT_SYMBOL(eth_get_headlen); + +static inline bool +eth_check_local_mask(const void *addr1, const void *addr2, const void *mask) +{ + const u16 *a1 = addr1; + const u16 *a2 = addr2; + const u16 *m = mask; + + return (((a1[0] ^ a2[0]) & ~m[0]) | + ((a1[1] ^ a2[1]) & ~m[1]) | + ((a1[2] ^ a2[2]) & ~m[2])); } -EXPORT_SYMBOL(eth_rebuild_header); /** * eth_type_trans - determine the packet's protocol ID. @@ -156,32 +163,34 @@ */ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) { - struct ethhdr *eth; + unsigned short _service_access_point; + const unsigned short *sap; + const struct ethhdr *eth; skb->dev = dev; + +#ifdef CONFIG_ETHERNET_PACKET_MANGLE + if (dev->eth_mangle_rx) + dev->eth_mangle_rx(dev, skb); +#endif + skb_reset_mac_header(skb); + + eth = (struct ethhdr *)skb->data; skb_pull_inline(skb, ETH_HLEN); - eth = eth_hdr(skb); - if (unlikely(is_multicast_ether_addr(eth->h_dest))) { + if (unlikely(is_multicast_ether_addr_64bits(eth->h_dest))) { if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast)) skb->pkt_type = PACKET_BROADCAST; else skb->pkt_type = PACKET_MULTICAST; } - - /* - * This ALLMULTI check should be redundant by 1.4 - * so don't forget to remove it. - * - * Seems, you forgot to remove it. All silly devices - * seems to set IFF_PROMISC. - */ - - else if (1 /*dev->flags&IFF_PROMISC */ ) { - if (unlikely(!ether_addr_equal_64bits(eth->h_dest, - dev->dev_addr))) - skb->pkt_type = PACKET_OTHERHOST; + else if (unlikely(!ether_addr_equal_64bits(eth->h_dest, + dev->dev_addr))) { + skb->pkt_type = PACKET_OTHERHOST; + if (eth_check_local_mask(eth->h_dest, dev->dev_addr, + dev->local_addr_mask)) + skb->gro_skip = 1; } /* @@ -190,12 +199,10 @@ * variants has been configured on the receiving interface, * and if so, set skb->protocol without looking at the packet. */ - if (netdev_uses_dsa_tags(dev)) - return htons(ETH_P_DSA); - if (netdev_uses_trailer_tags(dev)) - return htons(ETH_P_TRAILER); + if (unlikely(netdev_uses_dsa(dev))) + return htons(ETH_P_XDSA); - if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN) + if (likely(eth_proto_is_802_3(eth->h_proto))) return eth->h_proto; /* @@ -204,7 +211,8 @@ * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This * won't work for fault tolerant netware but does for the rest. */ - if (skb->len >= 2 && *(unsigned short *)(skb->data) == 0xFFFF) + sap = skb_header_pointer(skb, 0, sizeof(*sap), &_service_access_point); + if (sap && *sap == 0xFFFF) return htons(ETH_P_802_3); /* @@ -352,7 +360,6 @@ const struct header_ops eth_header_ops ____cacheline_aligned = { .create = eth_header, .parse = eth_header_parse, - .rebuild = eth_rebuild_header, .cache = eth_header_cache, .cache_update = eth_header_cache_update, }; @@ -368,13 +375,14 @@ dev->header_ops = ð_header_ops; dev->type = ARPHRD_ETHER; dev->hard_header_len = ETH_HLEN; + dev->min_header_len = ETH_HLEN; dev->mtu = ETH_DATA_LEN; dev->addr_len = ETH_ALEN; dev->tx_queue_len = 1000; /* Ethernet wants good queues */ dev->flags = IFF_BROADCAST|IFF_MULTICAST; dev->priv_flags |= IFF_TX_SKB_SHARING; - memset(dev->broadcast, 0xFF, ETH_ALEN); + eth_broadcast_addr(dev->broadcast); } EXPORT_SYMBOL(ether_setup); @@ -397,31 +405,111 @@ struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs, unsigned int rxqs) { - return alloc_netdev_mqs(sizeof_priv, "eth%d", ether_setup, txqs, rxqs); + return alloc_netdev_mqs(sizeof_priv, "eth%d", NET_NAME_UNKNOWN, + ether_setup, txqs, rxqs); } EXPORT_SYMBOL(alloc_etherdev_mqs); -static size_t _format_mac_addr(char *buf, int buflen, - const unsigned char *addr, int len) +ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len) { - int i; - char *cp = buf; + return scnprintf(buf, PAGE_SIZE, "%*phC\n", len, addr); +} +EXPORT_SYMBOL(sysfs_format_mac); - for (i = 0; i < len; i++) { - cp += scnprintf(cp, buflen - (cp - buf), "%02x", addr[i]); - if (i == len - 1) - break; - cp += scnprintf(cp, buflen - (cp - buf), ":"); +struct sk_buff **eth_gro_receive(struct sk_buff **head, + struct sk_buff *skb) +{ + struct sk_buff *p, **pp = NULL; + struct ethhdr *eh, *eh2; + unsigned int hlen, off_eth; + const struct packet_offload *ptype; + __be16 type; + int flush = 1; + + off_eth = skb_gro_offset(skb); + hlen = off_eth + sizeof(*eh); + eh = skb_gro_header_fast(skb, off_eth); + if (skb_gro_header_hard(skb, hlen)) { + eh = skb_gro_header_slow(skb, hlen, off_eth); + if (unlikely(!eh)) + goto out; } - return cp - buf; -} -ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len) + flush = 0; + + for (p = *head; p; p = p->next) { + if (!NAPI_GRO_CB(p)->same_flow) + continue; + + eh2 = (struct ethhdr *)(p->data + off_eth); + if (compare_ether_header(eh, eh2)) { + NAPI_GRO_CB(p)->same_flow = 0; + continue; + } + } + + type = eh->h_proto; + + rcu_read_lock(); + ptype = gro_find_receive_by_type(type); + if (ptype == NULL) { + flush = 1; + goto out_unlock; + } + + skb_gro_pull(skb, sizeof(*eh)); + skb_gro_postpull_rcsum(skb, eh, sizeof(*eh)); + pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb); + +out_unlock: + rcu_read_unlock(); +out: + NAPI_GRO_CB(skb)->flush |= flush; + + return pp; +} +EXPORT_SYMBOL(eth_gro_receive); + +int eth_gro_complete(struct sk_buff *skb, int nhoff) +{ + struct ethhdr *eh = (struct ethhdr *)(skb->data + nhoff); + __be16 type = eh->h_proto; + struct packet_offload *ptype; + int err = -ENOSYS; + + if (skb->encapsulation) + skb_set_inner_mac_header(skb, nhoff); + + rcu_read_lock(); + ptype = gro_find_complete_by_type(type); + if (ptype != NULL) + err = ptype->callbacks.gro_complete(skb, nhoff + + sizeof(struct ethhdr)); + + rcu_read_unlock(); + return err; +} +EXPORT_SYMBOL(eth_gro_complete); + +static struct packet_offload eth_packet_offload __read_mostly = { + .type = cpu_to_be16(ETH_P_TEB), + .priority = 10, + .callbacks = { + .gro_receive = eth_gro_receive, + .gro_complete = eth_gro_complete, + }, +}; + +void (*ssdk_update_rmon_cnt_hook) + (struct avm_hw_rmon_counter *res, u32 devid, u32 port) = NULL; +EXPORT_SYMBOL(ssdk_update_rmon_cnt_hook); + +static int __init eth_offload_init(void) { - size_t l; + ssdk_update_rmon_cnt_hook = NULL; + dev_add_offload(ð_packet_offload); - l = _format_mac_addr(buf, PAGE_SIZE, addr, len); - l += scnprintf(buf + l, PAGE_SIZE - l, "\n"); - return (ssize_t)l; + return 0; } -EXPORT_SYMBOL(sysfs_format_mac); + +fs_initcall(eth_offload_init);