Skip to content

Commit e658bc1

Browse files
jukkarkartben
authored andcommitted
net: Extend the protocol handling in Ethernet
Allow user to specify protocol extensions when receiving data from Ethernet network. This means that user can register L3 protocol handler using NET_L3_REGISTER() with the desired protocol type. Ethernet code will then call the handler if such a protocol type packet is received. This is currently only implemented for Ethernet. The original IPv4 and IPv6 handling is left intact even if they can be considered to be L3 layer protocol. This could be changed in the future if needed so that IPv4 and IPv6 handling could be made pluggable protocols. Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
1 parent b6ca9db commit e658bc1

File tree

12 files changed

+199
-78
lines changed

12 files changed

+199
-78
lines changed

cmake/linker_script/common/common-rom.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ zephyr_linker_section_configure(
9191
KEEP SORT NAME
9292
)
9393

94+
if(CONFIG_NETWORKING)
95+
zephyr_iterable_section(NAME net_l3_register KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN ${CONFIG_LINKER_ITERABLE_SUBALIGN})
96+
endif()
97+
9498
if(CONFIG_NET_SOCKETS)
9599
zephyr_iterable_section(NAME net_socket_register KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN ${CONFIG_LINKER_ITERABLE_SUBALIGN})
96100
endif()

include/zephyr/linker/common-rom/common-rom-net.ld

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
#include <zephyr/linker/iterable_sections.h>
44

5+
#if defined(CONFIG_NETWORKING)
6+
ITERABLE_SECTION_ROM(net_l3_register, Z_LINK_ITERABLE_SUBALIGN)
7+
#endif
8+
59
#if defined(CONFIG_NET_SOCKETS)
610
ITERABLE_SECTION_ROM(net_socket_register, Z_LINK_ITERABLE_SUBALIGN)
711
#endif

include/zephyr/net/ethernet.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,16 @@ static inline bool net_eth_is_vlan_interface(struct net_if *iface)
12611261
#define ETH_NET_DEVICE_DT_INST_DEFINE(inst, ...) \
12621262
ETH_NET_DEVICE_DT_DEFINE(DT_DRV_INST(inst), __VA_ARGS__)
12631263

1264+
/**
1265+
* @brief Ethernet L3 protocol register macro.
1266+
*
1267+
* @param name Name of the L3 protocol.
1268+
* @param ptype Ethernet protocol type.
1269+
* @param handler Handler function for this protocol type.
1270+
*/
1271+
#define ETH_NET_L3_REGISTER(name, ptype, handler) \
1272+
NET_L3_REGISTER(&NET_L2_GET_NAME(ETHERNET), name, ptype, handler)
1273+
12641274
/**
12651275
* @brief Inform ethernet L2 driver that ethernet carrier is detected.
12661276
* This happens when cable is connected.

include/zephyr/net/lldp.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -225,16 +225,6 @@ typedef enum net_verdict (*net_lldp_recv_cb_t)(struct net_if *iface,
225225
*/
226226
int net_lldp_register_callback(struct net_if *iface, net_lldp_recv_cb_t cb);
227227

228-
/**
229-
* @brief Parse LLDP packet
230-
*
231-
* @param iface Network interface
232-
* @param pkt Network packet
233-
*
234-
* @return Return the policy for network buffer
235-
*/
236-
enum net_verdict net_lldp_recv(struct net_if *iface, struct net_pkt *pkt);
237-
238228
/**
239229
* @brief Set LLDP protocol data unit (LLDPDU) for the network interface.
240230
*

include/zephyr/net/net_core.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <zephyr/kernel.h>
2222

2323
#include <zephyr/net/net_timeout.h>
24+
#include <zephyr/net/net_linkaddr.h>
2425

2526
#ifdef __cplusplus
2627
extern "C" {
@@ -154,6 +155,40 @@ int net_send_data(struct net_pkt *pkt);
154155
#define NET_TC_COUNT 0
155156
#endif /* CONFIG_NET_TC_TX_COUNT && CONFIG_NET_TC_RX_COUNT */
156157

