| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * INET An implementation of the TCP/IP protocol suite for the LINUX |
|---|
| 3 | 4 | * operating system. INET is implemented using the BSD Socket |
|---|
| .. | .. |
|---|
| 31 | 32 | * older network drivers and IFF_ALLMULTI. |
|---|
| 32 | 33 | * Christer Weinigel : Better rebuild header message. |
|---|
| 33 | 34 | * Andrew Morton : 26Feb01: kill ether_setup() - use netdev_boot_setup(). |
|---|
| 34 | | - * |
|---|
| 35 | | - * This program is free software; you can redistribute it and/or |
|---|
| 36 | | - * modify it under the terms of the GNU General Public License |
|---|
| 37 | | - * as published by the Free Software Foundation; either version |
|---|
| 38 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 39 | 35 | */ |
|---|
| 40 | 36 | #include <linux/module.h> |
|---|
| 41 | 37 | #include <linux/types.h> |
|---|
| .. | .. |
|---|
| 47 | 43 | #include <linux/inet.h> |
|---|
| 48 | 44 | #include <linux/ip.h> |
|---|
| 49 | 45 | #include <linux/netdevice.h> |
|---|
| 46 | +#include <linux/nvmem-consumer.h> |
|---|
| 50 | 47 | #include <linux/etherdevice.h> |
|---|
| 51 | 48 | #include <linux/skbuff.h> |
|---|
| 52 | 49 | #include <linux/errno.h> |
|---|
| .. | .. |
|---|
| 118 | 115 | |
|---|
| 119 | 116 | /** |
|---|
| 120 | 117 | * eth_get_headlen - determine the length of header for an ethernet frame |
|---|
| 118 | + * @dev: pointer to network device |
|---|
| 121 | 119 | * @data: pointer to start of frame |
|---|
| 122 | 120 | * @len: total length of frame |
|---|
| 123 | 121 | * |
|---|
| 124 | 122 | * Make a best effort attempt to pull the length for all of the headers for |
|---|
| 125 | 123 | * a given frame in a linear buffer. |
|---|
| 126 | 124 | */ |
|---|
| 127 | | -u32 eth_get_headlen(void *data, unsigned int len) |
|---|
| 125 | +u32 eth_get_headlen(const struct net_device *dev, void *data, unsigned int len) |
|---|
| 128 | 126 | { |
|---|
| 129 | 127 | const unsigned int flags = FLOW_DISSECTOR_F_PARSE_1ST_FRAG; |
|---|
| 130 | 128 | const struct ethhdr *eth = (const struct ethhdr *)data; |
|---|
| .. | .. |
|---|
| 135 | 133 | return len; |
|---|
| 136 | 134 | |
|---|
| 137 | 135 | /* parse any remaining L2/L3 headers, check for L4 */ |
|---|
| 138 | | - if (!skb_flow_dissect_flow_keys_basic(NULL, &keys, data, eth->h_proto, |
|---|
| 139 | | - sizeof(*eth), len, flags)) |
|---|
| 136 | + if (!skb_flow_dissect_flow_keys_basic(dev_net(dev), NULL, &keys, data, |
|---|
| 137 | + eth->h_proto, sizeof(*eth), |
|---|
| 138 | + len, flags)) |
|---|
| 140 | 139 | return max_t(u32, keys.control.thoff, sizeof(*eth)); |
|---|
| 141 | 140 | |
|---|
| 142 | 141 | /* parse for any L4 headers */ |
|---|
| .. | .. |
|---|
| 165 | 164 | eth = (struct ethhdr *)skb->data; |
|---|
| 166 | 165 | skb_pull_inline(skb, ETH_HLEN); |
|---|
| 167 | 166 | |
|---|
| 168 | | - if (unlikely(is_multicast_ether_addr_64bits(eth->h_dest))) { |
|---|
| 169 | | - if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast)) |
|---|
| 170 | | - skb->pkt_type = PACKET_BROADCAST; |
|---|
| 171 | | - else |
|---|
| 172 | | - skb->pkt_type = PACKET_MULTICAST; |
|---|
| 167 | + if (unlikely(!ether_addr_equal_64bits(eth->h_dest, |
|---|
| 168 | + dev->dev_addr))) { |
|---|
| 169 | + if (unlikely(is_multicast_ether_addr_64bits(eth->h_dest))) { |
|---|
| 170 | + if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast)) |
|---|
| 171 | + skb->pkt_type = PACKET_BROADCAST; |
|---|
| 172 | + else |
|---|
| 173 | + skb->pkt_type = PACKET_MULTICAST; |
|---|
| 174 | + } else { |
|---|
| 175 | + skb->pkt_type = PACKET_OTHERHOST; |
|---|
| 176 | + } |
|---|
| 173 | 177 | } |
|---|
| 174 | | - else if (unlikely(!ether_addr_equal_64bits(eth->h_dest, |
|---|
| 175 | | - dev->dev_addr))) |
|---|
| 176 | | - skb->pkt_type = PACKET_OTHERHOST; |
|---|
| 177 | 178 | |
|---|
| 178 | 179 | /* |
|---|
| 179 | 180 | * Some variants of DSA tagging don't have an ethertype field |
|---|
| 180 | 181 | * at all, so we check here whether one of those tagging |
|---|
| 181 | 182 | * variants has been configured on the receiving interface, |
|---|
| 182 | 183 | * and if so, set skb->protocol without looking at the packet. |
|---|
| 184 | + * The DSA tagging protocol may be able to decode some but not all |
|---|
| 185 | + * traffic (for example only for management). In that case give it the |
|---|
| 186 | + * option to filter the packets from which it can decode source port |
|---|
| 187 | + * information. |
|---|
| 183 | 188 | */ |
|---|
| 184 | | - if (unlikely(netdev_uses_dsa(dev))) |
|---|
| 189 | + if (unlikely(netdev_uses_dsa(dev)) && dsa_can_decode(skb, dev)) |
|---|
| 185 | 190 | return htons(ETH_P_XDSA); |
|---|
| 186 | 191 | |
|---|
| 187 | 192 | if (likely(eth_proto_is_802_3(eth->h_proto))) |
|---|
| .. | .. |
|---|
| 267 | 272 | EXPORT_SYMBOL(eth_header_cache_update); |
|---|
| 268 | 273 | |
|---|
| 269 | 274 | /** |
|---|
| 275 | + * eth_header_parser_protocol - extract protocol from L2 header |
|---|
| 276 | + * @skb: packet to extract protocol from |
|---|
| 277 | + */ |
|---|
| 278 | +__be16 eth_header_parse_protocol(const struct sk_buff *skb) |
|---|
| 279 | +{ |
|---|
| 280 | + const struct ethhdr *eth = eth_hdr(skb); |
|---|
| 281 | + |
|---|
| 282 | + return eth->h_proto; |
|---|
| 283 | +} |
|---|
| 284 | +EXPORT_SYMBOL(eth_header_parse_protocol); |
|---|
| 285 | + |
|---|
| 286 | +/** |
|---|
| 270 | 287 | * eth_prepare_mac_addr_change - prepare for mac change |
|---|
| 271 | 288 | * @dev: network device |
|---|
| 272 | 289 | * @p: socket address |
|---|
| .. | .. |
|---|
| 318 | 335 | } |
|---|
| 319 | 336 | EXPORT_SYMBOL(eth_mac_addr); |
|---|
| 320 | 337 | |
|---|
| 321 | | -/** |
|---|
| 322 | | - * eth_change_mtu - set new MTU size |
|---|
| 323 | | - * @dev: network device |
|---|
| 324 | | - * @new_mtu: new Maximum Transfer Unit |
|---|
| 325 | | - * |
|---|
| 326 | | - * Allow changing MTU size. Needs to be overridden for devices |
|---|
| 327 | | - * supporting jumbo frames. |
|---|
| 328 | | - */ |
|---|
| 329 | | -int eth_change_mtu(struct net_device *dev, int new_mtu) |
|---|
| 330 | | -{ |
|---|
| 331 | | - netdev_warn(dev, "%s is deprecated\n", __func__); |
|---|
| 332 | | - dev->mtu = new_mtu; |
|---|
| 333 | | - return 0; |
|---|
| 334 | | -} |
|---|
| 335 | | -EXPORT_SYMBOL(eth_change_mtu); |
|---|
| 336 | | - |
|---|
| 337 | 338 | int eth_validate_addr(struct net_device *dev) |
|---|
| 338 | 339 | { |
|---|
| 339 | 340 | if (!is_valid_ether_addr(dev->dev_addr)) |
|---|
| .. | .. |
|---|
| 348 | 349 | .parse = eth_header_parse, |
|---|
| 349 | 350 | .cache = eth_header_cache, |
|---|
| 350 | 351 | .cache_update = eth_header_cache_update, |
|---|
| 352 | + .parse_protocol = eth_header_parse_protocol, |
|---|
| 351 | 353 | }; |
|---|
| 352 | 354 | |
|---|
| 353 | 355 | /** |
|---|
| .. | .. |
|---|
| 397 | 399 | ether_setup, txqs, rxqs); |
|---|
| 398 | 400 | } |
|---|
| 399 | 401 | EXPORT_SYMBOL(alloc_etherdev_mqs); |
|---|
| 400 | | - |
|---|
| 401 | | -static void devm_free_netdev(struct device *dev, void *res) |
|---|
| 402 | | -{ |
|---|
| 403 | | - free_netdev(*(struct net_device **)res); |
|---|
| 404 | | -} |
|---|
| 405 | | - |
|---|
| 406 | | -struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv, |
|---|
| 407 | | - unsigned int txqs, unsigned int rxqs) |
|---|
| 408 | | -{ |
|---|
| 409 | | - struct net_device **dr; |
|---|
| 410 | | - struct net_device *netdev; |
|---|
| 411 | | - |
|---|
| 412 | | - dr = devres_alloc(devm_free_netdev, sizeof(*dr), GFP_KERNEL); |
|---|
| 413 | | - if (!dr) |
|---|
| 414 | | - return NULL; |
|---|
| 415 | | - |
|---|
| 416 | | - netdev = alloc_etherdev_mqs(sizeof_priv, txqs, rxqs); |
|---|
| 417 | | - if (!netdev) { |
|---|
| 418 | | - devres_free(dr); |
|---|
| 419 | | - return NULL; |
|---|
| 420 | | - } |
|---|
| 421 | | - |
|---|
| 422 | | - *dr = netdev; |
|---|
| 423 | | - devres_add(dev, dr); |
|---|
| 424 | | - |
|---|
| 425 | | - return netdev; |
|---|
| 426 | | -} |
|---|
| 427 | | -EXPORT_SYMBOL(devm_alloc_etherdev_mqs); |
|---|
| 428 | 402 | |
|---|
| 429 | 403 | ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len) |
|---|
| 430 | 404 | { |
|---|
| .. | .. |
|---|
| 532 | 506 | |
|---|
| 533 | 507 | int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr) |
|---|
| 534 | 508 | { |
|---|
| 535 | | - const unsigned char *addr; |
|---|
| 536 | | - struct device_node *dp; |
|---|
| 509 | + const unsigned char *addr = NULL; |
|---|
| 537 | 510 | |
|---|
| 538 | | - if (dev_is_pci(dev)) |
|---|
| 539 | | - dp = pci_device_to_OF_node(to_pci_dev(dev)); |
|---|
| 540 | | - else |
|---|
| 541 | | - dp = dev->of_node; |
|---|
| 542 | | - |
|---|
| 543 | | - addr = NULL; |
|---|
| 544 | | - if (dp) |
|---|
| 545 | | - addr = of_get_mac_address(dp); |
|---|
| 546 | | - if (!addr) |
|---|
| 511 | + if (dev->of_node) |
|---|
| 512 | + addr = of_get_mac_address(dev->of_node); |
|---|
| 513 | + if (IS_ERR_OR_NULL(addr)) |
|---|
| 547 | 514 | addr = arch_get_platform_mac_address(); |
|---|
| 548 | 515 | |
|---|
| 549 | 516 | if (!addr) |
|---|
| 550 | 517 | return -ENODEV; |
|---|
| 551 | 518 | |
|---|
| 552 | 519 | ether_addr_copy(mac_addr, addr); |
|---|
| 520 | + |
|---|
| 553 | 521 | return 0; |
|---|
| 554 | 522 | } |
|---|
| 555 | 523 | EXPORT_SYMBOL(eth_platform_get_mac_address); |
|---|
| 524 | + |
|---|
| 525 | +/** |
|---|
| 526 | + * Obtain the MAC address from an nvmem cell named 'mac-address' associated |
|---|
| 527 | + * with given device. |
|---|
| 528 | + * |
|---|
| 529 | + * @dev: Device with which the mac-address cell is associated. |
|---|
| 530 | + * @addrbuf: Buffer to which the MAC address will be copied on success. |
|---|
| 531 | + * |
|---|
| 532 | + * Returns 0 on success or a negative error number on failure. |
|---|
| 533 | + */ |
|---|
| 534 | +int nvmem_get_mac_address(struct device *dev, void *addrbuf) |
|---|
| 535 | +{ |
|---|
| 536 | + struct nvmem_cell *cell; |
|---|
| 537 | + const void *mac; |
|---|
| 538 | + size_t len; |
|---|
| 539 | + |
|---|
| 540 | + cell = nvmem_cell_get(dev, "mac-address"); |
|---|
| 541 | + if (IS_ERR(cell)) |
|---|
| 542 | + return PTR_ERR(cell); |
|---|
| 543 | + |
|---|
| 544 | + mac = nvmem_cell_read(cell, &len); |
|---|
| 545 | + nvmem_cell_put(cell); |
|---|
| 546 | + |
|---|
| 547 | + if (IS_ERR(mac)) |
|---|
| 548 | + return PTR_ERR(mac); |
|---|
| 549 | + |
|---|
| 550 | + if (len != ETH_ALEN || !is_valid_ether_addr(mac)) { |
|---|
| 551 | + kfree(mac); |
|---|
| 552 | + return -EINVAL; |
|---|
| 553 | + } |
|---|
| 554 | + |
|---|
| 555 | + ether_addr_copy(addrbuf, mac); |
|---|
| 556 | + kfree(mac); |
|---|
| 557 | + |
|---|
| 558 | + return 0; |
|---|
| 559 | +} |
|---|
| 560 | +EXPORT_SYMBOL(nvmem_get_mac_address); |
|---|