.. | .. |
---|
| 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); |
---|