158+
/**
159+
* @brief Registration information for a given L3 handler. Note that
160+
* the layer number (L3) just refers to something that is on top
161+
* of L2. So for example IPv6 is L3 and IPv4 is L3, but Ethernet
162+
* based LLDP, gPTP are more in the layer 2.5 but we consider them
163+
* as L3 here for simplicity.
164+
*/
165+
struct net_l3_register {
166+
/** Store also the name of the L3 type in order to be able to
167+
* print it later.
168+
*/
169+
const char * const name;
170+
/** What L2 layer this is for */
171+
const struct net_l2 * const l2;
172+
/** Handler function for the given protocol type */
173+
enum net_verdict (*handler)(struct net_if *iface,
174+
uint16_t ptype,
175+
struct net_pkt *pkt);
176+
/** Protocol type */
177+
uint16_t ptype;
178+
};
179+
180+
#define NET_L3_GET_NAME(l3_name, ptype) __net_l3_register_##l3_name##_##ptype
181+
182+
#define NET_L3_REGISTER(_l2_type, _name, _ptype, _handler) \
183+
static const STRUCT_SECTION_ITERABLE(net_l3_register, \
184+
NET_L3_GET_NAME(_name, _ptype)) = { \
185+
.ptype = _ptype, \
186+
.handler = _handler, \
187+
.name = STRINGIFY(_name), \
188+
.l2 = _l2_type, \
189+
}; \
190+
BUILD_ASSERT((_handler) != NULL, "Handler is not defined")
191+
157192
/* @endcond */
158193

159194
/**

modules/hostap/src/supp_main.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,3 +1219,16 @@ static int init(void)
12191219
}
12201220

12211221
SYS_INIT(init, APPLICATION, 0);
1222+
1223+
static enum net_verdict eapol_recv(struct net_if *iface, uint16_t ptype,
1224+
struct net_pkt *pkt)
1225+
{
1226+
ARG_UNUSED(iface);
1227+
ARG_UNUSED(ptype);
1228+
1229+
net_pkt_set_family(pkt, AF_UNSPEC);
1230+
1231+
return NET_CONTINUE;
1232+
}
1233+
1234+
ETH_NET_L3_REGISTER(EAPOL, NET_ETH_PTYPE_EAPOL, eapol_recv);

subsys/net/ip/net_private.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -239,18 +239,8 @@ void net_if_ipv6_start_dad(struct net_if *iface,
239239
* @brief Initialize Precision Time Protocol Layer.
240240
*/
241241
void net_gptp_init(void);
242-
243-
/**
244-
* @brief Process a ptp message.
245-
*
246-
* @param buf Buffer with a valid PTP Ethernet type.
247-
*
248-
* @return Return the policy for network buffer.
249-
*/
250-
enum net_verdict net_gptp_recv(struct net_if *iface, struct net_pkt *pkt);
251242
#else
252243
#define net_gptp_init()
253-
#define net_gptp_recv(iface, pkt) NET_DROP
254244
#endif /* CONFIG_NET_GPTP */
255245

256246
#if defined(CONFIG_NET_IPV4_FRAGMENT)

subsys/net/l2/ethernet/arp.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ LOG_MODULE_REGISTER(net_arp, CONFIG_NET_ARP_LOG_LEVEL);
1919
#include <zephyr/net/net_mgmt.h>
2020

2121
#include "arp.h"
22+
#include "ipv4.h"
2223
#include "net_private.h"
2324

