net: ethernet: Set the ptype by the caller in send

Instead of setting the upper protocol type in ethernet_send()
by checking the protocol type bits, use the ptype that is already
set by the caller. This allows new protocol types to be supported
and makes the system extensible.

Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
This commit is contained in:
Jukka Rissanen 2024-12-19 15:48:10 +02:00 committed by Benjamin Cabé
parent f6971ae7c2
commit 2f10d7d816
9 changed files with 77 additions and 44 deletions

View file

@ -17,6 +17,7 @@ LOG_MODULE_REGISTER(net_ipv4, CONFIG_NET_IPV4_LOG_LEVEL);
#include <zephyr/net/net_stats.h> #include <zephyr/net/net_stats.h>
#include <zephyr/net/net_context.h> #include <zephyr/net/net_context.h>
#include <zephyr/net/virtual.h> #include <zephyr/net/virtual.h>
#include <zephyr/net/ethernet.h>
#include "net_private.h" #include "net_private.h"
#include "connection.h" #include "connection.h"
#include "net_stats.h" #include "net_stats.h"
@ -133,6 +134,7 @@ int net_ipv4_finalize(struct net_pkt *pkt, uint8_t next_header_proto)
} }
net_pkt_set_data(pkt, &ipv4_access); net_pkt_set_data(pkt, &ipv4_access);
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_IP);
if (IS_ENABLED(CONFIG_NET_UDP) && if (IS_ENABLED(CONFIG_NET_UDP) &&
next_header_proto == IPPROTO_UDP) { next_header_proto == IPPROTO_UDP) {
@ -452,6 +454,8 @@ drop:
enum net_verdict net_ipv4_prepare_for_send(struct net_pkt *pkt) enum net_verdict net_ipv4_prepare_for_send(struct net_pkt *pkt)
{ {
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_IP);
if (IS_ENABLED(CONFIG_NET_IPV4_PMTU)) { if (IS_ENABLED(CONFIG_NET_IPV4_PMTU)) {
struct net_pmtu_entry *entry; struct net_pmtu_entry *entry;
struct sockaddr_in dst = { struct sockaddr_in dst = {

View file

@ -30,6 +30,7 @@ LOG_MODULE_REGISTER(net_ipv6, CONFIG_NET_IPV6_LOG_LEVEL);
#include <zephyr/net/net_context.h> #include <zephyr/net/net_context.h>
#include <zephyr/net/net_mgmt.h> #include <zephyr/net/net_mgmt.h>
#include <zephyr/net/virtual.h> #include <zephyr/net/virtual.h>
#include <zephyr/net/ethernet.h>
#include "net_private.h" #include "net_private.h"
#include "connection.h" #include "connection.h"
#include "icmpv6.h" #include "icmpv6.h"
@ -142,6 +143,8 @@ int net_ipv6_finalize(struct net_pkt *pkt, uint8_t next_header_proto)
return -ENOBUFS; return -ENOBUFS;
} }
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_IPV6);
if (IS_ENABLED(CONFIG_NET_UDP) && if (IS_ENABLED(CONFIG_NET_UDP) &&
next_header_proto == IPPROTO_UDP) { next_header_proto == IPPROTO_UDP) {
return net_udp_finalize(pkt, false); return net_udp_finalize(pkt, false);

View file

@ -25,6 +25,7 @@ LOG_MODULE_REGISTER(net_ipv6_nd, CONFIG_NET_IPV6_ND_LOG_LEVEL);
#include <zephyr/net/net_mgmt.h> #include <zephyr/net/net_mgmt.h>
#include <zephyr/net/dns_resolve.h> #include <zephyr/net/dns_resolve.h>
#include <zephyr/net/icmp.h> #include <zephyr/net/icmp.h>
#include <zephyr/net/ethernet.h>
#include "net_private.h" #include "net_private.h"
#include "connection.h" #include "connection.h"
#include "icmpv6.h" #include "icmpv6.h"
@ -805,6 +806,8 @@ enum net_verdict net_ipv6_prepare_for_send(struct net_pkt *pkt)
return NET_DROP; return NET_DROP;
} }
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_IPV6);
#if defined(CONFIG_NET_IPV6_FRAGMENT) #if defined(CONFIG_NET_IPV6_FRAGMENT)
/* If we have already fragmented the packet, the fragment id will /* If we have already fragmented the packet, the fragment id will
* contain a proper value and we can skip other checks. * contain a proper value and we can skip other checks.

View file

@ -2566,23 +2566,49 @@ skip_alloc:
if (net_context_get_proto(context) == IPPROTO_RAW) { if (net_context_get_proto(context) == IPPROTO_RAW) {
char type = (NET_IPV6_HDR(pkt)->vtc & 0xf0); char type = (NET_IPV6_HDR(pkt)->vtc & 0xf0);
struct sockaddr_ll *ll_addr;
/* Set the family to pkt if detected */ /* Set the family to pkt if detected */
switch (type) { switch (type) {
case 0x60: case 0x60:
net_pkt_set_family(pkt, AF_INET6); net_pkt_set_family(pkt, AF_INET6);
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_IPV6);
break; break;
case 0x40: case 0x40:
net_pkt_set_family(pkt, AF_INET); net_pkt_set_family(pkt, AF_INET);
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_IP);
break; break;
default: default:
/* Not IP traffic, let it go forward as it is */ /* Not IP traffic, let it go forward as it is */
ll_addr = (struct sockaddr_ll *)dst_addr;
net_pkt_set_ll_proto_type(pkt,
ntohs(ll_addr->sll_protocol));
break; break;
} }
/* Pass to L2: */ /* Pass to L2: */
ret = net_send_data(pkt); ret = net_send_data(pkt);
} else { } else {
struct sockaddr_ll_ptr *ll_src_addr;
struct sockaddr_ll *ll_dst_addr;
/* The destination address is set in remote for this
* socket type.
*/
ll_dst_addr = (struct sockaddr_ll *)&context->remote;
ll_src_addr = (struct sockaddr_ll_ptr *)&context->local;
net_pkt_lladdr_dst(pkt)->addr = ll_dst_addr->sll_addr;
net_pkt_lladdr_dst(pkt)->len =
sizeof(struct net_eth_addr);
net_pkt_lladdr_src(pkt)->addr = ll_src_addr->sll_addr;
net_pkt_lladdr_src(pkt)->len =
sizeof(struct net_eth_addr);
net_pkt_set_ll_proto_type(pkt,
ntohs(ll_dst_addr->sll_protocol));
net_if_queue_tx(net_pkt_iface(pkt), pkt); net_if_queue_tx(net_pkt_iface(pkt), pkt);
} }
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) && family == AF_CAN && } else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) && family == AF_CAN &&

