2016-06-01 15:06:27 +02:00
|
|
|
/*
|
2019-01-07 15:18:53 +02:00
|
|
|
* Copyright (c) 2016-2018 Intel Corporation.
|
2016-06-01 15:06:27 +02:00
|
|
|
*
|
2017-01-18 17:01:01 -08:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2016-06-01 15:06:27 +02:00
|
|
|
*/
|
|
|
|
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/logging/log.h>
|
2018-11-30 12:54:56 +02:00
|
|
|
LOG_MODULE_REGISTER(net_ethernet, CONFIG_NET_L2_ETHERNET_LOG_LEVEL);
|
2016-06-08 08:39:46 +03:00
|
|
|
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/net/net_core.h>
|
|
|
|
#include <zephyr/net/net_l2.h>
|
|
|
|
#include <zephyr/net/net_if.h>
|
|
|
|
#include <zephyr/net/net_mgmt.h>
|
|
|
|
#include <zephyr/net/ethernet.h>
|
|
|
|
#include <zephyr/net/ethernet_mgmt.h>
|
|
|
|
#include <zephyr/net/gptp.h>
|
|
|
|
#include <zephyr/random/rand32.h>
|
2019-02-26 09:56:06 +02:00
|
|
|
|
|
|
|
#if defined(CONFIG_NET_LLDP)
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/net/lldp.h>
|
2019-02-26 09:56:06 +02:00
|
|
|
#endif
|
2016-06-01 15:06:27 +02:00
|
|
|
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/syscall_handler.h>
|
2019-05-27 12:44:01 +08:00
|
|
|
|
2018-06-15 21:08:27 +02:00
|
|
|
#include "arp.h"
|
2018-12-05 14:39:43 +01:00
|
|
|
#include "eth_stats.h"
|
2016-06-08 08:39:46 +03:00
|
|
|
#include "net_private.h"
|
2016-06-28 17:33:16 +03:00
|
|
|
#include "ipv6.h"
|
2018-07-30 18:28:35 +03:00
|
|
|
#include "ipv4_autoconf_internal.h"
|
2021-06-25 18:54:17 -04:00
|
|
|
#include "bridge.h"
|
2016-06-08 08:39:46 +03:00
|
|
|
|
2018-06-08 15:35:27 +02:00
|
|
|
#define NET_BUF_TIMEOUT K_MSEC(100)
|
|
|
|
|
2018-06-25 10:22:54 +02:00
|
|
|
static const struct net_eth_addr multicast_eth_addr __unused = {
|
2016-06-10 09:08:29 +03:00
|
|
|
{ 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 } };
|
|
|
|
|
2016-06-08 14:13:27 +03:00
|
|
|
static const struct net_eth_addr broadcast_eth_addr = {
|
|
|
|
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
|
|
|
|
|
|
|
|
const struct net_eth_addr *net_eth_broadcast_addr(void)
|
|
|
|
{
|
|
|
|
return &broadcast_eth_addr;
|
|
|
|
}
|
|
|
|
|
2021-09-21 10:43:19 +02:00
|
|
|
void net_eth_ipv4_mcast_to_mac_addr(const struct in_addr *ipv4_addr,
|
|
|
|
struct net_eth_addr *mac_addr)
|
|
|
|
{
|
|
|
|
/* RFC 1112 6.4. Extensions to an Ethernet Local Network Module
|
|
|
|
* "An IP host group address is mapped to an Ethernet multicast
|
|
|
|
* address by placing the low-order 23-bits of the IP address into
|
|
|
|
* the low-order 23 bits of the Ethernet multicast address
|
|
|
|
* 01-00-5E-00-00-00 (hex)."
|
|
|
|
*/
|
|
|
|
mac_addr->addr[0] = 0x01;
|
|
|
|
mac_addr->addr[1] = 0x00;
|
|
|
|
mac_addr->addr[2] = 0x5e;
|
|
|
|
mac_addr->addr[3] = ipv4_addr->s4_addr[1];
|
|
|
|
mac_addr->addr[4] = ipv4_addr->s4_addr[2];
|
|
|
|
mac_addr->addr[5] = ipv4_addr->s4_addr[3];
|
|
|
|
|
|
|
|
mac_addr->addr[3] &= 0x7f;
|
|
|
|
}
|
|
|
|
|
2017-12-04 17:24:08 +02:00
|
|
|
void net_eth_ipv6_mcast_to_mac_addr(const struct in6_addr *ipv6_addr,
|
|
|
|
struct net_eth_addr *mac_addr)
|
|
|
|
{
|
|
|
|
/* RFC 2464 7. Address Mapping -- Multicast
|
|
|
|
* "An IPv6 packet with a multicast destination address DST,
|
|
|
|
* consisting of the sixteen octets DST[1] through DST[16],
|
|
|
|
* is transmitted to the Ethernet multicast address whose
|
|
|
|
* first two octets are the value 3333 hexadecimal and whose
|
|
|
|
* last four octets are the last four octets of DST."
|
|
|
|
*/
|
|
|
|
mac_addr->addr[0] = mac_addr->addr[1] = 0x33;
|
|
|
|
memcpy(mac_addr->addr + 2, &ipv6_addr->s6_addr[12], 4);
|
|
|
|
}
|
|
|
|
|
2018-01-19 12:24:33 +02:00
|
|
|
#define print_ll_addrs(pkt, type, len, src, dst) \
|
2018-11-30 12:54:56 +02:00
|
|
|
if (CONFIG_NET_L2_ETHERNET_LOG_LEVEL >= LOG_LEVEL_DBG) { \
|
2016-06-08 08:39:46 +03:00
|
|
|
char out[sizeof("xx:xx:xx:xx:xx:xx")]; \
|
|
|
|
\
|
2017-01-23 13:05:40 +02:00
|
|
|
snprintk(out, sizeof(out), "%s", \
|
2018-01-19 12:24:33 +02:00
|
|
|
net_sprint_ll_addr((src)->addr, \
|
2016-06-08 08:39:46 +03:00
|
|
|
sizeof(struct net_eth_addr))); \
|
|
|
|
\
|
2018-01-19 12:24:33 +02:00
|
|
|
NET_DBG("iface %p src %s dst %s type 0x%x len %zu", \
|
2022-06-20 07:43:37 +02:00
|
|
|
net_pkt_iface(pkt), out, \
|
|
|
|
net_sprint_ll_addr((dst)->addr, \
|
|
|
|
sizeof(struct net_eth_addr)), \
|
2016-12-06 19:20:03 +02:00
|
|
|
type, (size_t)len); \
|
2018-07-06 11:35:07 +03:00
|
|
|
}
|
2018-01-19 12:24:33 +02:00
|
|
|
|
2018-06-25 10:22:54 +02:00
|
|
|
#ifdef CONFIG_NET_VLAN
|
2019-04-12 14:15:34 +03:00
|
|
|
#define print_vlan_ll_addrs(pkt, type, tci, len, src, dst, tagstrip) \
|
2018-11-30 12:54:56 +02:00
|
|
|
if (CONFIG_NET_L2_ETHERNET_LOG_LEVEL >= LOG_LEVEL_DBG) { \
|
2018-01-19 12:24:33 +02:00
|
|
|
char out[sizeof("xx:xx:xx:xx:xx:xx")]; \
|
|
|
|
\
|
|
|
|
snprintk(out, sizeof(out), "%s", \
|
|
|
|
net_sprint_ll_addr((src)->addr, \
|
|
|
|
sizeof(struct net_eth_addr))); \
|
|
|
|
\
|
2019-04-12 14:15:34 +03:00
|
|
|
NET_DBG("iface %p src %s dst %s type 0x%x " \
|
|
|
|
"tag %d %spri %d len %zu", \
|
2022-06-20 07:43:37 +02:00
|
|
|
net_pkt_iface(pkt), out, \
|
|
|
|
net_sprint_ll_addr((dst)->addr, \
|
|
|
|
sizeof(struct net_eth_addr)), \
|
2018-01-19 12:24:33 +02:00
|
|
|
type, net_eth_vlan_get_vid(tci), \
|
2019-04-12 14:15:34 +03:00
|
|
|
tagstrip ? "(stripped) " : "", \
|
2018-01-19 12:24:33 +02:00
|
|
|
net_eth_vlan_get_pcp(tci), (size_t)len); \
|
2018-07-06 11:35:07 +03:00
|
|
|
}
|
2018-06-25 10:22:54 +02:00
|
|
|
#else
|
|
|
|
#define print_vlan_ll_addrs(...)
|
|
|
|
#endif /* CONFIG_NET_VLAN */
|
2016-06-08 08:39:46 +03:00
|
|
|
|
2016-12-02 14:47:29 +01:00
|
|
|
static inline void ethernet_update_length(struct net_if *iface,
|
2017-04-05 08:37:44 +02:00
|
|
|
struct net_pkt *pkt)
|
2016-12-02 14:47:29 +01:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t len;
|
2016-12-02 14:47:29 +01:00
|
|
|
|
|
|
|
/* Let's check IP payload's length. If it's smaller than 46 bytes,
|
|
|
|
* i.e. smaller than minimal Ethernet frame size minus ethernet
|
|
|
|
* header size,then Ethernet has padded so it fits in the minimal
|
|
|
|
* frame size of 60 bytes. In that case, we need to get rid of it.
|
|
|
|
*/
|
|
|
|
|
2017-04-05 08:37:44 +02:00
|
|
|
if (net_pkt_family(pkt) == AF_INET) {
|
2018-08-08 15:22:00 +03:00
|
|
|
len = ntohs(NET_IPV4_HDR(pkt)->len);
|
2016-12-02 14:47:29 +01:00
|
|
|
} else {
|
2018-08-13 09:57:00 +03:00
|
|
|
len = ntohs(NET_IPV6_HDR(pkt)->len) + NET_IPV6H_LEN;
|
2016-12-02 14:47:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (len < NET_ETH_MINIMAL_FRAME_SIZE - sizeof(struct net_eth_hdr)) {
|
|
|
|
struct net_buf *frag;
|
|
|
|
|
2017-04-05 08:37:44 +02:00
|
|
|
for (frag = pkt->frags; frag; frag = frag->frags) {
|
2016-12-02 14:47:29 +01:00
|
|
|
if (frag->len < len) {
|
|
|
|
len -= frag->len;
|
|
|
|
} else {
|
|
|
|
frag->len = len;
|
2018-11-29 11:23:03 -08:00
|
|
|
len = 0U;
|
2016-12-02 14:47:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-05 14:39:43 +01:00
|
|
|
static void ethernet_update_rx_stats(struct net_if *iface,
|
|
|
|
struct net_pkt *pkt, size_t length)
|
|
|
|
{
|
2019-01-07 15:18:53 +02:00
|
|
|
#if defined(CONFIG_NET_STATISTICS_ETHERNET)
|
2018-12-05 14:39:43 +01:00
|
|
|
struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
|
|
|
|
|
|
|
|
eth_stats_update_bytes_rx(iface, length);
|
|
|
|
eth_stats_update_pkts_rx(iface);
|
|
|
|
|
|
|
|
if (net_eth_is_addr_broadcast(&hdr->dst)) {
|
|
|
|
eth_stats_update_broadcast_rx(iface);
|
|
|
|
} else if (net_eth_is_addr_multicast(&hdr->dst)) {
|
|
|
|
eth_stats_update_multicast_rx(iface);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_STATISTICS_ETHERNET */
|
2019-01-07 15:18:53 +02:00
|
|
|
}
|
2018-12-05 14:39:43 +01:00
|
|
|
|
2019-04-12 14:15:34 +03:00
|
|
|
static inline bool eth_is_vlan_tag_stripped(struct net_if *iface)
|
|
|
|
{
|
2020-04-30 20:33:38 +02:00
|
|
|
const struct device *dev = net_if_get_device(iface);
|
2020-05-28 21:23:02 +02:00
|
|
|
const struct ethernet_api *api = dev->api;
|
2019-04-12 14:15:34 +03:00
|
|
|
|
|
|
|
return (api->get_capabilities(dev) & ETHERNET_HW_VLAN_TAG_STRIP);
|
|
|
|
}
|
|
|
|
|
2019-05-21 13:33:23 +03:00
|
|
|
/* Drop packet if it has broadcast destination MAC address but the IP
|
|
|
|
* address is not multicast or broadcast address. See RFC 1122 ch 3.3.6
|
|
|
|
*/
|
|
|
|
static inline
|
|
|
|
enum net_verdict ethernet_check_ipv4_bcast_addr(struct net_pkt *pkt,
|
|
|
|
struct net_eth_hdr *hdr)
|
|
|
|
{
|
|
|
|
if (net_eth_is_addr_broadcast(&hdr->dst) &&
|
2021-10-04 14:40:22 +02:00
|
|
|
!(net_ipv4_is_addr_mcast((struct in_addr *)NET_IPV4_HDR(pkt)->dst) ||
|
2019-05-21 13:33:23 +03:00
|
|
|
net_ipv4_is_addr_bcast(net_pkt_iface(pkt),
|
2021-10-04 14:40:22 +02:00
|
|
|
(struct in_addr *)NET_IPV4_HDR(pkt)->dst))) {
|
2019-05-21 13:33:23 +03:00
|
|
|
return NET_DROP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NET_OK;
|
|
|
|
}
|
|
|
|
|
2016-06-01 15:06:27 +02:00
|
|
|
static enum net_verdict ethernet_recv(struct net_if *iface,
|
2017-04-05 08:37:44 +02:00
|
|
|
struct net_pkt *pkt)
|
2016-06-01 15:06:27 +02:00
|
|
|
{
|
2018-01-19 12:24:33 +02:00
|
|
|
struct ethernet_context *ctx = net_if_l2_data(iface);
|
2017-04-10 13:03:41 +02:00
|
|
|
struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
|
2020-05-27 11:26:57 -05:00
|
|
|
uint8_t hdr_len = sizeof(struct net_eth_hdr);
|
2020-09-22 18:02:04 +03:00
|
|
|
uint16_t type;
|
2016-06-07 14:17:51 +03:00
|
|
|
struct net_linkaddr *lladdr;
|
2016-10-05 19:42:43 -05:00
|
|
|
sa_family_t family;
|
2018-01-19 12:24:33 +02:00
|
|
|
|
2020-09-23 12:36:31 +03:00
|
|
|
/* This expects that the Ethernet header is in the first net_buf
|
|
|
|
* fragment. This is a safe expectation here as it would not make
|
|
|
|
* any sense to split the Ethernet header to two net_buf's by the
|
|
|
|
* Ethernet driver.
|
|
|
|
*/
|
|
|
|
if (hdr == NULL || pkt->buffer->len < hdr_len) {
|
2020-09-22 18:02:04 +03:00
|
|
|
goto drop;
|
|
|
|
}
|
|
|
|
|
2021-06-25 18:54:17 -04:00
|
|
|
if (IS_ENABLED(CONFIG_NET_ETHERNET_BRIDGE) &&
|
|
|
|
net_eth_iface_is_bridged(ctx)) {
|
|
|
|
net_pkt_set_l2_bridged(pkt, true);
|
|
|
|
net_pkt_lladdr_src(pkt)->addr = hdr->src.addr;
|
|
|
|
net_pkt_lladdr_src(pkt)->len = sizeof(struct net_eth_addr);
|
|
|
|
net_pkt_lladdr_src(pkt)->type = NET_LINK_ETHERNET;
|
|
|
|
net_pkt_lladdr_dst(pkt)->addr = hdr->dst.addr;
|
|
|
|
net_pkt_lladdr_dst(pkt)->len = sizeof(struct net_eth_addr);
|
|
|
|
net_pkt_lladdr_dst(pkt)->type = NET_LINK_ETHERNET;
|
|
|
|
ethernet_update_rx_stats(iface, pkt, net_pkt_get_len(pkt));
|
|
|
|
return net_eth_bridge_input(ctx, pkt);
|
|
|
|
}
|
|
|
|
|
2020-09-22 18:02:04 +03:00
|
|
|
type = ntohs(hdr->type);
|
|
|
|
|
2018-06-08 10:03:06 +02:00
|
|
|
if (net_eth_is_vlan_enabled(ctx, iface) &&
|
2019-04-12 14:15:34 +03:00
|
|
|
type == NET_ETH_PTYPE_VLAN &&
|
|
|
|
!eth_is_vlan_tag_stripped(iface)) {
|
2018-06-08 10:03:06 +02:00
|
|
|
struct net_eth_vlan_hdr *hdr_vlan =
|
|
|
|
(struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt);
|
2016-06-03 12:40:19 +03:00
|
|
|
|
2018-06-08 10:03:06 +02:00
|
|
|
net_pkt_set_vlan_tci(pkt, ntohs(hdr_vlan->vlan.tci));
|
|
|
|
type = ntohs(hdr_vlan->type);
|
|
|
|
hdr_len = sizeof(struct net_eth_vlan_hdr);
|
2018-01-19 12:24:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
2016-06-03 12:40:19 +03:00
|
|
|
case NET_ETH_PTYPE_IP:
|
|
|
|
case NET_ETH_PTYPE_ARP:
|
2017-04-05 08:37:44 +02:00
|
|
|
net_pkt_set_family(pkt, AF_INET);
|
2016-10-05 19:42:43 -05:00
|
|
|
family = AF_INET;
|
2016-06-03 12:40:19 +03:00
|
|
|
break;
|
|
|
|
case NET_ETH_PTYPE_IPV6:
|
2017-04-05 08:37:44 +02:00
|
|
|
net_pkt_set_family(pkt, AF_INET6);
|
2016-10-05 19:42:43 -05:00
|
|
|
family = AF_INET6;
|
2016-06-03 12:40:19 +03:00
|
|
|
break;
|
2022-08-08 02:01:58 +05:30
|
|
|
case NET_ETH_PTYPE_EAPOL:
|
|
|
|
family = AF_UNSPEC;
|
|
|
|
break;
|
2021-09-08 20:28:27 -07:00
|
|
|
#if defined(CONFIG_NET_L2_PTP)
|
2018-01-24 14:33:35 +02:00
|
|
|
case NET_ETH_PTYPE_PTP:
|
|
|
|
family = AF_UNSPEC;
|
|
|
|
break;
|
|
|
|
#endif
|
2017-04-05 17:17:12 -07:00
|
|
|
case NET_ETH_PTYPE_LLDP:
|
2018-08-20 11:40:53 +03:00
|
|
|
#if defined(CONFIG_NET_LLDP)
|
2018-06-27 15:06:18 +02:00
|
|
|
net_buf_pull(pkt->frags, hdr_len);
|
2018-08-20 11:40:53 +03:00
|
|
|
return net_lldp_recv(iface, pkt);
|
|
|
|
#else
|
|
|
|
NET_DBG("LLDP Rx agent not enabled");
|
2018-12-05 14:39:43 +01:00
|
|
|
goto drop;
|
2018-08-20 11:40:53 +03:00
|
|
|
#endif
|
2016-10-05 10:09:27 +02:00
|
|
|
default:
|
2022-05-17 09:33:17 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_ETHERNET_FORWARD_UNRECOGNISED_ETHERTYPE)) {
|
|
|
|
family = AF_UNSPEC;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-03-03 17:07:49 +02:00
|
|
|
NET_DBG("Unknown hdr type 0x%04x iface %p", type, iface);
|
2018-12-05 14:39:43 +01:00
|
|
|
goto drop;
|
2016-06-03 12:40:19 +03:00
|
|
|
}
|
|
|
|
|
2016-06-07 14:17:51 +03:00
|
|
|
/* Set the pointers to ll src and dst addresses */
|
2018-09-11 09:16:03 +02:00
|
|
|
lladdr = net_pkt_lladdr_src(pkt);
|
2018-12-06 14:19:51 +01:00
|
|
|
lladdr->addr = hdr->src.addr;
|
2016-07-05 17:07:03 +03:00
|
|
|
lladdr->len = sizeof(struct net_eth_addr);
|
2017-02-15 13:20:31 +02:00
|
|
|
lladdr->type = NET_LINK_ETHERNET;
|
2016-06-07 14:17:51 +03:00
|
|
|
|
2018-09-11 09:16:03 +02:00
|
|
|
lladdr = net_pkt_lladdr_dst(pkt);
|
2018-12-06 14:19:51 +01:00
|
|
|
lladdr->addr = hdr->dst.addr;
|
2016-07-05 17:07:03 +03:00
|
|
|
lladdr->len = sizeof(struct net_eth_addr);
|
2017-02-15 13:20:31 +02:00
|
|
|
lladdr->type = NET_LINK_ETHERNET;
|
2016-06-07 14:17:51 +03:00
|
|
|
|
2022-07-28 13:36:49 +02:00
|
|
|
net_pkt_set_ll_proto_type(pkt, type);
|
|
|
|
|
2018-06-08 10:03:06 +02:00
|
|
|
if (net_eth_is_vlan_enabled(ctx, iface)) {
|
2019-04-12 14:15:34 +03:00
|
|
|
if (type == NET_ETH_PTYPE_VLAN ||
|
|
|
|
(eth_is_vlan_tag_stripped(iface) &&
|
|
|
|
net_pkt_vlan_tci(pkt))) {
|
|
|
|
print_vlan_ll_addrs(pkt, type, net_pkt_vlan_tci(pkt),
|
|
|
|
net_pkt_get_len(pkt),
|
|
|
|
net_pkt_lladdr_src(pkt),
|
|
|
|
net_pkt_lladdr_dst(pkt),
|
|
|
|
eth_is_vlan_tag_stripped(iface));
|
|
|
|
} else {
|
|
|
|
print_ll_addrs(pkt, type, net_pkt_get_len(pkt),
|
|
|
|
net_pkt_lladdr_src(pkt),
|
|
|
|
net_pkt_lladdr_dst(pkt));
|
|
|
|
}
|
2018-06-08 10:03:06 +02:00
|
|
|
} else {
|
2018-01-19 12:24:33 +02:00
|
|
|
print_ll_addrs(pkt, type, net_pkt_get_len(pkt),
|
2018-09-11 09:16:03 +02:00
|
|
|
net_pkt_lladdr_src(pkt),
|
|
|
|
net_pkt_lladdr_dst(pkt));
|
2018-01-19 12:24:33 +02:00
|
|
|
}
|
2016-06-08 08:39:46 +03:00
|
|
|
|
2016-07-05 17:06:03 +03:00
|
|
|
if (!net_eth_is_addr_broadcast((struct net_eth_addr *)lladdr->addr) &&
|
|
|
|
!net_eth_is_addr_multicast((struct net_eth_addr *)lladdr->addr) &&
|
2018-01-24 14:33:35 +02:00
|
|
|
!net_eth_is_addr_lldp_multicast(
|
|
|
|
(struct net_eth_addr *)lladdr->addr) &&
|
2016-07-05 17:06:03 +03:00
|
|
|
!net_linkaddr_cmp(net_if_get_link_addr(iface), lladdr)) {
|
|
|
|
/* The ethernet frame is not for me as the link addresses
|
|
|
|
* are different.
|
|
|
|
*/
|
|
|
|
NET_DBG("Dropping frame, not for me [%s]",
|
2022-06-20 07:43:37 +02:00
|
|
|
net_sprint_ll_addr(net_if_get_link_addr(iface)->addr,
|
|
|
|
sizeof(struct net_eth_addr)));
|
2018-12-05 14:39:43 +01:00
|
|
|
goto drop;
|
2016-07-05 17:06:03 +03:00
|
|
|
}
|
|
|
|
|
2018-06-27 15:06:18 +02:00
|
|
|
net_buf_pull(pkt->frags, hdr_len);
|
2016-10-06 10:03:52 +02:00
|
|
|
|
2019-05-21 13:33:23 +03:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV4) && type == NET_ETH_PTYPE_IP &&
|
|
|
|
ethernet_check_ipv4_bcast_addr(pkt, hdr) == NET_DROP) {
|
|
|
|
goto drop;
|
|
|
|
}
|
|
|
|
|
|
|
|
ethernet_update_rx_stats(iface, pkt, net_pkt_get_len(pkt) + hdr_len);
|
|
|
|
|
2019-05-28 13:42:57 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_ARP) &&
|
|
|
|
family == AF_INET && type == NET_ETH_PTYPE_ARP) {
|
2016-06-08 14:37:15 +03:00
|
|
|
NET_DBG("ARP packet from %s received",
|
2022-06-20 07:43:37 +02:00
|
|
|
net_sprint_ll_addr((uint8_t *)hdr->src.addr,
|
|
|
|
sizeof(struct net_eth_addr)));
|
2019-05-28 13:42:57 +02:00
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV4_AUTO) &&
|
|
|
|
net_ipv4_autoconf_input(iface, pkt) == NET_DROP) {
|
2018-07-30 18:28:35 +03:00
|
|
|
return NET_DROP;
|
|
|
|
}
|
2019-05-28 13:42:57 +02:00
|
|
|
|
2018-12-06 14:19:51 +01:00
|
|
|
return net_arp_input(pkt, hdr);
|
2016-06-01 15:06:27 +02:00
|
|
|
}
|
2018-01-24 14:33:35 +02:00
|
|
|
|
2019-05-28 13:42:57 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_GPTP) && type == NET_ETH_PTYPE_PTP) {
|
2018-01-24 14:33:35 +02:00
|
|
|
return net_gptp_recv(iface, pkt);
|
|
|
|
}
|
|
|
|
|
2017-04-05 08:37:44 +02:00
|
|
|
ethernet_update_length(iface, pkt);
|
2016-12-02 14:47:29 +01:00
|
|
|
|
2016-06-01 15:06:27 +02:00
|
|
|
return NET_CONTINUE;
|
2018-12-05 14:39:43 +01:00
|
|
|
drop:
|
|
|
|
eth_stats_update_errors_rx(iface);
|
|
|
|
return NET_DROP;
|
2016-06-01 15:06:27 +02:00
|
|
|
}
|
|
|
|
|
2018-06-25 10:22:54 +02:00
|
|
|
#ifdef CONFIG_NET_IPV4
|
|
|
|
static inline bool ethernet_ipv4_dst_is_broadcast_or_mcast(struct net_pkt *pkt)
|
2016-09-12 16:03:37 +03:00
|
|
|
{
|
2018-06-25 10:22:54 +02:00
|
|
|
if (net_ipv4_is_addr_bcast(net_pkt_iface(pkt),
|
2021-10-04 14:40:22 +02:00
|
|
|
(struct in_addr *)NET_IPV4_HDR(pkt)->dst) ||
|
|
|
|
net_ipv4_is_addr_mcast((struct in_addr *)NET_IPV4_HDR(pkt)->dst)) {
|
2018-06-25 10:22:54 +02:00
|
|
|
return true;
|
|
|
|
}
|
2016-09-12 16:03:37 +03:00
|
|
|
|
2018-06-25 10:22:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
2016-09-12 16:03:37 +03:00
|
|
|
|
2018-06-25 10:22:54 +02:00
|
|
|
static bool ethernet_fill_in_dst_on_ipv4_mcast(struct net_pkt *pkt,
|
|
|
|
struct net_eth_addr *dst)
|
|
|
|
{
|
|
|
|
if (net_pkt_family(pkt) == AF_INET &&
|
2021-10-04 14:40:22 +02:00
|
|
|
net_ipv4_is_addr_mcast((struct in_addr *)NET_IPV4_HDR(pkt)->dst)) {
|
2016-09-12 16:03:37 +03:00
|
|
|
/* Multicast address */
|
2021-10-04 14:40:22 +02:00
|
|
|
net_eth_ipv4_mcast_to_mac_addr(
|
|
|
|
(struct in_addr *)NET_IPV4_HDR(pkt)->dst, dst);
|
2017-09-03 22:02:13 +03:00
|
|
|
|
2018-06-25 10:22:54 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2018-06-26 14:41:54 +02:00
|
|
|
|
|
|
|
static struct net_pkt *ethernet_ll_prepare_on_ipv4(struct net_if *iface,
|
|
|
|
struct net_pkt *pkt)
|
|
|
|
{
|
|
|
|
if (ethernet_ipv4_dst_is_broadcast_or_mcast(pkt)) {
|
|
|
|
return pkt;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_NET_ARP)) {
|
|
|
|
struct net_pkt *arp_pkt;
|
|
|
|
|
2021-10-04 14:40:22 +02:00
|
|
|
arp_pkt = net_arp_prepare(pkt, (struct in_addr *)NET_IPV4_HDR(pkt)->dst, NULL);
|
2018-06-26 14:41:54 +02:00
|
|
|
if (!arp_pkt) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pkt != arp_pkt) {
|
|
|
|
NET_DBG("Sending arp pkt %p (orig %p) to iface %p",
|
|
|
|
arp_pkt, pkt, iface);
|
|
|
|
net_pkt_unref(pkt);
|
|
|
|
return arp_pkt;
|
|
|
|
}
|
|
|
|
|
|
|
|
NET_DBG("Found ARP entry, sending pkt %p to iface %p",
|
|
|
|
pkt, iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
return pkt;
|
|
|
|
}
|
2018-06-25 10:22:54 +02:00
|
|
|
#else
|
|
|
|
#define ethernet_ipv4_dst_is_broadcast_or_mcast(...) false
|
|
|
|
#define ethernet_fill_in_dst_on_ipv4_mcast(...) false
|
2018-06-26 14:41:54 +02:00
|
|
|
#define ethernet_ll_prepare_on_ipv4(...) NULL
|
2018-06-25 10:22:54 +02:00
|
|
|
#endif /* CONFIG_NET_IPV4 */
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPV6
|
|
|
|
static bool ethernet_fill_in_dst_on_ipv6_mcast(struct net_pkt *pkt,
|
|
|
|
struct net_eth_addr *dst)
|
|
|
|
{
|
|
|
|
if (net_pkt_family(pkt) == AF_INET6 &&
|
2021-10-05 12:23:57 +02:00
|
|
|
net_ipv6_is_addr_mcast((struct in6_addr *)NET_IPV6_HDR(pkt)->dst)) {
|
2020-05-27 11:26:57 -05:00
|
|
|
memcpy(dst, (uint8_t *)multicast_eth_addr.addr,
|
2018-06-25 10:22:54 +02:00
|
|
|
sizeof(struct net_eth_addr) - 4);
|
2020-05-27 11:26:57 -05:00
|
|
|
memcpy((uint8_t *)dst + 2,
|
2021-10-05 12:23:57 +02:00
|
|
|
NET_IPV6_HDR(pkt)->dst + 12,
|
2018-06-25 10:22:54 +02:00
|
|
|
sizeof(struct net_eth_addr) - 2);
|
2016-09-12 16:03:37 +03:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2018-06-25 10:22:54 +02:00
|
|
|
#else
|
|
|
|
#define ethernet_fill_in_dst_on_ipv6_mcast(...) false
|
|
|
|
#endif /* CONFIG_NET_IPV6 */
|
2016-09-12 16:03:37 +03:00
|
|
|
|
2018-01-19 12:24:33 +02:00
|
|
|
#if defined(CONFIG_NET_VLAN)
|
|
|
|
static enum net_verdict set_vlan_tag(struct ethernet_context *ctx,
|
|
|
|
struct net_if *iface,
|
|
|
|
struct net_pkt *pkt)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (net_pkt_vlan_tag(pkt) != NET_VLAN_TAG_UNSPEC) {
|
|
|
|
return NET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_IPV6)
|
|
|
|
if (net_pkt_family(pkt) == AF_INET6) {
|
|
|
|
struct net_if *target;
|
|
|
|
|
2021-10-05 12:23:57 +02:00
|
|
|
if (net_if_ipv6_addr_lookup((struct in6_addr *)NET_IPV6_HDR(pkt)->src,
|
2018-01-19 12:24:33 +02:00
|
|
|
&target)) {
|
|
|
|
if (target != iface) {
|
|
|
|
NET_DBG("Iface %p should be %p", iface,
|
|
|
|
target);
|
|
|
|
|
|
|
|
iface = target;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_IPV4)
|
|
|
|
if (net_pkt_family(pkt) == AF_INET) {
|
|
|
|
struct net_if *target;
|
|
|
|
|
2021-10-04 14:40:22 +02:00
|
|
|
if (net_if_ipv4_addr_lookup((struct in_addr *)NET_IPV4_HDR(pkt)->src,
|
2018-01-19 12:24:33 +02:00
|
|
|
&target)) {
|
|
|
|
if (target != iface) {
|
|
|
|
NET_DBG("Iface %p should be %p", iface,
|
|
|
|
target);
|
|
|
|
iface = target;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
|
|
|
|
if (ctx->vlan[i].tag == NET_VLAN_TAG_UNSPEC ||
|
|
|
|
ctx->vlan[i].iface != iface) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Depending on source address, use the proper network
|
|
|
|
* interface when sending.
|
|
|
|
*/
|
|
|
|
net_pkt_set_vlan_tag(pkt, ctx->vlan[i].tag);
|
|
|
|
|
|
|
|
return NET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NET_DROP;
|
|
|
|
}
|
2018-02-07 15:15:24 +02:00
|
|
|
|
|
|
|
static void set_vlan_priority(struct ethernet_context *ctx,
|
|
|
|
struct net_pkt *pkt)
|
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint8_t vlan_priority;
|
2018-06-25 15:25:33 +02:00
|
|
|
|
|
|
|
vlan_priority = net_priority2vlan(net_pkt_priority(pkt));
|
|
|
|
net_pkt_set_vlan_priority(pkt, vlan_priority);
|
2018-02-07 15:15:24 +02:00
|
|
|
}
|
2018-06-08 10:03:06 +02:00
|
|
|
#else
|
|
|
|
#define set_vlan_tag(...) NET_DROP
|
|
|
|
#define set_vlan_priority(...)
|
2018-01-19 12:24:33 +02:00
|
|
|
#endif /* CONFIG_NET_VLAN */
|
|
|
|
|
2018-06-25 10:22:54 +02:00
|
|
|
static struct net_buf *ethernet_fill_header(struct ethernet_context *ctx,
|
|
|
|
struct net_pkt *pkt,
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t ptype)
|
2018-01-19 12:24:33 +02:00
|
|
|
{
|
2018-06-08 15:35:27 +02:00
|
|
|
struct net_buf *hdr_frag;
|
2018-01-19 12:24:33 +02:00
|
|
|
struct net_eth_hdr *hdr;
|
2022-11-15 17:17:21 +01:00
|
|
|
size_t hdr_len = IS_ENABLED(CONFIG_NET_VLAN) ?
|
|
|
|
sizeof(struct net_eth_vlan_hdr) :
|
|
|
|
sizeof(struct net_eth_hdr);
|
2018-06-08 15:35:27 +02:00
|
|
|
|
2022-11-15 17:17:21 +01:00
|
|
|
hdr_frag = net_pkt_get_frag(pkt, hdr_len, NET_BUF_TIMEOUT);
|
2018-06-08 15:35:27 +02:00
|
|
|
if (!hdr_frag) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-01-19 12:24:33 +02:00
|
|
|
|
2018-06-08 10:03:06 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_VLAN) &&
|
|
|
|
net_eth_is_vlan_enabled(ctx, net_pkt_iface(pkt))) {
|
2018-01-19 12:24:33 +02:00
|
|
|
struct net_eth_vlan_hdr *hdr_vlan;
|
|
|
|
|
2018-06-27 15:06:18 +02:00
|
|
|
hdr_vlan = (struct net_eth_vlan_hdr *)(hdr_frag->data);
|
2018-01-19 12:24:33 +02:00
|
|
|
|
2021-10-06 13:31:07 +13:00
|
|
|
if (ptype == htons(NET_ETH_PTYPE_ARP) ||
|
|
|
|
(!ethernet_fill_in_dst_on_ipv4_mcast(pkt, &hdr_vlan->dst) &&
|
|
|
|
!ethernet_fill_in_dst_on_ipv6_mcast(pkt, &hdr_vlan->dst))) {
|
2018-06-25 10:22:54 +02:00
|
|
|
memcpy(&hdr_vlan->dst, net_pkt_lladdr_dst(pkt)->addr,
|
2018-01-19 12:24:33 +02:00
|
|
|
sizeof(struct net_eth_addr));
|
|
|
|
}
|
|
|
|
|
2018-06-25 10:22:54 +02:00
|
|
|
memcpy(&hdr_vlan->src, net_pkt_lladdr_src(pkt)->addr,
|
|
|
|
sizeof(struct net_eth_addr));
|
2018-01-19 12:24:33 +02:00
|
|
|
|
|
|
|
hdr_vlan->type = ptype;
|
|
|
|
hdr_vlan->vlan.tpid = htons(NET_ETH_PTYPE_VLAN);
|
|
|
|
hdr_vlan->vlan.tci = htons(net_pkt_vlan_tci(pkt));
|
2019-04-11 11:21:59 +03:00
|
|
|
net_buf_add(hdr_frag, sizeof(struct net_eth_vlan_hdr));
|
2018-01-19 12:24:33 +02:00
|
|
|
|
|
|
|
print_vlan_ll_addrs(pkt, ntohs(hdr_vlan->type),
|
|
|
|
net_pkt_vlan_tci(pkt),
|
2018-06-08 15:35:27 +02:00
|
|
|
hdr_frag->len,
|
2019-04-12 14:15:34 +03:00
|
|
|
&hdr_vlan->src, &hdr_vlan->dst, false);
|
2018-06-08 15:35:27 +02:00
|
|
|
} else {
|
2018-06-27 15:06:18 +02:00
|
|
|
hdr = (struct net_eth_hdr *)(hdr_frag->data);
|
2018-01-19 12:24:33 +02:00
|
|
|
|
2021-10-06 13:31:07 +13:00
|
|
|
if (ptype == htons(NET_ETH_PTYPE_ARP) ||
|
|
|
|
(!ethernet_fill_in_dst_on_ipv4_mcast(pkt, &hdr->dst) &&
|
|
|
|
!ethernet_fill_in_dst_on_ipv6_mcast(pkt, &hdr->dst))) {
|
2018-06-25 10:22:54 +02:00
|
|
|
memcpy(&hdr->dst, net_pkt_lladdr_dst(pkt)->addr,
|
|
|
|
sizeof(struct net_eth_addr));
|
2018-06-08 15:35:27 +02:00
|
|
|
}
|
2018-06-12 11:38:50 +02:00
|
|
|
|
2018-06-25 10:22:54 +02:00
|
|
|
memcpy(&hdr->src, net_pkt_lladdr_src(pkt)->addr,
|
|
|
|
sizeof(struct net_eth_addr));
|
2018-01-19 12:24:33 +02:00
|
|
|
|
2018-06-08 15:35:27 +02:00
|
|
|
hdr->type = ptype;
|
2018-06-27 15:06:18 +02:00
|
|
|
net_buf_add(hdr_frag, sizeof(struct net_eth_hdr));
|
2018-01-19 12:24:33 +02:00
|
|
|
|
2018-06-08 15:35:27 +02:00
|
|
|
print_ll_addrs(pkt, ntohs(hdr->type),
|
|
|
|
hdr_frag->len, &hdr->src, &hdr->dst);
|
2018-01-19 12:24:33 +02:00
|
|
|
}
|
|
|
|
|
2018-06-08 15:35:27 +02:00
|
|
|
net_pkt_frag_insert(pkt, hdr_frag);
|
2018-01-19 12:24:33 +02:00
|
|
|
|
2018-06-08 15:35:27 +02:00
|
|
|
return hdr_frag;
|
2018-01-19 12:24:33 +02:00
|
|
|
}
|
|
|
|
|
2018-12-05 14:39:43 +01:00
|
|
|
#if defined(CONFIG_NET_STATISTICS_ETHERNET)
|
2019-01-07 15:18:53 +02:00
|
|
|
static void ethernet_update_tx_stats(struct net_if *iface, struct net_pkt *pkt)
|
2018-12-05 14:39:43 +01:00
|
|
|
{
|
|
|
|
struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
|
|
|
|
|
2019-01-07 15:18:53 +02:00
|
|
|
eth_stats_update_bytes_tx(iface, net_pkt_get_len(pkt));
|
|
|
|
eth_stats_update_pkts_tx(iface);
|
2018-12-05 14:39:43 +01:00
|
|
|
|
2019-01-07 15:18:53 +02:00
|
|
|
if (net_eth_is_addr_multicast(&hdr->dst)) {
|
|
|
|
eth_stats_update_multicast_tx(iface);
|
|
|
|
} else if (net_eth_is_addr_broadcast(&hdr->dst)) {
|
|
|
|
eth_stats_update_broadcast_tx(iface);
|
2018-12-05 14:39:43 +01:00
|
|
|
}
|
|
|
|
}
|
2019-05-28 13:42:57 +02:00
|
|
|
#else
|
|
|
|
#define ethernet_update_tx_stats(...)
|
2019-01-07 15:18:53 +02:00
|
|
|
#endif /* CONFIG_NET_STATISTICS_ETHERNET */
|
|
|
|
|
2019-01-18 08:03:53 +01:00
|
|
|
static void ethernet_remove_l2_header(struct net_pkt *pkt)
|
|
|
|
{
|
|
|
|
struct net_buf *buf;
|
|
|
|
|
|
|
|
/* Remove the buffer added in ethernet_fill_header() */
|
|
|
|
buf = pkt->buffer;
|
|
|
|
pkt->buffer = buf->frags;
|
|
|
|
buf->frags = NULL;
|
|
|
|
|
|
|
|
net_pkt_frag_unref(buf);
|
|
|
|
}
|
|
|
|
|
2018-06-26 14:51:05 +02:00
|
|
|
static int ethernet_send(struct net_if *iface, struct net_pkt *pkt)
|
2018-06-26 14:41:54 +02:00
|
|
|
{
|
2020-05-28 21:23:02 +02:00
|
|
|
const struct ethernet_api *api = net_if_get_device(iface)->api;
|
2018-06-26 14:41:54 +02:00
|
|
|
struct ethernet_context *ctx = net_if_l2_data(iface);
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t ptype;
|
2018-06-26 14:41:54 +02:00
|
|
|
int ret;
|
|
|
|
|
2019-04-15 23:58:00 +03:00
|
|
|
if (!api) {
|
|
|
|
ret = -ENOENT;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2021-06-25 18:54:17 -04:00
|
|
|
if (IS_ENABLED(CONFIG_NET_ETHERNET_BRIDGE) &&
|
|
|
|
net_pkt_is_l2_bridged(pkt)) {
|
|
|
|
net_pkt_cursor_init(pkt);
|
|
|
|
ret = net_l2_send(api->send, net_if_get_device(iface), iface, pkt);
|
|
|
|
if (ret != 0) {
|
|
|
|
eth_stats_update_errors_tx(iface);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
ethernet_update_tx_stats(iface, pkt);
|
|
|
|
ret = net_pkt_get_len(pkt);
|
|
|
|
net_pkt_unref(pkt);
|
|
|
|
return ret;
|
|
|
|
} else if (IS_ENABLED(CONFIG_NET_IPV4) &&
|
2018-06-26 14:41:54 +02:00
|
|
|
net_pkt_family(pkt) == AF_INET) {
|
|
|
|
struct net_pkt *tmp;
|
|
|
|
|
2019-04-12 12:24:43 -06:00
|
|
|
if (net_pkt_ipv4_auto(pkt)) {
|
2018-11-20 10:41:57 +02:00
|
|
|
ptype = htons(NET_ETH_PTYPE_ARP);
|
2018-06-25 10:22:54 +02:00
|
|
|
} else {
|
2019-04-12 12:24:43 -06:00
|
|
|
tmp = ethernet_ll_prepare_on_ipv4(iface, pkt);
|
|
|
|
if (!tmp) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto error;
|
|
|
|
} else if (IS_ENABLED(CONFIG_NET_ARP) && tmp != pkt) {
|
|
|
|
/* Original pkt got queued and is replaced
|
|
|
|
* by an ARP request packet.
|
|
|
|
*/
|
|
|
|
pkt = tmp;
|
|
|
|
ptype = htons(NET_ETH_PTYPE_ARP);
|
|
|
|
net_pkt_set_family(pkt, AF_INET);
|
|
|
|
} else {
|
|
|
|
ptype = htons(NET_ETH_PTYPE_IP);
|
|
|
|
}
|
2018-06-25 10:22:54 +02:00
|
|
|
}
|
2018-06-26 14:41:54 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_IPV6) &&
|
|
|
|
net_pkt_family(pkt) == AF_INET6) {
|
|
|
|
ptype = htons(NET_ETH_PTYPE_IPV6);
|
2019-01-30 15:50:44 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
|
|
|
|
net_pkt_family(pkt) == AF_PACKET) {
|
2020-06-14 12:51:04 +03:00
|
|
|
struct net_context *context = net_pkt_context(pkt);
|
|
|
|
|
|
|
|
if (context && net_context_get_type(context) == SOCK_DGRAM) {
|
|
|
|
struct sockaddr_ll *dst_addr;
|
|
|
|
struct sockaddr_ll_ptr *src_addr;
|
|
|
|
|
|
|
|
/* The destination address is set in remote for this
|
|
|
|
* socket type.
|
|
|
|
*/
|
|
|
|
dst_addr = (struct sockaddr_ll *)&context->remote;
|
|
|
|
src_addr = (struct sockaddr_ll_ptr *)&context->local;
|
|
|
|
|
|
|
|
net_pkt_lladdr_dst(pkt)->addr = dst_addr->sll_addr;
|
|
|
|
net_pkt_lladdr_dst(pkt)->len =
|
|
|
|
sizeof(struct net_eth_addr);
|
|
|
|
net_pkt_lladdr_src(pkt)->addr = src_addr->sll_addr;
|
|
|
|
net_pkt_lladdr_src(pkt)->len =
|
|
|
|
sizeof(struct net_eth_addr);
|
|
|
|
ptype = dst_addr->sll_protocol;
|
|
|
|
} else {
|
|
|
|
goto send;
|
|
|
|
}
|
2021-09-08 20:28:27 -07:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_L2_PTP) && net_pkt_is_ptp(pkt)) {
|
2018-11-12 11:42:44 +01:00
|
|
|
ptype = htons(NET_ETH_PTYPE_PTP);
|
2019-01-11 13:35:11 +01:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_LLDP) && net_pkt_is_lldp(pkt)) {
|
|
|
|
ptype = htons(NET_ETH_PTYPE_LLDP);
|
2018-06-26 14:41:54 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_ARP)) {
|
2022-03-16 21:07:43 +00:00
|
|
|
/* Unknown type: Unqueued pkt is an ARP reply.
|
2018-06-26 14:41:54 +02:00
|
|
|
*/
|
|
|
|
ptype = htons(NET_ETH_PTYPE_ARP);
|
|
|
|
net_pkt_set_family(pkt, AF_INET);
|
2018-06-25 10:22:54 +02:00
|
|
|
} else {
|
2018-06-26 14:41:54 +02:00
|
|
|
ret = -ENOTSUP;
|
|
|
|
goto error;
|
2016-06-07 14:20:15 +03:00
|
|
|
}
|
|
|
|
|
2018-06-26 14:41:54 +02:00
|
|
|
/* If the ll dst addr has not been set before, let's assume
|
2019-06-18 14:45:40 -04:00
|
|
|
* temporarily it's a broadcast one. When filling the header,
|
2018-06-26 14:41:54 +02:00
|
|
|
* it might detect this should be multicast and act accordingly.
|
2016-06-07 14:20:15 +03:00
|
|
|
*/
|
2018-09-11 09:16:03 +02:00
|
|
|
if (!net_pkt_lladdr_dst(pkt)->addr) {
|
2020-05-27 11:26:57 -05:00
|
|
|
net_pkt_lladdr_dst(pkt)->addr = (uint8_t *)broadcast_eth_addr.addr;
|
2018-09-11 09:16:03 +02:00
|
|
|
net_pkt_lladdr_dst(pkt)->len = sizeof(struct net_eth_addr);
|
2016-06-08 14:38:45 +03:00
|
|
|
}
|
2016-06-07 14:19:12 +03:00
|
|
|
|
2018-06-08 10:03:06 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_VLAN) &&
|
|
|
|
net_eth_is_vlan_enabled(ctx, iface)) {
|
2018-01-19 12:24:33 +02:00
|
|
|
if (set_vlan_tag(ctx, iface, pkt) == NET_DROP) {
|
2018-06-26 14:41:54 +02:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto error;
|
2018-01-19 12:24:33 +02:00
|
|
|
}
|
2018-02-07 15:15:24 +02:00
|
|
|
|
|
|
|
set_vlan_priority(ctx, pkt);
|
2018-01-19 12:24:33 +02:00
|
|
|
}
|
|
|
|
|
2018-06-25 10:22:54 +02:00
|
|
|
/* Then set the ethernet header.
|
|
|
|
*/
|
|
|
|
if (!ethernet_fill_header(ctx, pkt, ptype)) {
|
2018-06-26 14:41:54 +02:00
|
|
|
ret = -ENOMEM;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2018-11-27 20:16:42 +01:00
|
|
|
net_pkt_cursor_init(pkt);
|
|
|
|
|
2019-01-30 15:50:44 +02:00
|
|
|
send:
|
2021-03-28 16:19:42 +03:00
|
|
|
ret = net_l2_send(api->send, net_if_get_device(iface), iface, pkt);
|
2019-01-07 15:18:53 +02:00
|
|
|
if (ret != 0) {
|
|
|
|
eth_stats_update_errors_tx(iface);
|
2019-01-18 08:03:53 +01:00
|
|
|
ethernet_remove_l2_header(pkt);
|
2019-01-07 15:18:53 +02:00
|
|
|
goto error;
|
2018-06-25 10:22:54 +02:00
|
|
|
}
|
2019-05-28 13:42:57 +02:00
|
|
|
|
2019-01-07 15:18:53 +02:00
|
|
|
ethernet_update_tx_stats(iface, pkt);
|
2019-05-28 13:42:57 +02:00
|
|
|
|
2019-01-07 15:18:53 +02:00
|
|
|
ret = net_pkt_get_len(pkt);
|
2019-01-18 08:03:53 +01:00
|
|
|
ethernet_remove_l2_header(pkt);
|
2018-06-25 10:22:54 +02:00
|
|
|
|
2019-01-07 15:18:53 +02:00
|
|
|
net_pkt_unref(pkt);
|
2018-06-26 14:41:54 +02:00
|
|
|
error:
|
|
|
|
return ret;
|
2018-06-25 10:22:54 +02:00
|
|
|
}
|
|
|
|
|
2017-04-22 14:13:23 +08:00
|
|
|
static inline int ethernet_enable(struct net_if *iface, bool state)
|
|
|
|
{
|
2018-08-09 16:08:27 +03:00
|
|
|
const struct ethernet_api *eth =
|
2020-05-28 21:23:02 +02:00
|
|
|
net_if_get_device(iface)->api;
|
2018-08-09 16:08:27 +03:00
|
|
|
|
2019-04-15 23:58:00 +03:00
|
|
|
if (!eth) {
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2017-04-22 14:13:23 +08:00
|
|
|
if (!state) {
|
2018-06-11 09:42:03 +02:00
|
|
|
net_arp_clear_cache(iface);
|
2018-08-09 16:08:27 +03:00
|
|
|
|
|
|
|
if (eth->stop) {
|
|
|
|
eth->stop(net_if_get_device(iface));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (eth->start) {
|
|
|
|
eth->start(net_if_get_device(iface));
|
|
|
|
}
|
2017-04-22 14:13:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-08-06 16:59:33 +03:00
|
|
|
enum net_l2_flags ethernet_flags(struct net_if *iface)
|
|
|
|
{
|
|
|
|
struct ethernet_context *ctx = net_if_l2_data(iface);
|
|
|
|
|
|
|
|
return ctx->ethernet_l2_flags;
|
|
|
|
}
|
|
|
|
|
2018-01-19 12:24:33 +02:00
|
|
|
#if defined(CONFIG_NET_VLAN)
|
2020-05-27 11:26:57 -05:00
|
|
|
struct net_if *net_eth_get_vlan_iface(struct net_if *iface, uint16_t tag)
|
2018-01-19 12:24:33 +02:00
|
|
|
{
|
|
|
|
struct ethernet_context *ctx = net_if_l2_data(iface);
|
2018-04-06 15:37:42 +03:00
|
|
|
struct net_if *first_non_vlan_iface = NULL;
|
2018-01-19 12:24:33 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
|
2018-04-06 15:37:42 +03:00
|
|
|
if (ctx->vlan[i].tag == NET_VLAN_TAG_UNSPEC) {
|
|
|
|
if (!first_non_vlan_iface) {
|
|
|
|
first_non_vlan_iface = ctx->vlan[i].iface;
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->vlan[i].tag != tag) {
|
2018-01-19 12:24:33 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
NET_DBG("[%d] vlan tag %d -> iface %p", i, tag,
|
|
|
|
ctx->vlan[i].iface);
|
|
|
|
|
|
|
|
return ctx->vlan[i].iface;
|
|
|
|
}
|
|
|
|
|
2018-04-06 15:37:42 +03:00
|
|
|
return first_non_vlan_iface;
|
2018-01-19 12:24:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool enable_vlan_iface(struct ethernet_context *ctx,
|
|
|
|
struct net_if *iface)
|
|
|
|
{
|
|
|
|
int iface_idx = net_if_get_by_iface(iface);
|
|
|
|
|
|
|
|
if (iface_idx < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_set_bit(ctx->interfaces, iface_idx);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool disable_vlan_iface(struct ethernet_context *ctx,
|
|
|
|
struct net_if *iface)
|
|
|
|
{
|
|
|
|
int iface_idx = net_if_get_by_iface(iface);
|
|
|
|
|
|
|
|
if (iface_idx < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_clear_bit(ctx->interfaces, iface_idx);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool is_vlan_enabled_for_iface(struct ethernet_context *ctx,
|
|
|
|
struct net_if *iface)
|
|
|
|
{
|
|
|
|
int iface_idx = net_if_get_by_iface(iface);
|
|
|
|
|
|
|
|
if (iface_idx < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return !!atomic_test_bit(ctx->interfaces, iface_idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool net_eth_is_vlan_enabled(struct ethernet_context *ctx,
|
|
|
|
struct net_if *iface)
|
|
|
|
{
|
|
|
|
if (ctx->vlan_enabled) {
|
|
|
|
if (ctx->vlan_enabled == NET_VLAN_MAX_COUNT) {
|
|
|
|
/* All network interface are using VLAN, no need
|
|
|
|
* to check further.
|
|
|
|
*/
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_vlan_enabled_for_iface(ctx, iface)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t net_eth_get_vlan_tag(struct net_if *iface)
|
2018-01-19 12:24:33 +02:00
|
|
|
{
|
|
|
|
struct ethernet_context *ctx = net_if_l2_data(iface);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
|
|
|
|
if (ctx->vlan[i].iface == iface) {
|
|
|
|
return ctx->vlan[i].tag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NET_VLAN_TAG_UNSPEC;
|
|
|
|
}
|
|
|
|
|
2018-07-03 10:58:12 +03:00
|
|
|
bool net_eth_get_vlan_status(struct net_if *iface)
|
|
|
|
{
|
|
|
|
struct ethernet_context *ctx = net_if_l2_data(iface);
|
|
|
|
|
|
|
|
if (ctx->vlan_enabled &&
|
|
|
|
net_eth_get_vlan_tag(iface) != NET_VLAN_TAG_UNSPEC) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-01-19 12:24:33 +02:00
|
|
|
static struct ethernet_vlan *get_vlan(struct ethernet_context *ctx,
|
|
|
|
struct net_if *iface,
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t vlan_tag)
|
2018-01-19 12:24:33 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
|
|
|
|
if (ctx->vlan[i].iface == iface &&
|
|
|
|
ctx->vlan[i].tag == vlan_tag) {
|
|
|
|
return &ctx->vlan[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-01-29 13:31:05 +02:00
|
|
|
static void setup_ipv6_link_local_addr(struct net_if *iface)
|
|
|
|
{
|
|
|
|
struct net_linkaddr link_addr;
|
|
|
|
struct net_if_addr *ifaddr;
|
|
|
|
struct in6_addr addr;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t entropy;
|
|
|
|
uint8_t mac_addr[6];
|
2020-01-29 13:31:05 +02:00
|
|
|
|
|
|
|
entropy = sys_rand32_get();
|
|
|
|
mac_addr[0] = entropy >> 0;
|
|
|
|
mac_addr[1] = entropy >> 8;
|
|
|
|
mac_addr[2] = entropy >> 16;
|
|
|
|
|
|
|
|
entropy = sys_rand32_get();
|
|
|
|
mac_addr[3] = entropy >> 0;
|
|
|
|
mac_addr[4] = entropy >> 8;
|
|
|
|
mac_addr[5] = entropy >> 16;
|
|
|
|
|
|
|
|
mac_addr[0] |= 0x02; /* force LAA bit */
|
|
|
|
|
|
|
|
link_addr.len = sizeof(mac_addr);
|
|
|
|
link_addr.type = NET_LINK_ETHERNET;
|
|
|
|
link_addr.addr = mac_addr;
|
|
|
|
|
|
|
|
net_ipv6_addr_create_iid(&addr, &link_addr);
|
|
|
|
|
|
|
|
ifaddr = net_if_ipv6_addr_add(iface, &addr, NET_ADDR_AUTOCONF, 0);
|
|
|
|
if (!ifaddr) {
|
|
|
|
NET_DBG("Cannot add %s address to VLAN interface %p",
|
2022-06-20 07:43:37 +02:00
|
|
|
net_sprint_ipv6_addr(&addr), iface);
|
2020-01-29 13:31:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
int net_eth_vlan_enable(struct net_if *iface, uint16_t tag)
|
2018-01-19 12:24:33 +02:00
|
|
|
{
|
|
|
|
struct ethernet_context *ctx = net_if_l2_data(iface);
|
|
|
|
const struct ethernet_api *eth =
|
2020-05-28 21:23:02 +02:00
|
|
|
net_if_get_device(iface)->api;
|
2018-01-19 12:24:33 +02:00
|
|
|
struct ethernet_vlan *vlan;
|
|
|
|
int i;
|
|
|
|
|
2019-04-15 23:58:00 +03:00
|
|
|
if (!eth) {
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2018-01-19 12:24:33 +02:00
|
|
|
if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ctx->is_init) {
|
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
|
2021-11-23 12:24:50 +01:00
|
|
|
if (tag >= NET_VLAN_TAG_UNSPEC) {
|
2018-01-19 12:24:33 +02:00
|
|
|
return -EBADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
vlan = get_vlan(ctx, iface, tag);
|
|
|
|
if (vlan) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
|
|
|
|
if (ctx->vlan[i].iface != iface) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->vlan[i].tag != NET_VLAN_TAG_UNSPEC) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
NET_DBG("[%d] Adding vlan tag %d to iface %p", i, tag, iface);
|
|
|
|
|
|
|
|
ctx->vlan[i].tag = tag;
|
|
|
|
|
2020-01-29 13:31:05 +02:00
|
|
|
/* Add a link local IPv6 address to VLAN interface here.
|
|
|
|
* Each network interface needs LL address, but as there is
|
|
|
|
* only one link (MAC) address defined for all the master and
|
|
|
|
* slave interfaces, the VLAN interface might be left without
|
|
|
|
* a LL address. In order to solve this issue, we create a
|
|
|
|
* random LL address and set it to the VLAN network interface.
|
|
|
|
*/
|
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6)) {
|
|
|
|
setup_ipv6_link_local_addr(iface);
|
|
|
|
}
|
|
|
|
|
2018-01-19 12:24:33 +02:00
|
|
|
enable_vlan_iface(ctx, iface);
|
|
|
|
|
|
|
|
if (eth->vlan_setup) {
|
2018-04-05 17:01:06 +02:00
|
|
|
eth->vlan_setup(net_if_get_device(iface),
|
|
|
|
iface, tag, true);
|
2018-01-19 12:24:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx->vlan_enabled++;
|
|
|
|
if (ctx->vlan_enabled > NET_VLAN_MAX_COUNT) {
|
|
|
|
ctx->vlan_enabled = NET_VLAN_MAX_COUNT;
|
|
|
|
}
|
|
|
|
|
2018-07-03 12:56:08 +03:00
|
|
|
ethernet_mgmt_raise_vlan_enabled_event(iface, tag);
|
|
|
|
|
2018-01-19 12:24:33 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOSPC;
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
int net_eth_vlan_disable(struct net_if *iface, uint16_t tag)
|
2018-01-19 12:24:33 +02:00
|
|
|
{
|
|
|
|
struct ethernet_context *ctx = net_if_l2_data(iface);
|
|
|
|
const struct ethernet_api *eth =
|
2020-05-28 21:23:02 +02:00
|
|
|
net_if_get_device(iface)->api;
|
2018-01-19 12:24:33 +02:00
|
|
|
struct ethernet_vlan *vlan;
|
|
|
|
|
2019-04-15 23:58:00 +03:00
|
|
|
if (!eth) {
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2018-01-19 12:24:33 +02:00
|
|
|
if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tag == NET_VLAN_TAG_UNSPEC) {
|
|
|
|
return -EBADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
vlan = get_vlan(ctx, iface, tag);
|
|
|
|
if (!vlan) {
|
|
|
|
return -ESRCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
NET_DBG("Removing vlan tag %d from iface %p", vlan->tag, vlan->iface);
|
|
|
|
|
|
|
|
vlan->tag = NET_VLAN_TAG_UNSPEC;
|
|
|
|
|
|
|
|
disable_vlan_iface(ctx, iface);
|
|
|
|
|
|
|
|
if (eth->vlan_setup) {
|
2018-04-05 17:01:06 +02:00
|
|
|
eth->vlan_setup(net_if_get_device(iface), iface, tag, false);
|
2018-01-19 12:24:33 +02:00
|
|
|
}
|
|
|
|
|
2018-07-03 12:56:08 +03:00
|
|
|
ethernet_mgmt_raise_vlan_disabled_event(iface, tag);
|
|
|
|
|
2018-01-19 12:24:33 +02:00
|
|
|
ctx->vlan_enabled--;
|
|
|
|
if (ctx->vlan_enabled < 0) {
|
|
|
|
ctx->vlan_enabled = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-05-28 13:42:57 +02:00
|
|
|
#endif /* CONFIG_NET_VLAN */
|
2018-01-19 12:24:33 +02:00
|
|
|
|
2018-06-28 09:58:50 +02:00
|
|
|
NET_L2_INIT(ETHERNET_L2, ethernet_recv, ethernet_send, ethernet_enable,
|
|
|
|
ethernet_flags);
|
2018-01-19 12:24:33 +02:00
|
|
|
|
2021-03-16 17:18:54 +01:00
|
|
|
static void carrier_on_off(struct k_work *work)
|
2018-06-04 13:37:17 +03:00
|
|
|
{
|
2021-03-16 17:18:54 +01:00
|
|
|
struct ethernet_context *ctx = CONTAINER_OF(work, struct ethernet_context,
|
|
|
|
carrier_work);
|
|
|
|
bool eth_carrier_up;
|
2018-06-04 13:37:17 +03:00
|
|
|
|
2021-03-16 17:18:54 +01:00
|
|
|
if (ctx->iface == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2018-06-04 13:37:17 +03:00
|
|
|
|
2021-03-16 17:18:54 +01:00
|
|
|
eth_carrier_up = atomic_test_bit(&ctx->flags, ETH_CARRIER_UP);
|
2018-06-04 13:37:17 +03:00
|
|
|
|
2021-03-16 17:18:54 +01:00
|
|
|
if (eth_carrier_up == ctx->is_net_carrier_up) {
|
|
|
|
return;
|
|
|
|
}
|
2018-06-04 13:37:17 +03:00
|
|
|
|
2021-03-16 17:18:54 +01:00
|
|
|
ctx->is_net_carrier_up = eth_carrier_up;
|
2018-06-04 13:37:17 +03:00
|
|
|
|
2021-03-16 17:18:54 +01:00
|
|
|
NET_DBG("Carrier %s for interface %p", eth_carrier_up ? "ON" : "OFF",
|
|
|
|
ctx->iface);
|
2018-06-04 13:37:17 +03:00
|
|
|
|
2021-03-16 17:18:54 +01:00
|
|
|
if (eth_carrier_up) {
|
|
|
|
ethernet_mgmt_raise_carrier_on_event(ctx->iface);
|
2022-09-30 14:53:44 +02:00
|
|
|
net_if_carrier_on(ctx->iface);
|
2021-03-16 17:18:54 +01:00
|
|
|
} else {
|
|
|
|
ethernet_mgmt_raise_carrier_off_event(ctx->iface);
|
2022-09-30 14:53:44 +02:00
|
|
|
net_if_carrier_off(ctx->iface);
|
2021-03-16 17:18:54 +01:00
|
|
|
}
|
2018-06-04 13:37:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void net_eth_carrier_on(struct net_if *iface)
|
|
|
|
{
|
|
|
|
struct ethernet_context *ctx = net_if_l2_data(iface);
|
|
|
|
|
2021-03-16 17:18:54 +01:00
|
|
|
if (!atomic_test_and_set_bit(&ctx->flags, ETH_CARRIER_UP)) {
|
|
|
|
k_work_submit(&ctx->carrier_work);
|
|
|
|
}
|
2018-06-04 13:37:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void net_eth_carrier_off(struct net_if *iface)
|
|
|
|
{
|
|
|
|
struct ethernet_context *ctx = net_if_l2_data(iface);
|
|
|
|
|
2021-03-16 17:18:54 +01:00
|
|
|
if (atomic_test_and_clear_bit(&ctx->flags, ETH_CARRIER_UP)) {
|
|
|
|
k_work_submit(&ctx->carrier_work);
|
|
|
|
}
|
2018-06-04 13:37:17 +03:00
|
|
|
}
|
|
|
|
|
2019-05-27 20:50:08 +08:00
|
|
|
#if defined(CONFIG_PTP_CLOCK)
|
2020-04-30 20:33:38 +02:00
|
|
|
const struct device *net_eth_get_ptp_clock(struct net_if *iface)
|
2018-01-24 15:22:55 +02:00
|
|
|
{
|
2020-04-30 20:33:38 +02:00
|
|
|
const struct device *dev = net_if_get_device(iface);
|
2020-05-28 21:23:02 +02:00
|
|
|
const struct ethernet_api *api = dev->api;
|
2018-01-24 15:22:55 +02:00
|
|
|
|
2019-04-15 23:58:00 +03:00
|
|
|
if (!api) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-01-24 15:22:55 +02:00
|
|
|
if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(api->get_capabilities(dev) & ETHERNET_PTP)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-05-15 14:57:33 +03:00
|
|
|
if (!api->get_ptp_clock) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-01-24 15:22:55 +02:00
|
|
|
return api->get_ptp_clock(net_if_get_device(iface));
|
|
|
|
}
|
2019-05-27 20:50:08 +08:00
|
|
|
#endif /* CONFIG_PTP_CLOCK */
|
2018-01-24 15:22:55 +02:00
|
|
|
|
2019-05-24 14:43:56 +03:00
|
|
|
#if defined(CONFIG_PTP_CLOCK)
|
2020-04-30 20:33:38 +02:00
|
|
|
const struct device *z_impl_net_eth_get_ptp_clock_by_index(int index)
|
2019-05-24 14:43:56 +03:00
|
|
|
{
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
iface = net_if_get_by_index(index);
|
|
|
|
if (!iface) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return net_eth_get_ptp_clock(iface);
|
|
|
|
}
|
2019-05-27 12:44:01 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_USERSPACE
|
2020-04-30 20:33:38 +02:00
|
|
|
static inline const struct device *z_vrfy_net_eth_get_ptp_clock_by_index(int index)
|
2019-05-27 12:44:01 +08:00
|
|
|
{
|
userspace: Support for split 64 bit arguments
System call arguments, at the arch layer, are single words. So
passing wider values requires splitting them into two registers at
call time. This gets even more complicated for values (e.g
k_timeout_t) that may have different sizes depending on configuration.
This patch adds a feature to gen_syscalls.py to detect functions with
wide arguments and automatically generates code to split/unsplit them.
Unfortunately the current scheme of Z_SYSCALL_DECLARE_* macros won't
work with functions like this, because for N arguments (our current
maximum N is 10) there are 2^N possible configurations of argument
widths. So this generates the complete functions for each handler and
wrapper, effectively doing in python what was originally done in the
preprocessor.
Another complexity is that traditional the z_hdlr_*() function for a
system call has taken the raw list of word arguments, which does not
work when some of those arguments must be 64 bit types. So instead of
using a single Z_SYSCALL_HANDLER macro, this splits the job of
z_hdlr_*() into two steps: An automatically-generated unmarshalling
function, z_mrsh_*(), which then calls a user-supplied verification
function z_vrfy_*(). The verification function is typesafe, and is a
simple C function with exactly the same argument and return signature
as the syscall impl function. It is also not responsible for
validating the pointers to the extra parameter array or a wide return
value, that code gets automatically generated.
This commit includes new vrfy/msrh handling for all syscalls invoked
during CI runs. Future commits will port the less testable code.
Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2019-08-06 13:34:31 -07:00
|
|
|
return z_impl_net_eth_get_ptp_clock_by_index(index);
|
2019-05-27 12:44:01 +08:00
|
|
|
}
|
userspace: Support for split 64 bit arguments
System call arguments, at the arch layer, are single words. So
passing wider values requires splitting them into two registers at
call time. This gets even more complicated for values (e.g
k_timeout_t) that may have different sizes depending on configuration.
This patch adds a feature to gen_syscalls.py to detect functions with
wide arguments and automatically generates code to split/unsplit them.
Unfortunately the current scheme of Z_SYSCALL_DECLARE_* macros won't
work with functions like this, because for N arguments (our current
maximum N is 10) there are 2^N possible configurations of argument
widths. So this generates the complete functions for each handler and
wrapper, effectively doing in python what was originally done in the
preprocessor.
Another complexity is that traditional the z_hdlr_*() function for a
system call has taken the raw list of word arguments, which does not
work when some of those arguments must be 64 bit types. So instead of
using a single Z_SYSCALL_HANDLER macro, this splits the job of
z_hdlr_*() into two steps: An automatically-generated unmarshalling
function, z_mrsh_*(), which then calls a user-supplied verification
function z_vrfy_*(). The verification function is typesafe, and is a
simple C function with exactly the same argument and return signature
as the syscall impl function. It is also not responsible for
validating the pointers to the extra parameter array or a wide return
value, that code gets automatically generated.
This commit includes new vrfy/msrh handling for all syscalls invoked
during CI runs. Future commits will port the less testable code.
Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2019-08-06 13:34:31 -07:00
|
|
|
#include <syscalls/net_eth_get_ptp_clock_by_index_mrsh.c>
|
2019-05-27 12:44:01 +08:00
|
|
|
#endif /* CONFIG_USERSPACE */
|
|
|
|
#else /* CONFIG_PTP_CLOCK */
|
2020-04-30 20:33:38 +02:00
|
|
|
const struct device *z_impl_net_eth_get_ptp_clock_by_index(int index)
|
2019-05-27 12:44:01 +08:00
|
|
|
{
|
|
|
|
ARG_UNUSED(index);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_PTP_CLOCK */
|
2019-05-24 14:43:56 +03:00
|
|
|
|
2021-09-08 20:28:27 -07:00
|
|
|
#if defined(CONFIG_NET_L2_PTP)
|
2018-01-24 14:33:35 +02:00
|
|
|
int net_eth_get_ptp_port(struct net_if *iface)
|
|
|
|
{
|
|
|
|
struct ethernet_context *ctx = net_if_l2_data(iface);
|
|
|
|
|
|
|
|
return ctx->port;
|
|
|
|
}
|
|
|
|
|
|
|
|
void net_eth_set_ptp_port(struct net_if *iface, int port)
|
|
|
|
{
|
|
|
|
struct ethernet_context *ctx = net_if_l2_data(iface);
|
|
|
|
|
|
|
|
ctx->port = port;
|
|
|
|
}
|
2021-09-08 20:28:27 -07:00
|
|
|
#endif /* CONFIG_NET_L2_PTP */
|
2018-01-24 14:33:35 +02:00
|
|
|
|
2018-07-20 16:44:58 +03:00
|
|
|
int net_eth_promisc_mode(struct net_if *iface, bool enable)
|
|
|
|
{
|
|
|
|
struct ethernet_req_params params;
|
|
|
|
|
|
|
|
if (!(net_eth_get_hw_capabilities(iface) & ETHERNET_PROMISC_MODE)) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
params.promisc_mode = enable;
|
|
|
|
|
|
|
|
return net_mgmt(NET_REQUEST_ETHERNET_SET_PROMISC_MODE, iface,
|
|
|
|
¶ms, sizeof(struct ethernet_req_params));
|
|
|
|
}
|
|
|
|
|
2018-01-19 12:24:33 +02:00
|
|
|
void ethernet_init(struct net_if *iface)
|
|
|
|
{
|
|
|
|
struct ethernet_context *ctx = net_if_l2_data(iface);
|
2018-06-04 13:37:17 +03:00
|
|
|
|
|
|
|
#if defined(CONFIG_NET_VLAN)
|
2018-01-19 12:24:33 +02:00
|
|
|
int i;
|
2018-06-04 13:37:17 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
NET_DBG("Initializing Ethernet L2 %p for iface %p", ctx, iface);
|
2018-01-19 12:24:33 +02:00
|
|
|
|
2018-08-06 16:59:33 +03:00
|
|
|
ctx->ethernet_l2_flags = NET_L2_MULTICAST;
|
2021-03-16 17:18:54 +01:00
|
|
|
ctx->iface = iface;
|
|
|
|
k_work_init(&ctx->carrier_work, carrier_on_off);
|
2018-08-06 16:59:33 +03:00
|
|
|
|
2018-08-06 17:46:37 +03:00
|
|
|
if (net_eth_get_hw_capabilities(iface) & ETHERNET_PROMISC_MODE) {
|
|
|
|
ctx->ethernet_l2_flags |= NET_L2_PROMISC_MODE;
|
|
|
|
}
|
|
|
|
|
2018-06-04 13:37:17 +03:00
|
|
|
#if defined(CONFIG_NET_VLAN)
|
2018-04-06 10:57:13 +02:00
|
|
|
if (!(net_eth_get_hw_capabilities(iface) & ETHERNET_HW_VLAN)) {
|
2018-01-19 12:24:33 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
|
|
|
|
if (!ctx->vlan[i].iface) {
|
|
|
|
NET_DBG("[%d] alloc ctx %p iface %p", i, ctx, iface);
|
|
|
|
ctx->vlan[i].tag = NET_VLAN_TAG_UNSPEC;
|
|
|
|
ctx->vlan[i].iface = iface;
|
|
|
|
|
|
|
|
if (!ctx->is_init) {
|
|
|
|
atomic_clear(ctx->interfaces);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-06-04 13:37:17 +03:00
|
|
|
#endif
|
2018-01-19 12:24:33 +02:00
|
|
|
|
2018-06-15 21:08:27 +02:00
|
|
|
net_arp_init();
|
|
|
|
|
2018-01-19 12:24:33 +02:00
|
|
|
ctx->is_init = true;
|
|
|
|
}
|