18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * INET An implementation of the TCP/IP protocol suite for the LINUX 48c2ecf20Sopenharmony_ci * operating system. INET is implemented using the BSD Socket 58c2ecf20Sopenharmony_ci * interface as the means of communication with the user level. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Ethernet-type device handling. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Version: @(#)eth.c 1.0.7 05/25/93 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Authors: Ross Biro 128c2ecf20Sopenharmony_ci * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> 138c2ecf20Sopenharmony_ci * Mark Evans, <evansmp@uhura.aston.ac.uk> 148c2ecf20Sopenharmony_ci * Florian La Roche, <rzsfl@rz.uni-sb.de> 158c2ecf20Sopenharmony_ci * Alan Cox, <gw4pts@gw4pts.ampr.org> 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Fixes: 188c2ecf20Sopenharmony_ci * Mr Linux : Arp problems 198c2ecf20Sopenharmony_ci * Alan Cox : Generic queue tidyup (very tiny here) 208c2ecf20Sopenharmony_ci * Alan Cox : eth_header ntohs should be htons 218c2ecf20Sopenharmony_ci * Alan Cox : eth_rebuild_header missing an htons and 228c2ecf20Sopenharmony_ci * minor other things. 238c2ecf20Sopenharmony_ci * Tegge : Arp bug fixes. 248c2ecf20Sopenharmony_ci * Florian : Removed many unnecessary functions, code cleanup 258c2ecf20Sopenharmony_ci * and changes for new arp and skbuff. 268c2ecf20Sopenharmony_ci * Alan Cox : Redid header building to reflect new format. 278c2ecf20Sopenharmony_ci * Alan Cox : ARP only when compiled with CONFIG_INET 288c2ecf20Sopenharmony_ci * Greg Page : 802.2 and SNAP stuff. 298c2ecf20Sopenharmony_ci * Alan Cox : MAC layer pointers/new format. 308c2ecf20Sopenharmony_ci * Paul Gortmaker : eth_copy_and_sum shouldn't csum padding. 318c2ecf20Sopenharmony_ci * Alan Cox : Protect against forwarding explosions with 328c2ecf20Sopenharmony_ci * older network drivers and IFF_ALLMULTI. 338c2ecf20Sopenharmony_ci * Christer Weinigel : Better rebuild header message. 348c2ecf20Sopenharmony_ci * Andrew Morton : 26Feb01: kill ether_setup() - use netdev_boot_setup(). 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci#include <linux/module.h> 378c2ecf20Sopenharmony_ci#include <linux/types.h> 388c2ecf20Sopenharmony_ci#include <linux/kernel.h> 398c2ecf20Sopenharmony_ci#include <linux/string.h> 408c2ecf20Sopenharmony_ci#include <linux/mm.h> 418c2ecf20Sopenharmony_ci#include <linux/socket.h> 428c2ecf20Sopenharmony_ci#include <linux/in.h> 438c2ecf20Sopenharmony_ci#include <linux/inet.h> 448c2ecf20Sopenharmony_ci#include <linux/ip.h> 458c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 468c2ecf20Sopenharmony_ci#include <linux/nvmem-consumer.h> 478c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 488c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 498c2ecf20Sopenharmony_ci#include <linux/errno.h> 508c2ecf20Sopenharmony_ci#include <linux/init.h> 518c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 528c2ecf20Sopenharmony_ci#include <linux/of_net.h> 538c2ecf20Sopenharmony_ci#include <linux/pci.h> 548c2ecf20Sopenharmony_ci#include <net/dst.h> 558c2ecf20Sopenharmony_ci#include <net/arp.h> 568c2ecf20Sopenharmony_ci#include <net/sock.h> 578c2ecf20Sopenharmony_ci#include <net/ipv6.h> 588c2ecf20Sopenharmony_ci#include <net/ip.h> 598c2ecf20Sopenharmony_ci#include <net/dsa.h> 608c2ecf20Sopenharmony_ci#include <net/flow_dissector.h> 618c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 628c2ecf20Sopenharmony_ci#include <net/pkt_sched.h> 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci__setup("ether=", netdev_boot_setup); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/** 678c2ecf20Sopenharmony_ci * eth_header - create the Ethernet header 688c2ecf20Sopenharmony_ci * @skb: buffer to alter 698c2ecf20Sopenharmony_ci * @dev: source device 708c2ecf20Sopenharmony_ci * @type: Ethernet type field 718c2ecf20Sopenharmony_ci * @daddr: destination address (NULL leave destination address) 728c2ecf20Sopenharmony_ci * @saddr: source address (NULL use device source address) 738c2ecf20Sopenharmony_ci * @len: packet length (<= skb->len) 748c2ecf20Sopenharmony_ci * 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * Set the protocol type. For a packet of type ETH_P_802_3/2 we put the length 778c2ecf20Sopenharmony_ci * in here instead. 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_ciint eth_header(struct sk_buff *skb, struct net_device *dev, 808c2ecf20Sopenharmony_ci unsigned short type, 818c2ecf20Sopenharmony_ci const void *daddr, const void *saddr, unsigned int len) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct ethhdr *eth = skb_push(skb, ETH_HLEN); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (type != ETH_P_802_3 && type != ETH_P_802_2) 868c2ecf20Sopenharmony_ci eth->h_proto = htons(type); 878c2ecf20Sopenharmony_ci else 888c2ecf20Sopenharmony_ci eth->h_proto = htons(len); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* 918c2ecf20Sopenharmony_ci * Set the source hardware address. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (!saddr) 958c2ecf20Sopenharmony_ci saddr = dev->dev_addr; 968c2ecf20Sopenharmony_ci memcpy(eth->h_source, saddr, ETH_ALEN); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (daddr) { 998c2ecf20Sopenharmony_ci memcpy(eth->h_dest, daddr, ETH_ALEN); 1008c2ecf20Sopenharmony_ci return ETH_HLEN; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* 1048c2ecf20Sopenharmony_ci * Anyway, the loopback-device should never use this function... 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { 1088c2ecf20Sopenharmony_ci eth_zero_addr(eth->h_dest); 1098c2ecf20Sopenharmony_ci return ETH_HLEN; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return -ETH_HLEN; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_header); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/** 1178c2ecf20Sopenharmony_ci * eth_get_headlen - determine the length of header for an ethernet frame 1188c2ecf20Sopenharmony_ci * @dev: pointer to network device 1198c2ecf20Sopenharmony_ci * @data: pointer to start of frame 1208c2ecf20Sopenharmony_ci * @len: total length of frame 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * Make a best effort attempt to pull the length for all of the headers for 1238c2ecf20Sopenharmony_ci * a given frame in a linear buffer. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ciu32 eth_get_headlen(const struct net_device *dev, void *data, unsigned int len) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci const unsigned int flags = FLOW_DISSECTOR_F_PARSE_1ST_FRAG; 1288c2ecf20Sopenharmony_ci const struct ethhdr *eth = (const struct ethhdr *)data; 1298c2ecf20Sopenharmony_ci struct flow_keys_basic keys; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* this should never happen, but better safe than sorry */ 1328c2ecf20Sopenharmony_ci if (unlikely(len < sizeof(*eth))) 1338c2ecf20Sopenharmony_ci return len; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* parse any remaining L2/L3 headers, check for L4 */ 1368c2ecf20Sopenharmony_ci if (!skb_flow_dissect_flow_keys_basic(dev_net(dev), NULL, &keys, data, 1378c2ecf20Sopenharmony_ci eth->h_proto, sizeof(*eth), 1388c2ecf20Sopenharmony_ci len, flags)) 1398c2ecf20Sopenharmony_ci return max_t(u32, keys.control.thoff, sizeof(*eth)); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* parse for any L4 headers */ 1428c2ecf20Sopenharmony_ci return min_t(u32, __skb_get_poff(NULL, data, &keys, len), len); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_get_headlen); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/** 1478c2ecf20Sopenharmony_ci * eth_type_trans - determine the packet's protocol ID. 1488c2ecf20Sopenharmony_ci * @skb: received socket data 1498c2ecf20Sopenharmony_ci * @dev: receiving network device 1508c2ecf20Sopenharmony_ci * 1518c2ecf20Sopenharmony_ci * The rule here is that we 1528c2ecf20Sopenharmony_ci * assume 802.3 if the type field is short enough to be a length. 1538c2ecf20Sopenharmony_ci * This is normal practice and works for any 'now in use' protocol. 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_ci__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci unsigned short _service_access_point; 1588c2ecf20Sopenharmony_ci const unsigned short *sap; 1598c2ecf20Sopenharmony_ci const struct ethhdr *eth; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci skb->dev = dev; 1628c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci eth = (struct ethhdr *)skb->data; 1658c2ecf20Sopenharmony_ci skb_pull_inline(skb, ETH_HLEN); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (unlikely(!ether_addr_equal_64bits(eth->h_dest, 1688c2ecf20Sopenharmony_ci dev->dev_addr))) { 1698c2ecf20Sopenharmony_ci if (unlikely(is_multicast_ether_addr_64bits(eth->h_dest))) { 1708c2ecf20Sopenharmony_ci if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast)) 1718c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_BROADCAST; 1728c2ecf20Sopenharmony_ci else 1738c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_MULTICAST; 1748c2ecf20Sopenharmony_ci } else { 1758c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_OTHERHOST; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * Some variants of DSA tagging don't have an ethertype field 1818c2ecf20Sopenharmony_ci * at all, so we check here whether one of those tagging 1828c2ecf20Sopenharmony_ci * variants has been configured on the receiving interface, 1838c2ecf20Sopenharmony_ci * and if so, set skb->protocol without looking at the packet. 1848c2ecf20Sopenharmony_ci * The DSA tagging protocol may be able to decode some but not all 1858c2ecf20Sopenharmony_ci * traffic (for example only for management). In that case give it the 1868c2ecf20Sopenharmony_ci * option to filter the packets from which it can decode source port 1878c2ecf20Sopenharmony_ci * information. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci if (unlikely(netdev_uses_dsa(dev)) && dsa_can_decode(skb, dev)) 1908c2ecf20Sopenharmony_ci return htons(ETH_P_XDSA); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (likely(eth_proto_is_802_3(eth->h_proto))) 1938c2ecf20Sopenharmony_ci return eth->h_proto; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* 1968c2ecf20Sopenharmony_ci * This is a magic hack to spot IPX packets. Older Novell breaks 1978c2ecf20Sopenharmony_ci * the protocol design and runs IPX over 802.3 without an 802.2 LLC 1988c2ecf20Sopenharmony_ci * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This 1998c2ecf20Sopenharmony_ci * won't work for fault tolerant netware but does for the rest. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci sap = skb_header_pointer(skb, 0, sizeof(*sap), &_service_access_point); 2028c2ecf20Sopenharmony_ci if (sap && *sap == 0xFFFF) 2038c2ecf20Sopenharmony_ci return htons(ETH_P_802_3); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* 2068c2ecf20Sopenharmony_ci * Real 802.2 LLC 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_ci return htons(ETH_P_802_2); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_type_trans); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci/** 2138c2ecf20Sopenharmony_ci * eth_header_parse - extract hardware address from packet 2148c2ecf20Sopenharmony_ci * @skb: packet to extract header from 2158c2ecf20Sopenharmony_ci * @haddr: destination buffer 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ciint eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci const struct ethhdr *eth = eth_hdr(skb); 2208c2ecf20Sopenharmony_ci memcpy(haddr, eth->h_source, ETH_ALEN); 2218c2ecf20Sopenharmony_ci return ETH_ALEN; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_header_parse); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/** 2268c2ecf20Sopenharmony_ci * eth_header_cache - fill cache entry from neighbour 2278c2ecf20Sopenharmony_ci * @neigh: source neighbour 2288c2ecf20Sopenharmony_ci * @hh: destination cache entry 2298c2ecf20Sopenharmony_ci * @type: Ethernet type field 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci * Create an Ethernet header template from the neighbour. 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_ciint eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh, __be16 type) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci struct ethhdr *eth; 2368c2ecf20Sopenharmony_ci const struct net_device *dev = neigh->dev; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci eth = (struct ethhdr *) 2398c2ecf20Sopenharmony_ci (((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth)))); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (type == htons(ETH_P_802_3)) 2428c2ecf20Sopenharmony_ci return -1; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci eth->h_proto = type; 2458c2ecf20Sopenharmony_ci memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); 2468c2ecf20Sopenharmony_ci memcpy(eth->h_dest, neigh->ha, ETH_ALEN); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Pairs with READ_ONCE() in neigh_resolve_output(), 2498c2ecf20Sopenharmony_ci * neigh_hh_output() and neigh_update_hhs(). 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci smp_store_release(&hh->hh_len, ETH_HLEN); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_header_cache); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/** 2588c2ecf20Sopenharmony_ci * eth_header_cache_update - update cache entry 2598c2ecf20Sopenharmony_ci * @hh: destination cache entry 2608c2ecf20Sopenharmony_ci * @dev: network device 2618c2ecf20Sopenharmony_ci * @haddr: new hardware address 2628c2ecf20Sopenharmony_ci * 2638c2ecf20Sopenharmony_ci * Called by Address Resolution module to notify changes in address. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_civoid eth_header_cache_update(struct hh_cache *hh, 2668c2ecf20Sopenharmony_ci const struct net_device *dev, 2678c2ecf20Sopenharmony_ci const unsigned char *haddr) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci memcpy(((u8 *) hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), 2708c2ecf20Sopenharmony_ci haddr, ETH_ALEN); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_header_cache_update); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/** 2758c2ecf20Sopenharmony_ci * eth_header_parser_protocol - extract protocol from L2 header 2768c2ecf20Sopenharmony_ci * @skb: packet to extract protocol from 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci__be16 eth_header_parse_protocol(const struct sk_buff *skb) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci const struct ethhdr *eth = eth_hdr(skb); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return eth->h_proto; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_header_parse_protocol); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/** 2878c2ecf20Sopenharmony_ci * eth_prepare_mac_addr_change - prepare for mac change 2888c2ecf20Sopenharmony_ci * @dev: network device 2898c2ecf20Sopenharmony_ci * @p: socket address 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_ciint eth_prepare_mac_addr_change(struct net_device *dev, void *p) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct sockaddr *addr = p; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev)) 2968c2ecf20Sopenharmony_ci return -EBUSY; 2978c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 2988c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 2998c2ecf20Sopenharmony_ci return 0; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_prepare_mac_addr_change); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/** 3048c2ecf20Sopenharmony_ci * eth_commit_mac_addr_change - commit mac change 3058c2ecf20Sopenharmony_ci * @dev: network device 3068c2ecf20Sopenharmony_ci * @p: socket address 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_civoid eth_commit_mac_addr_change(struct net_device *dev, void *p) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct sockaddr *addr = p; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_commit_mac_addr_change); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci/** 3178c2ecf20Sopenharmony_ci * eth_mac_addr - set new Ethernet hardware address 3188c2ecf20Sopenharmony_ci * @dev: network device 3198c2ecf20Sopenharmony_ci * @p: socket address 3208c2ecf20Sopenharmony_ci * 3218c2ecf20Sopenharmony_ci * Change hardware address of device. 3228c2ecf20Sopenharmony_ci * 3238c2ecf20Sopenharmony_ci * This doesn't change hardware matching, so needs to be overridden 3248c2ecf20Sopenharmony_ci * for most real devices. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_ciint eth_mac_addr(struct net_device *dev, void *p) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci int ret; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci ret = eth_prepare_mac_addr_change(dev, p); 3318c2ecf20Sopenharmony_ci if (ret < 0) 3328c2ecf20Sopenharmony_ci return ret; 3338c2ecf20Sopenharmony_ci eth_commit_mac_addr_change(dev, p); 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_mac_addr); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ciint eth_validate_addr(struct net_device *dev) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(dev->dev_addr)) 3418c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_validate_addr); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ciconst struct header_ops eth_header_ops ____cacheline_aligned = { 3488c2ecf20Sopenharmony_ci .create = eth_header, 3498c2ecf20Sopenharmony_ci .parse = eth_header_parse, 3508c2ecf20Sopenharmony_ci .cache = eth_header_cache, 3518c2ecf20Sopenharmony_ci .cache_update = eth_header_cache_update, 3528c2ecf20Sopenharmony_ci .parse_protocol = eth_header_parse_protocol, 3538c2ecf20Sopenharmony_ci}; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci/** 3568c2ecf20Sopenharmony_ci * ether_setup - setup Ethernet network device 3578c2ecf20Sopenharmony_ci * @dev: network device 3588c2ecf20Sopenharmony_ci * 3598c2ecf20Sopenharmony_ci * Fill in the fields of the device structure with Ethernet-generic values. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_civoid ether_setup(struct net_device *dev) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci dev->header_ops = ð_header_ops; 3648c2ecf20Sopenharmony_ci dev->type = ARPHRD_ETHER; 3658c2ecf20Sopenharmony_ci dev->hard_header_len = ETH_HLEN; 3668c2ecf20Sopenharmony_ci dev->min_header_len = ETH_HLEN; 3678c2ecf20Sopenharmony_ci dev->mtu = ETH_DATA_LEN; 3688c2ecf20Sopenharmony_ci dev->min_mtu = ETH_MIN_MTU; 3698c2ecf20Sopenharmony_ci dev->max_mtu = ETH_DATA_LEN; 3708c2ecf20Sopenharmony_ci dev->addr_len = ETH_ALEN; 3718c2ecf20Sopenharmony_ci dev->tx_queue_len = DEFAULT_TX_QUEUE_LEN; 3728c2ecf20Sopenharmony_ci dev->flags = IFF_BROADCAST|IFF_MULTICAST; 3738c2ecf20Sopenharmony_ci dev->priv_flags |= IFF_TX_SKB_SHARING; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci eth_broadcast_addr(dev->broadcast); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ether_setup); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/** 3818c2ecf20Sopenharmony_ci * alloc_etherdev_mqs - Allocates and sets up an Ethernet device 3828c2ecf20Sopenharmony_ci * @sizeof_priv: Size of additional driver-private structure to be allocated 3838c2ecf20Sopenharmony_ci * for this Ethernet device 3848c2ecf20Sopenharmony_ci * @txqs: The number of TX queues this device has. 3858c2ecf20Sopenharmony_ci * @rxqs: The number of RX queues this device has. 3868c2ecf20Sopenharmony_ci * 3878c2ecf20Sopenharmony_ci * Fill in the fields of the device structure with Ethernet-generic 3888c2ecf20Sopenharmony_ci * values. Basically does everything except registering the device. 3898c2ecf20Sopenharmony_ci * 3908c2ecf20Sopenharmony_ci * Constructs a new net device, complete with a private data area of 3918c2ecf20Sopenharmony_ci * size (sizeof_priv). A 32-byte (not bit) alignment is enforced for 3928c2ecf20Sopenharmony_ci * this private data area. 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistruct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs, 3968c2ecf20Sopenharmony_ci unsigned int rxqs) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci return alloc_netdev_mqs(sizeof_priv, "eth%d", NET_NAME_UNKNOWN, 3998c2ecf20Sopenharmony_ci ether_setup, txqs, rxqs); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(alloc_etherdev_mqs); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cissize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%*phC\n", len, addr); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sysfs_format_mac); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistruct sk_buff *eth_gro_receive(struct list_head *head, struct sk_buff *skb) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci const struct packet_offload *ptype; 4128c2ecf20Sopenharmony_ci unsigned int hlen, off_eth; 4138c2ecf20Sopenharmony_ci struct sk_buff *pp = NULL; 4148c2ecf20Sopenharmony_ci struct ethhdr *eh, *eh2; 4158c2ecf20Sopenharmony_ci struct sk_buff *p; 4168c2ecf20Sopenharmony_ci __be16 type; 4178c2ecf20Sopenharmony_ci int flush = 1; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci off_eth = skb_gro_offset(skb); 4208c2ecf20Sopenharmony_ci hlen = off_eth + sizeof(*eh); 4218c2ecf20Sopenharmony_ci eh = skb_gro_header_fast(skb, off_eth); 4228c2ecf20Sopenharmony_ci if (skb_gro_header_hard(skb, hlen)) { 4238c2ecf20Sopenharmony_ci eh = skb_gro_header_slow(skb, hlen, off_eth); 4248c2ecf20Sopenharmony_ci if (unlikely(!eh)) 4258c2ecf20Sopenharmony_ci goto out; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci flush = 0; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci list_for_each_entry(p, head, list) { 4318c2ecf20Sopenharmony_ci if (!NAPI_GRO_CB(p)->same_flow) 4328c2ecf20Sopenharmony_ci continue; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci eh2 = (struct ethhdr *)(p->data + off_eth); 4358c2ecf20Sopenharmony_ci if (compare_ether_header(eh, eh2)) { 4368c2ecf20Sopenharmony_ci NAPI_GRO_CB(p)->same_flow = 0; 4378c2ecf20Sopenharmony_ci continue; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci type = eh->h_proto; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci rcu_read_lock(); 4448c2ecf20Sopenharmony_ci ptype = gro_find_receive_by_type(type); 4458c2ecf20Sopenharmony_ci if (ptype == NULL) { 4468c2ecf20Sopenharmony_ci flush = 1; 4478c2ecf20Sopenharmony_ci goto out_unlock; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci skb_gro_pull(skb, sizeof(*eh)); 4518c2ecf20Sopenharmony_ci skb_gro_postpull_rcsum(skb, eh, sizeof(*eh)); 4528c2ecf20Sopenharmony_ci pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ciout_unlock: 4558c2ecf20Sopenharmony_ci rcu_read_unlock(); 4568c2ecf20Sopenharmony_ciout: 4578c2ecf20Sopenharmony_ci skb_gro_flush_final(skb, pp, flush); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return pp; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_gro_receive); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ciint eth_gro_complete(struct sk_buff *skb, int nhoff) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci struct ethhdr *eh = (struct ethhdr *)(skb->data + nhoff); 4668c2ecf20Sopenharmony_ci __be16 type = eh->h_proto; 4678c2ecf20Sopenharmony_ci struct packet_offload *ptype; 4688c2ecf20Sopenharmony_ci int err = -ENOSYS; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (skb->encapsulation) 4718c2ecf20Sopenharmony_ci skb_set_inner_mac_header(skb, nhoff); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci rcu_read_lock(); 4748c2ecf20Sopenharmony_ci ptype = gro_find_complete_by_type(type); 4758c2ecf20Sopenharmony_ci if (ptype != NULL) 4768c2ecf20Sopenharmony_ci err = ptype->callbacks.gro_complete(skb, nhoff + 4778c2ecf20Sopenharmony_ci sizeof(struct ethhdr)); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci rcu_read_unlock(); 4808c2ecf20Sopenharmony_ci return err; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_gro_complete); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cistatic struct packet_offload eth_packet_offload __read_mostly = { 4858c2ecf20Sopenharmony_ci .type = cpu_to_be16(ETH_P_TEB), 4868c2ecf20Sopenharmony_ci .priority = 10, 4878c2ecf20Sopenharmony_ci .callbacks = { 4888c2ecf20Sopenharmony_ci .gro_receive = eth_gro_receive, 4898c2ecf20Sopenharmony_ci .gro_complete = eth_gro_complete, 4908c2ecf20Sopenharmony_ci }, 4918c2ecf20Sopenharmony_ci}; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic int __init eth_offload_init(void) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci dev_add_offload(ð_packet_offload); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return 0; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cifs_initcall(eth_offload_init); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ciunsigned char * __weak arch_get_platform_mac_address(void) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci return NULL; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ciint eth_platform_get_mac_address(struct device *dev, u8 *mac_addr) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci const unsigned char *addr = NULL; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (dev->of_node) 5128c2ecf20Sopenharmony_ci addr = of_get_mac_address(dev->of_node); 5138c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(addr)) 5148c2ecf20Sopenharmony_ci addr = arch_get_platform_mac_address(); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (!addr) 5178c2ecf20Sopenharmony_ci return -ENODEV; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci ether_addr_copy(mac_addr, addr); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return 0; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eth_platform_get_mac_address); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci/** 5268c2ecf20Sopenharmony_ci * Obtain the MAC address from an nvmem cell named 'mac-address' associated 5278c2ecf20Sopenharmony_ci * with given device. 5288c2ecf20Sopenharmony_ci * 5298c2ecf20Sopenharmony_ci * @dev: Device with which the mac-address cell is associated. 5308c2ecf20Sopenharmony_ci * @addrbuf: Buffer to which the MAC address will be copied on success. 5318c2ecf20Sopenharmony_ci * 5328c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error number on failure. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ciint nvmem_get_mac_address(struct device *dev, void *addrbuf) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci struct nvmem_cell *cell; 5378c2ecf20Sopenharmony_ci const void *mac; 5388c2ecf20Sopenharmony_ci size_t len; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci cell = nvmem_cell_get(dev, "mac-address"); 5418c2ecf20Sopenharmony_ci if (IS_ERR(cell)) 5428c2ecf20Sopenharmony_ci return PTR_ERR(cell); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci mac = nvmem_cell_read(cell, &len); 5458c2ecf20Sopenharmony_ci nvmem_cell_put(cell); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (IS_ERR(mac)) 5488c2ecf20Sopenharmony_ci return PTR_ERR(mac); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (len != ETH_ALEN || !is_valid_ether_addr(mac)) { 5518c2ecf20Sopenharmony_ci kfree(mac); 5528c2ecf20Sopenharmony_ci return -EINVAL; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci ether_addr_copy(addrbuf, mac); 5568c2ecf20Sopenharmony_ci kfree(mac); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci return 0; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nvmem_get_mac_address); 561