View file

@ -270,6 +270,9 @@ static inline struct net_pkt *arp_prepare(struct net_if *iface,
return NULL; return NULL;
} }
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_ARP);
net_pkt_set_family(pkt, AF_INET);
/* Avoid recursive loop with network packet capturing */ /* Avoid recursive loop with network packet capturing */
if (IS_ENABLED(CONFIG_NET_CAPTURE) && pending) { if (IS_ENABLED(CONFIG_NET_CAPTURE) && pending) {
net_pkt_set_captured(pkt, net_pkt_is_captured(pending)); net_pkt_set_captured(pkt, net_pkt_is_captured(pending));
@ -498,6 +501,7 @@ static void arp_gratuitous_send(struct net_if *iface,
net_buf_add(pkt->buffer, sizeof(struct net_arp_hdr)); net_buf_add(pkt->buffer, sizeof(struct net_arp_hdr));
net_pkt_set_vlan_tag(pkt, net_eth_get_vlan_tag(iface)); net_pkt_set_vlan_tag(pkt, net_eth_get_vlan_tag(iface));
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_ARP);
hdr = NET_ARP_HDR(pkt); hdr = NET_ARP_HDR(pkt);
@ -751,6 +755,9 @@ static inline struct net_pkt *arp_prepare_reply(struct net_if *iface,
net_pkt_lladdr_dst(pkt)->addr = (uint8_t *)&hdr->dst_hwaddr.addr; net_pkt_lladdr_dst(pkt)->addr = (uint8_t *)&hdr->dst_hwaddr.addr;
net_pkt_lladdr_dst(pkt)->len = sizeof(struct net_eth_addr); net_pkt_lladdr_dst(pkt)->len = sizeof(struct net_eth_addr);
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_ARP);
net_pkt_set_family(pkt, AF_INET);
return pkt; return pkt;
} }

View file