2425
#define NET_BUF_TIMEOUT K_MSEC(100)
@@ -1013,3 +1014,28 @@ void net_arp_init(void)
10131014
K_SECONDS(CONFIG_NET_ARP_GRATUITOUS_INTERVAL));
10141015
#endif /* defined(CONFIG_NET_ARP_GRATUITOUS_TRANSMISSION) */
10151016
}
1017+
1018+
static enum net_verdict arp_recv(struct net_if *iface,
1019+
uint16_t ptype,
1020+
struct net_pkt *pkt)
1021+
{
1022+
struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
1023+
1024+
ARG_UNUSED(iface);
1025+
ARG_UNUSED(ptype);
1026+
1027+
net_pkt_set_family(pkt, AF_INET);
1028+
1029+
NET_DBG("ARP packet from %s received",
1030+
net_sprint_ll_addr((uint8_t *)hdr->src.addr,
1031+
sizeof(struct net_eth_addr)));
1032+
1033+
if (IS_ENABLED(CONFIG_NET_IPV4_ACD) &&
1034+
net_ipv4_acd_input(iface, pkt) == NET_DROP) {
1035+
return NET_DROP;
1036+
}
1037+
1038+
return net_arp_input(pkt, hdr);
1039+
}
1040+
1041+
ETH_NET_L3_REGISTER(ARP, NET_ETH_PTYPE_ARP, arp_recv);

subsys/net/l2/ethernet/ethernet.c

