net: bridge: handle RX in bridge_input.c
Current bridge function is very simple which does forwarding for all
packets. There will be more and more features of bridge RX handling.
Let's move bridge RX handling to bridge_input.c for next IPv4/IPv6
protocols support for virtual bridge interface.
And currently there is no path to call bridge_iface_recv function.
Let's rework it for proper function returning NET_CONTINUE.
Also fixed another issue of link local address checking. Because
net_linkaddr structure changed. So fixed
is_link_local_addr((struct net_eth_addr *)net_pkt_lladdr_dst(pkt))
to
is_link_local_addr((struct net_eth_addr *)(net_pkt_lladdr_dst(pkt)->addr))
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
diff --git a/include/zephyr/net/ethernet_bridge.h b/include/zephyr/net/ethernet_bridge.h
index 2afae63..a49236a 100644
--- a/include/zephyr/net/ethernet_bridge.h
+++ b/include/zephyr/net/ethernet_bridge.h
@@ -9,6 +9,7 @@
/*
* Copyright (c) 2021 BayLibre SAS
* Copyright (c) 2024 Nordic Semiconductor
+ * SPDX-FileCopyrightText: Copyright 2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -178,6 +179,16 @@
}
/**
+ * @brief Process pkt received on bridged interface.
+ *
+ * @param iface Pointer to bridged iface
+ * @param pkt Pointer to pkt
+ *
+ * @return net_verdict.
+ */
+enum net_verdict eth_bridge_input_process(struct net_if *iface, struct net_pkt *pkt);
+
+/**
* @}
*/
diff --git a/subsys/net/l2/ethernet/bridge/CMakeLists.txt b/subsys/net/l2/ethernet/bridge/CMakeLists.txt
index b3567e4..e5d9aef 100644
--- a/subsys/net/l2/ethernet/bridge/CMakeLists.txt
+++ b/subsys/net/l2/ethernet/bridge/CMakeLists.txt
@@ -4,4 +4,5 @@
zephyr_library_include_directories(. ${ZEPHYR_BASE}/subsys/net/ip)
zephyr_library_sources(bridge.c)
+zephyr_library_sources(bridge_input.c)
zephyr_library_sources_ifdef(CONFIG_NET_ETHERNET_BRIDGE_SHELL bridge_shell.c)
diff --git a/subsys/net/l2/ethernet/bridge/bridge.c b/subsys/net/l2/ethernet/bridge/bridge.c
index 68384b6..db33769 100644
--- a/subsys/net/l2/ethernet/bridge/bridge.c
+++ b/subsys/net/l2/ethernet/bridge/bridge.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2021 BayLibre SAS
* Copyright (c) 2024 Nordic Semiconductor
+ * SPDX-FileCopyrightText: Copyright 2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -234,20 +235,6 @@
return 0;
}
-static inline bool is_link_local_addr(struct net_eth_addr *addr)
-{
- if (addr->addr[0] == 0x01 &&
- addr->addr[1] == 0x80 &&
- addr->addr[2] == 0xc2 &&
- addr->addr[3] == 0x00 &&
- addr->addr[4] == 0x00 &&
- (addr->addr[5] & 0x0f) == 0x00) {
- return true;
- }
-
- return false;
-}
-
static void random_linkaddr(uint8_t *linkaddr, size_t len)
{
sys_rand_get(linkaddr, len);
@@ -350,22 +337,18 @@
return 0;
}
-static enum net_verdict bridge_iface_process(struct net_if *iface,
- struct net_pkt *pkt,
- bool is_send)
+/*
+ * For direct TX, send pkt to all ifaces.
+ * For forward TX (pkt from an original iface), send to all other ifaces.
+ */
+static enum net_verdict bridge_iface_send_process(struct net_if *iface,
+ struct net_pkt *pkt)
{
struct eth_bridge_iface_context *ctx = net_if_get_device(iface)->data;
struct net_if *orig_iface;
struct net_pkt *send_pkt = pkt;
int fwd_iface_num = 0;
- /* Drop all link-local packets for now. */
- if (is_link_local_addr((struct net_eth_addr *)net_pkt_lladdr_dst(pkt))) {
- NET_DBG("DROP: lladdr");
- net_pkt_unref(pkt);
- return NET_OK;
- }
-
lock_bridge(ctx);
orig_iface = net_pkt_orig_iface(pkt);
@@ -404,8 +387,7 @@
net_pkt_set_iface(send_pkt, ctx->eth_iface[i]);
net_if_queue_tx(ctx->eth_iface[i], send_pkt);
- NET_DBG("%s iface %d pkt %p (ref %d)",
- is_send ? "Send" : "Recv",
+ NET_DBG("Send iface %d pkt %p (ref %d)",
net_if_get_by_iface(ctx->eth_iface[i]),
send_pkt, (int)atomic_get(&send_pkt->atomic_ref));
}
@@ -432,24 +414,28 @@
net_pkt_hexdump(pkt, str);
}
- (void)bridge_iface_process(iface, pkt, true);
+ (void)bridge_iface_send_process(iface, pkt);
return 0;
}
-static enum net_verdict bridge_iface_recv(struct net_if *iface,
- struct net_pkt *pkt)
+static enum net_verdict bridge_iface_recv(struct net_if *iface, struct net_pkt *pkt)
{
+ struct eth_bridge_iface_context *ctx = net_if_get_device(iface)->data;
+
if (DEBUG_RX) {
- char str[sizeof("RX iface xx")];
+ char str[sizeof("RX bridge xx")];
- snprintk(str, sizeof(str), "RX iface %d",
- net_if_get_by_iface(net_pkt_iface(pkt)));
-
+ snprintk(str, sizeof(str), "RX bridge %d", net_if_get_by_iface(iface));
net_pkt_hexdump(pkt, str);
}
- return bridge_iface_process(iface, pkt, false);
+ if (!ctx->status) {
+ NET_DBG("Bridge interface %d not active", net_if_get_by_iface(iface));
+ return NET_DROP;
+ }
+
+ return NET_CONTINUE;
}
/* We cannot attach the bridge interface to Ethernet interface because
diff --git a/subsys/net/l2/ethernet/bridge/bridge_input.c b/subsys/net/l2/ethernet/bridge/bridge_input.c
new file mode 100644
index 0000000..6e1956f
--- /dev/null
+++ b/subsys/net/l2/ethernet/bridge/bridge_input.c
@@ -0,0 +1,65 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2025 NXP
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(net_eth_bridge_input, CONFIG_NET_ETHERNET_BRIDGE_LOG_LEVEL);
+
+#include <zephyr/net/ethernet_bridge.h>
+
+static int eth_bridge_forward(struct net_if *bridge, struct net_if *orig_iface, struct net_pkt *pkt)
+{
+ struct net_pkt *out_pkt;
+
+ out_pkt = net_pkt_clone(pkt, K_NO_WAIT);
+ if (out_pkt == NULL) {
+ return -ENOMEM;
+ }
+
+ net_pkt_set_l2_bridged(out_pkt, true);
+ net_pkt_set_iface(out_pkt, bridge);
+ net_pkt_set_orig_iface(out_pkt, orig_iface);
+
+ net_if_queue_tx(bridge, out_pkt);
+
+ NET_DBG("Passing rx pkt %p (orig %p) to bridge %d tx path from %d",
+ out_pkt, pkt, net_if_get_by_iface(bridge),
+ net_if_get_by_iface(orig_iface));
+
+ return 0;
+}
+
+static inline bool is_link_local_addr(struct net_eth_addr *addr)
+{
+ if (addr->addr[0] == 0x01 &&
+ addr->addr[1] == 0x80 &&
+ addr->addr[2] == 0xc2 &&
+ addr->addr[3] == 0x00 &&
+ addr->addr[4] == 0x00 &&
+ (addr->addr[5] & 0x0f) == 0x00) {
+ return true;
+ }
+
+ return false;
+}
+
+enum net_verdict eth_bridge_input_process(struct net_if *iface, struct net_pkt *pkt)
+{
+ struct ethernet_context *ctx = net_if_l2_data(iface);
+ struct net_if *bridge = net_eth_get_bridge(ctx);
+ struct net_eth_addr *dst_addr = (struct net_eth_addr *)(net_pkt_lladdr_dst(pkt)->addr);
+
+ /* Drop all link-local packets for now. */
+ if (is_link_local_addr(dst_addr)) {
+ NET_DBG("DROP: lladdr");
+ return NET_DROP;
+ }
+
+ if (eth_bridge_forward(bridge, iface, pkt) != 0) {
+ return NET_DROP;
+ }
+
+ return NET_CONTINUE;
+}
diff --git a/subsys/net/l2/ethernet/ethernet.c b/subsys/net/l2/ethernet/ethernet.c
index 6302bfa..a54ceca 100644
--- a/subsys/net/l2/ethernet/ethernet.c
+++ b/subsys/net/l2/ethernet/ethernet.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2016-2018 Intel Corporation.
+ * SPDX-FileCopyrightText: Copyright 2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -276,25 +277,18 @@
goto drop;
}
- if (IS_ENABLED(CONFIG_NET_ETHERNET_BRIDGE) &&
- net_eth_iface_is_bridged(ctx) && !net_pkt_is_l2_bridged(pkt)) {
- struct net_if *bridge = net_eth_get_bridge(ctx);
- struct net_pkt *out_pkt;
+ /* Set the pointers to ll src and dst addresses */
+ (void)net_linkaddr_create(net_pkt_lladdr_src(pkt), hdr->src.addr,
+ sizeof(struct net_eth_addr), NET_LINK_ETHERNET);
- out_pkt = net_pkt_clone(pkt, K_NO_WAIT);
- if (out_pkt == NULL) {
+ (void)net_linkaddr_create(net_pkt_lladdr_dst(pkt), hdr->dst.addr,
+ sizeof(struct net_eth_addr), NET_LINK_ETHERNET);
+
+ if (IS_ENABLED(CONFIG_NET_ETHERNET_BRIDGE) && net_eth_iface_is_bridged(ctx)) {
+ verdict = eth_bridge_input_process(iface, pkt);
+ if (verdict == NET_DROP) {
goto drop;
}
-
- net_pkt_set_l2_bridged(out_pkt, true);
- net_pkt_set_iface(out_pkt, bridge);
- net_pkt_set_orig_iface(out_pkt, iface);
-
- NET_DBG("Passing pkt %p (orig %p) to bridge %d from %d",
- out_pkt, pkt, net_if_get_by_iface(bridge),
- net_if_get_by_iface(iface));
-
- (void)net_if_queue_tx(bridge, out_pkt);
}
type = net_ntohs(hdr->type);
@@ -343,13 +337,6 @@
}
}
- /* Set the pointers to ll src and dst addresses */
- (void)net_linkaddr_create(net_pkt_lladdr_src(pkt), hdr->src.addr,
- sizeof(struct net_eth_addr), NET_LINK_ETHERNET);
-
- (void)net_linkaddr_create(net_pkt_lladdr_dst(pkt), hdr->dst.addr,
- sizeof(struct net_eth_addr), NET_LINK_ETHERNET);
-
lladdr = net_pkt_lladdr_dst(pkt);
net_pkt_set_ll_proto_type(pkt, type);