@ -674,9 +674,9 @@ static int ethernet_send(struct net_if *iface, struct net_pkt *pkt)
{ {
const struct ethernet_api *api = net_if_get_device(iface)->api; const struct ethernet_api *api = net_if_get_device(iface)->api;
struct ethernet_context *ctx = net_if_l2_data(iface); struct ethernet_context *ctx = net_if_l2_data(iface);
uint16_t ptype = 0; uint16_t ptype = htons(net_pkt_ll_proto_type(pkt));
int ret;
struct net_pkt *orig_pkt = pkt; struct net_pkt *orig_pkt = pkt;
int ret;
if (!api) { if (!api) {
ret = -ENOENT; ret = -ENOENT;
@ -696,15 +696,12 @@ static int ethernet_send(struct net_if *iface, struct net_pkt *pkt)
goto send; goto send;
} }
if (IS_ENABLED(CONFIG_NET_IPV4) && if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) {
net_pkt_family(pkt) == AF_INET) { if (!net_pkt_ipv4_acd(pkt)) {
struct net_pkt *tmp; struct net_pkt *tmp;
if (net_pkt_ipv4_acd(pkt)) {
ptype = htons(NET_ETH_PTYPE_ARP);
} else {
tmp = ethernet_ll_prepare_on_ipv4(iface, pkt); tmp = ethernet_ll_prepare_on_ipv4(iface, pkt);
if (!tmp) { if (tmp == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto error; goto error;
} else if (IS_ENABLED(CONFIG_NET_ARP) && tmp != pkt) { } else if (IS_ENABLED(CONFIG_NET_ARP) && tmp != pkt) {
@ -712,49 +709,22 @@ static int ethernet_send(struct net_if *iface, struct net_pkt *pkt)
* by an ARP request packet. * by an ARP request packet.
*/ */
pkt = tmp; pkt = tmp;
ptype = htons(NET_ETH_PTYPE_ARP); ptype = htons(net_pkt_ll_proto_type(pkt));
net_pkt_set_family(pkt, AF_INET);
} else {
ptype = htons(NET_ETH_PTYPE_IP);
} }
} }
} else if (IS_ENABLED(CONFIG_NET_IPV6) &&
net_pkt_family(pkt) == AF_INET6) {
ptype = htons(NET_ETH_PTYPE_IPV6);
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) && } else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
net_pkt_family(pkt) == AF_PACKET) { net_pkt_family(pkt) == AF_PACKET) {
struct net_context *context = net_pkt_context(pkt); struct net_context *context = net_pkt_context(pkt);
if (context && net_context_get_type(context) == SOCK_DGRAM) { if (!(context && net_context_get_type(context) == SOCK_DGRAM)) {
struct sockaddr_ll *dst_addr; /* Raw packet, just send it */
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; goto send;
} }
} else if (IS_ENABLED(CONFIG_NET_L2_PTP) && net_pkt_is_ptp(pkt)) { }
ptype = htons(NET_ETH_PTYPE_PTP);
} else if (IS_ENABLED(CONFIG_NET_LLDP) && net_pkt_is_lldp(pkt)) { if (ptype == 0) {
ptype = htons(NET_ETH_PTYPE_LLDP); /* Caller of this function has not set the ptype */
} else if (IS_ENABLED(CONFIG_NET_ARP)) { NET_ERR("No protocol set for pkt %p", pkt);
/* Unknown type: Unqueued pkt is an ARP reply.
*/
ptype = htons(NET_ETH_PTYPE_ARP);
net_pkt_set_family(pkt, AF_INET);
} else {
ret = -ENOTSUP; ret = -ENOTSUP;
goto error; goto error;
} }

View file

@ -170,6 +170,7 @@ static struct net_pkt *setup_gptp_frame(struct net_if *iface,
net_buf_add(pkt->buffer, sizeof(struct gptp_hdr) + extra_header); net_buf_add(pkt->buffer, sizeof(struct gptp_hdr) + extra_header);
net_pkt_set_ptp(pkt, true); net_pkt_set_ptp(pkt, true);
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_PTP);
net_pkt_lladdr_src(pkt)->addr = net_if_get_link_addr(iface)->addr; net_pkt_lladdr_src(pkt)->addr = net_if_get_link_addr(iface)->addr;
net_pkt_lladdr_src(pkt)->len = net_if_get_link_addr(iface)->len; net_pkt_lladdr_src(pkt)->len = net_if_get_link_addr(iface)->len;

View file

@ -114,6 +114,7 @@ static int lldp_send(struct ethernet_lldp *lldp)
} }
net_pkt_set_lldp(pkt, true); net_pkt_set_lldp(pkt, true);
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_LLDP);
ret = net_pkt_write(pkt, (uint8_t *)lldp->lldpdu, ret = net_pkt_write(pkt, (uint8_t *)lldp->lldpdu,
sizeof(struct net_lldpdu)); sizeof(struct net_lldpdu));

View file