Lines changed: 71 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -236,11 +236,13 @@ static enum net_verdict ethernet_recv(struct net_if *iface,
236236
struct net_pkt *pkt)
237237
{
238238
struct ethernet_context *ctx = net_if_l2_data(iface);
239-
struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
240239
uint8_t hdr_len = sizeof(struct net_eth_hdr);
241-
uint16_t type;
242-
struct net_linkaddr *lladdr;
240+
struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
241+
enum net_verdict verdict = NET_CONTINUE;
243242
bool is_vlan_pkt = false;
243+
bool handled = false;
244+
struct net_linkaddr *lladdr;
245+
uint16_t type;
244246

245247
/* This expects that the Ethernet header is in the first net_buf
246248
* fragment. This is a safe expectation here as it would not make
@@ -279,7 +281,6 @@ static enum net_verdict ethernet_recv(struct net_if *iface,
279281
!eth_is_vlan_tag_stripped(iface)) {
280282
struct net_eth_vlan_hdr *hdr_vlan =
281283
(struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt);
282-
enum net_verdict verdict;
283284

284285
net_pkt_set_vlan_tci(pkt, ntohs(hdr_vlan->vlan.tci));
285286
type = ntohs(hdr_vlan->type);
@@ -310,39 +311,6 @@ static enum net_verdict ethernet_recv(struct net_if *iface,
310311
}
311312
}
312313

313-
switch (type) {
314-
case NET_ETH_PTYPE_IP:
315-
case NET_ETH_PTYPE_ARP:
316-
net_pkt_set_family(pkt, AF_INET);
317-
break;
318-
case NET_ETH_PTYPE_IPV6:
319-
net_pkt_set_family(pkt, AF_INET6);
320-
break;
321-
case NET_ETH_PTYPE_EAPOL:
322-
break;
323-
#if defined(CONFIG_NET_L2_PTP)
324-
case NET_ETH_PTYPE_PTP:
325-
break;
326-
#endif
327-
case NET_ETH_PTYPE_LLDP:
328-
#if defined(CONFIG_NET_LLDP)
329-
net_buf_pull(pkt->frags, hdr_len);
330-
return net_lldp_recv(iface, pkt);
331-
#else
332-
NET_DBG("LLDP Rx agent not enabled");
333-
goto drop;
334-
#endif
335-
default:
336-
if (IS_ENABLED(CONFIG_NET_ETHERNET_FORWARD_UNRECOGNISED_ETHERTYPE)) {
337-
break;
338-
}
339-
340-
NET_DBG("Unknown hdr type 0x%04x iface %d (%p)", type,
341-
net_if_get_by_iface(iface), iface);
342-
eth_stats_update_unknown_protocol(iface);
343-
return NET_DROP;
344-
}
345-
346314
/* Set the pointers to ll src and dst addresses */
347315
lladdr = net_pkt_lladdr_src(pkt);
348316
lladdr->addr = hdr->src.addr;
@@ -370,9 +338,7 @@ static enum net_verdict ethernet_recv(struct net_if *iface,
370338

371339
if (!net_eth_is_addr_broadcast((struct net_eth_addr *)lladdr->addr) &&
372340
!net_eth_is_addr_multicast((struct net_eth_addr *)lladdr->addr) &&
373-
!net_eth_is_addr_lldp_multicast(
374-
(struct net_eth_addr *)lladdr->addr) &&
375-
!net_eth_is_addr_ptp_multicast((struct net_eth_addr *)lladdr->addr) &&
341+
!net_eth_is_addr_group((struct net_eth_addr *)lladdr->addr) &&
376342
!net_linkaddr_cmp(net_if_get_link_addr(iface), lladdr)) {
377343
/* The ethernet frame is not for me as the link addresses
378344
* are different.
@@ -383,43 +349,92 @@ static enum net_verdict ethernet_recv(struct net_if *iface,
383349
goto drop;
384350
}
385351

352+
/* Get rid of the Ethernet header. */
386353
net_buf_pull(pkt->frags, hdr_len);
387354

388-
if (IS_ENABLED(CONFIG_NET_IPV4) && type == NET_ETH_PTYPE_IP &&
389-
ethernet_check_ipv4_bcast_addr(pkt, hdr) == NET_DROP) {
390-
goto drop;
391-
}
355+
STRUCT_SECTION_FOREACH(net_l3_register, l3) {
356+
if (l3->ptype != type || l3->l2 != &NET_L2_GET_NAME(ETHERNET)) {
357+
continue;
358+
}
392359

393-
ethernet_update_rx_stats(iface, hdr, net_pkt_get_len(pkt) + hdr_len);
360+
NET_DBG("Calling L3 %s handler for type 0x%04x iface %d (%p)",
361+
l3->name, type, net_if_get_by_iface(iface), iface);
394362

395-
if (IS_ENABLED(CONFIG_NET_ARP) && type == NET_ETH_PTYPE_ARP) {
396-
NET_DBG("ARP packet from %s received",
397-
net_sprint_ll_addr((uint8_t *)hdr->src.addr,
398-
sizeof(struct net_eth_addr)));
363+
verdict = l3->handler(iface, type, pkt);
364+
if (verdict == NET_DROP) {
365+
NET_DBG("Dropping frame, packet rejected by %s", l3->name);
366+
goto drop;
367+
}
399368

400-
if (IS_ENABLED(CONFIG_NET_IPV4_ACD) &&
401-
net_ipv4_acd_input(iface, pkt) == NET_DROP) {
369+
handled = true;
370+
break;
371+
}
372+
373+
if (!handled) {
374+
if (IS_ENABLED(CONFIG_NET_ETHERNET_FORWARD_UNRECOGNISED_ETHERTYPE)) {
375+
net_pkt_set_family(pkt, AF_UNSPEC);
376+
} else {
377+
NET_DBG("Unknown hdr type 0x%04x iface %d (%p)", type,
378+
net_if_get_by_iface(iface), iface);
379+
eth_stats_update_unknown_protocol(iface);
402380
return NET_DROP;
403381
}
404-
405-
return net_arp_input(pkt, hdr);
406382
}
407383

408-
if (IS_ENABLED(CONFIG_NET_GPTP) && type == NET_ETH_PTYPE_PTP) {
409-
return net_gptp_recv(iface, pkt);
384+
/* FIXME: ARP eats the packet and the pkt is no longer a valid one,
385+
* so we cannot update the stats here. Fix the code to be more generic
386+
* so that we do not need this check.
387+
*/
388+
if (type == NET_ETH_PTYPE_ARP) {
389+
return verdict;
410390
}
411391

392+
ethernet_update_rx_stats(iface, hdr, net_pkt_get_len(pkt) + hdr_len);
393+
412394
if (type != NET_ETH_PTYPE_EAPOL) {
413395
ethernet_update_length(iface, pkt);
414396
}
415397

416-
return NET_CONTINUE;
398+
return verdict;
417399
drop:
418400
eth_stats_update_errors_rx(iface);
419401
return NET_DROP;
420402
}
421403

404+
#if defined(CONFIG_NET_IPV4) || defined(CONFIG_NET_IPV6)
405+
static enum net_verdict ethernet_ip_recv(struct net_if *iface,
406+
uint16_t ptype,
407+
struct net_pkt *pkt)
408+
{
409+
ARG_UNUSED(iface);
410+
411+
if (ptype == NET_ETH_PTYPE_IP) {
412+
struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
413+
414+
if (ethernet_check_ipv4_bcast_addr(pkt, hdr) == NET_DROP) {
415+
return NET_DROP;
416+
}
417+
418+
net_pkt_set_family(pkt, AF_INET);
419+
} else if (ptype == NET_ETH_PTYPE_IPV6) {
420+
net_pkt_set_family(pkt, AF_INET6);
421+
} else {
422+
return NET_DROP;
423+
}
424+
425+
return NET_CONTINUE;
426+
}
427+
#endif /* CONFIG_NET_IPV4 || CONFIG_NET_IPV6 */
428+
422429
#ifdef CONFIG_NET_IPV4
430+
ETH_NET_L3_REGISTER(IPv4, NET_ETH_PTYPE_IP, ethernet_ip_recv);
431+
#endif
432+
433+
#if defined(CONFIG_NET_IPV6)
434+
ETH_NET_L3_REGISTER(IPv6, NET_ETH_PTYPE_IPV6, ethernet_ip_recv);
435+
#endif /* CONFIG_NET_IPV6 */
436+
437+
#if defined(CONFIG_NET_IPV4)
423438
static inline bool ethernet_ipv4_dst_is_broadcast_or_mcast(struct net_pkt *pkt)
424439
{
425440
if (net_ipv4_is_addr_bcast(net_pkt_iface(pkt),

subsys/net/l2/ethernet/gptp/gptp.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,10 +320,20 @@ static void gptp_handle_msg(struct net_pkt *pkt)
320320
}
321321
}
322322

323-
enum net_verdict net_gptp_recv(struct net_if *iface, struct net_pkt *pkt)
323+
static enum net_verdict net_gptp_recv(struct net_if *iface, uint16_t ptype,
324+
struct net_pkt *pkt)
324325
{
325326
struct gptp_hdr *hdr = GPTP_HDR(pkt);
326327

328+
ARG_UNUSED(ptype);
329+
330+
if (!(net_eth_is_addr_ptp_multicast(
331+
(struct net_eth_addr *)net_pkt_lladdr_dst(pkt)->addr) ||
332+
net_eth_is_addr_lldp_multicast(
333+
(struct net_eth_addr *)net_pkt_lladdr_dst(pkt)->addr))) {
334+
return NET_DROP;
335+
}
336+
327337
if ((hdr->ptp_version != GPTP_VERSION) ||
328338
(hdr->transport_specific != GPTP_TRANSPORT_802_1_AS)) {
329339
/* The stack only supports PTP V2 and transportSpecific set
@@ -346,6 +356,8 @@ enum net_verdict net_gptp_recv(struct net_if *iface, struct net_pkt *pkt)
346356
return NET_DROP;
347357
}
348358

359+
ETH_NET_L3_REGISTER(gPTP, NET_ETH_PTYPE_PTP, net_gptp_recv);
360+
349361
static void gptp_init_clock_ds(void)
350362
{
351363
struct gptp_global_ds *global_ds;

0 commit comments

Comments
 (0)