@ -215,6 +215,8 @@ static inline struct net_pkt *prepare_arp_reply(struct net_if *iface,
net_buf_add(pkt->buffer, sizeof(struct net_arp_hdr)); net_buf_add(pkt->buffer, sizeof(struct net_arp_hdr));
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_ARP);
return pkt; return pkt;
} }
@ -265,6 +267,8 @@ static inline struct net_pkt *prepare_arp_request(struct net_if *iface,
net_buf_add(pkt->buffer, sizeof(struct net_arp_hdr)); net_buf_add(pkt->buffer, sizeof(struct net_arp_hdr));
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_ARP);
return pkt; return pkt;
} }
@ -373,6 +377,8 @@ ZTEST(arp_fn_tests, test_arp)
net_ipv4_addr_copy_raw(ipv4->src, (uint8_t *)&src); net_ipv4_addr_copy_raw(ipv4->src, (uint8_t *)&src);
net_ipv4_addr_copy_raw(ipv4->dst, (uint8_t *)&dst); net_ipv4_addr_copy_raw(ipv4->dst, (uint8_t *)&dst);
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_IP);
memcpy(net_buf_add(pkt->buffer, len), app_data, len); memcpy(net_buf_add(pkt->buffer, len), app_data, len);
pkt2 = net_arp_prepare(pkt, &dst, NULL); pkt2 = net_arp_prepare(pkt, &dst, NULL);
@ -381,6 +387,9 @@ ZTEST(arp_fn_tests, test_arp)
* stored in ARP table. * stored in ARP table.
*/ */
zassert_equal(net_pkt_ll_proto_type(pkt2), NET_ETH_PTYPE_ARP,
"ARP packet type is wrong");
/**TESTPOINTS: Check packets*/ /**TESTPOINTS: Check packets*/
zassert_not_equal((void *)(pkt2), (void *)(pkt), zassert_not_equal((void *)(pkt2), (void *)(pkt),
/* The packets cannot be the same as the ARP cache has /* The packets cannot be the same as the ARP cache has
@ -530,6 +539,8 @@ ZTEST(arp_fn_tests, test_arp)
net_ipv4_addr_copy_raw(arp_hdr->dst_ipaddr, (uint8_t *)&dst); net_ipv4_addr_copy_raw(arp_hdr->dst_ipaddr, (uint8_t *)&dst);
net_ipv4_addr_copy_raw(arp_hdr->src_ipaddr, (uint8_t *)&src); net_ipv4_addr_copy_raw(arp_hdr->src_ipaddr, (uint8_t *)&src);
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_ARP);
pkt2 = prepare_arp_reply(iface, pkt, &eth_hwaddr, &eth_hdr); pkt2 = prepare_arp_reply(iface, pkt, &eth_hwaddr, &eth_hdr);
zassert_not_null(pkt2, "ARP reply generation failed."); zassert_not_null(pkt2, "ARP reply generation failed.");
@ -554,6 +565,9 @@ ZTEST(arp_fn_tests, test_arp)
net_pkt_unref(pkt); net_pkt_unref(pkt);
/* Clear the ARP cache so that old entries do not confuse the tests */
net_arp_clear_cache(iface);
/* Then feed in ARP request */ /* Then feed in ARP request */
pkt = net_pkt_alloc_with_buffer(iface, sizeof(struct net_eth_hdr) + pkt = net_pkt_alloc_with_buffer(iface, sizeof(struct net_eth_hdr) +
sizeof(struct net_arp_hdr), sizeof(struct net_arp_hdr),
@ -571,6 +585,8 @@ ZTEST(arp_fn_tests, test_arp)
net_ipv4_addr_copy_raw(arp_hdr->dst_ipaddr, (uint8_t *)&src); net_ipv4_addr_copy_raw(arp_hdr->dst_ipaddr, (uint8_t *)&src);
net_ipv4_addr_copy_raw(arp_hdr->src_ipaddr, (uint8_t *)&dst); net_ipv4_addr_copy_raw(arp_hdr->src_ipaddr, (uint8_t *)&dst);
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_ARP);
pkt2 = prepare_arp_request(iface, pkt, &eth_hwaddr, &eth_hdr); pkt2 = prepare_arp_request(iface, pkt, &eth_hwaddr, &eth_hdr);
/**TESTPOINT: Check if ARP request generation failed*/ /**TESTPOINT: Check if ARP request generation failed*/
@ -633,6 +649,8 @@ ZTEST(arp_fn_tests, test_arp)
net_buf_add(pkt->buffer, sizeof(struct net_arp_hdr)); net_buf_add(pkt->buffer, sizeof(struct net_arp_hdr));
net_pkt_set_ll_proto_type(pkt, NET_ETH_PTYPE_ARP);
verdict = net_arp_input(pkt, eth_hdr); verdict = net_arp_input(pkt, eth_hdr);
zassert_not_equal(verdict, NET_DROP, "Gratuitous ARP failed"); zassert_not_equal(verdict, NET_DROP, "Gratuitous ARP failed");