Skip to content

net: connection: Unconditionally forward packets when handling packet sockets #93246

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions include/zephyr/net/net_pkt.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ struct net_pkt {
uint8_t chksum_done : 1; /* Checksum has already been computed for
* the packet.
*/
uint8_t loopback : 1; /* Packet is a loop back packet. */
#if defined(CONFIG_NET_IP_FRAGMENT)
uint8_t ip_reassembled : 1; /* Packet is a reassembled IP packet. */
#endif
Expand Down Expand Up @@ -1020,6 +1021,17 @@ static inline void net_pkt_set_ipv6_fragment_id(struct net_pkt *pkt,
}
#endif /* CONFIG_NET_IPV6_FRAGMENT */

static inline bool net_pkt_is_loopback(struct net_pkt *pkt)
{
return !!(pkt->loopback);
}

static inline void net_pkt_set_loopback(struct net_pkt *pkt,
bool loopback)
{
pkt->loopback = loopback;
}

#if defined(CONFIG_NET_IP_FRAGMENT)
static inline bool net_pkt_is_ip_reassembled(struct net_pkt *pkt)
{
Expand Down
49 changes: 11 additions & 38 deletions subsys/net/ip/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -637,16 +637,14 @@ static void conn_raw_socket_deliver(struct net_pkt *pkt, struct net_conn *conn,
#endif /* defined(CONFIG_NET_SOCKETS_PACKET) || defined(CONFIG_NET_SOCKETS_INET_RAW) */

#if defined(CONFIG_NET_SOCKETS_PACKET)
enum net_verdict net_conn_packet_input(struct net_pkt *pkt, uint16_t proto)
void net_conn_packet_input(struct net_pkt *pkt, uint16_t proto, enum net_sock_type type)
{
bool raw_sock_found = false;
bool raw_pkt_continue = false;
struct sockaddr_ll *local;
struct net_conn *conn;

/* Only accept input with AF_PACKET family. */
if (net_pkt_family(pkt) != AF_PACKET) {
return NET_CONTINUE;
return;
}

NET_DBG("Check proto 0x%04x listener for pkt %p family %d",
Expand All @@ -666,33 +664,22 @@ enum net_verdict net_conn_packet_input(struct net_pkt *pkt, uint16_t proto)
* in this packet.
*/
if (conn->family != AF_PACKET) {
raw_pkt_continue = true;
continue; /* wrong family */
}

if (conn->type == SOCK_DGRAM && !net_pkt_is_l2_processed(pkt)) {
/* If DGRAM packet sockets are present, we shall continue
* with this packet regardless the result.
*/
raw_pkt_continue = true;
continue; /* L2 not processed yet */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need to continue here (skip this "connection") if the condition is satisfied? We don't want to report raw packets to datagram packet sockets.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

}

if (conn->type == SOCK_RAW && net_pkt_is_l2_processed(pkt)) {
continue; /* L2 already processed */
if (conn->type != type) {
continue;
}

if (conn->proto == 0) {
continue; /* Local proto 0 doesn't forward any packets */
}

if (conn->proto != proto) {
/* Allow proto mismatch if socket was created with ETH_P_ALL, or it's raw
* packet socket input (proto ETH_P_ALL).
*/
if (conn->proto != ETH_P_ALL && proto != ETH_P_ALL) {
continue; /* wrong protocol */
}
/* Allow proto mismatch if socket was created with ETH_P_ALL, or it's raw
* packet socket input.
*/
if (conn->proto != proto && conn->proto != ETH_P_ALL && type != SOCK_RAW) {
continue; /* wrong protocol */
}

/* Apply protocol-specific matching criteria... */
Expand All @@ -708,31 +695,17 @@ enum net_verdict net_conn_packet_input(struct net_pkt *pkt, uint16_t proto)

conn_raw_socket_deliver(pkt, conn, false);

raw_sock_found = true;
}

k_mutex_unlock(&conn_lock);

if (!raw_pkt_continue && raw_sock_found) {
/* As one or more raw socket packets have already been delivered
* in the loop above, report NET_OK.
*/
net_pkt_unref(pkt);
return NET_OK;
}

/* When there is open connection different than AF_PACKET this
* packet shall be also handled in the upper net stack layers.
*/
return NET_CONTINUE;
}
#else
enum net_verdict net_conn_packet_input(struct net_pkt *pkt, uint16_t proto)
void net_conn_packet_input(struct net_pkt *pkt, uint16_t proto, enum net_sock_type type)
{
ARG_UNUSED(pkt);
ARG_UNUSED(proto);

return NET_CONTINUE;
ARG_UNUSED(type);
}
#endif /* defined(CONFIG_NET_SOCKETS_PACKET) */

Expand Down
7 changes: 4 additions & 3 deletions subsys/net/ip/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,12 @@ int net_conn_update(struct net_conn_handle *handle,
*
* @param pkt Network packet holding received data
* @param proto LL protocol for the connection
* @param type socket type
*
* @return NET_OK if the packet was consumed, NET_CONTINUE if the packet should
* be processed further in the stack.
*/
enum net_verdict net_conn_packet_input(struct net_pkt *pkt, uint16_t proto);
void net_conn_packet_input(struct net_pkt *pkt,
uint16_t proto,
enum net_sock_type type);

/**
* @brief Called by net_core.c when an IP packet is received
Expand Down
4 changes: 2 additions & 2 deletions subsys/net/ip/ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ int net_ipv4_parse_hdr_options(struct net_pkt *pkt,
}
#endif

enum net_verdict net_ipv4_input(struct net_pkt *pkt, bool is_loopback)
enum net_verdict net_ipv4_input(struct net_pkt *pkt)
{
NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr);
NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr);
Expand Down Expand Up @@ -301,7 +301,7 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt, bool is_loopback)
net_pkt_update_length(pkt, pkt_len);
}

if (!is_loopback) {
if (!net_pkt_is_loopback(pkt)) {
if (net_ipv4_is_addr_loopback_raw(hdr->dst) ||
net_ipv4_is_addr_loopback_raw(hdr->src)) {
NET_DBG("DROP: localhost packet");
Expand Down
4 changes: 2 additions & 2 deletions subsys/net/ip/ipv4_fragment.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,9 @@ static void reassemble_packet(struct net_ipv4_reassembly *reass)
/* We need to use the queue when feeding the packet back into the
* IP stack as we might run out of stack if we call processing_data()
* directly. As the packet does not contain link layer header, we
* MUST NOT pass it to L2 so there will be a special check for that
* in process_data() when handling the packet.
* MUST NOT pass it to L2 so mark it as l2_processed.
*/
net_pkt_set_l2_processed(pkt, true);
if (net_recv_data(net_pkt_iface(pkt), pkt) >= 0) {
return;
}
Expand Down
6 changes: 3 additions & 3 deletions subsys/net/ip/ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ static inline bool is_src_non_tentative_itself(const uint8_t *src)
return false;
}

enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback)
enum net_verdict net_ipv6_input(struct net_pkt *pkt)
{
NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv6_access, struct net_ipv6_hdr);
NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr);
Expand Down Expand Up @@ -537,7 +537,7 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback)
goto drop;
}

if (!is_loopback) {
if (!net_pkt_is_loopback(pkt)) {
if (net_ipv6_is_addr_loopback_raw(hdr->dst) ||
net_ipv6_is_addr_loopback_raw(hdr->src)) {
NET_DBG("DROP: ::1 packet");
Expand Down Expand Up @@ -631,7 +631,7 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback)
}

if ((IS_ENABLED(CONFIG_NET_ROUTING) || IS_ENABLED(CONFIG_NET_ROUTE_MCAST)) &&
!is_loopback && is_src_non_tentative_itself(hdr->src)) {
!net_pkt_is_loopback(pkt) && is_src_non_tentative_itself(hdr->src)) {
NET_DBG("DROP: src addr is %s", "mine");
goto drop;
}
Expand Down
4 changes: 2 additions & 2 deletions subsys/net/ip/ipv6_fragment.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,9 +346,9 @@ static void reassemble_packet(struct net_ipv6_reassembly *reass)
/* We need to use the queue when feeding the packet back into the
* IP stack as we might run out of stack if we call processing_data()
* directly. As the packet does not contain link layer header, we
* MUST NOT pass it to L2 so there will be a special check for that
* in process_data() when handling the packet.
* MUST NOT pass it to L2 so mark it as l2_processed.
*/
net_pkt_set_l2_processed(pkt, true);
if (net_recv_data(net_pkt_iface(pkt), pkt) >= 0) {
return;
}
Expand Down
50 changes: 15 additions & 35 deletions subsys/net/ip/net_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,26 +64,11 @@ LOG_MODULE_REGISTER(net_core, CONFIG_NET_CORE_LOG_LEVEL);
#include "net_stats.h"

#if defined(CONFIG_NET_NATIVE)
static inline enum net_verdict process_data(struct net_pkt *pkt,
bool is_loopback)
static inline enum net_verdict process_data(struct net_pkt *pkt)
{
int ret;
bool locally_routed = false;

net_pkt_set_l2_processed(pkt, false);

/* Initial call will forward packets to SOCK_RAW packet sockets. */
ret = net_packet_socket_input(pkt, ETH_P_ALL);
if (ret != NET_CONTINUE) {
return ret;
}

/* If the packet is routed back to us when we have reassembled an IPv4 or IPv6 packet,
* then do not pass it to L2 as the packet does not have link layer headers in it.
*/
if (net_pkt_is_ip_reassembled(pkt)) {
locally_routed = true;
}
net_packet_socket_input(pkt, ETH_P_ALL, SOCK_RAW);

/* If there is no data, then drop the packet. */
if (!pkt->frags) {
Expand All @@ -93,8 +78,9 @@ static inline enum net_verdict process_data(struct net_pkt *pkt,
return NET_DROP;
}

if (!is_loopback && !locally_routed) {
if (!net_pkt_is_l2_processed(pkt)) {
ret = net_if_recv_data(net_pkt_iface(pkt), pkt);
net_pkt_set_l2_processed(pkt, true);
if (ret != NET_CONTINUE) {
if (ret == NET_DROP) {
NET_DBG("Packet %p discarded by L2", pkt);
Expand All @@ -106,21 +92,13 @@ static inline enum net_verdict process_data(struct net_pkt *pkt,
}
}

net_pkt_set_l2_processed(pkt, true);

/* L2 has modified the buffer starting point, it is easier
* to re-initialize the cursor rather than updating it.
*/
net_pkt_cursor_init(pkt);

if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET_DGRAM)) {
/* Consecutive call will forward packets to SOCK_DGRAM packet sockets
* (after L2 removed header).
*/
ret = net_packet_socket_input(pkt, net_pkt_ll_proto_type(pkt));
if (ret != NET_CONTINUE) {
return ret;
}
net_packet_socket_input(pkt, net_pkt_ll_proto_type(pkt), SOCK_DGRAM);
}

uint8_t family = net_pkt_family(pkt);
Expand All @@ -131,9 +109,9 @@ static inline enum net_verdict process_data(struct net_pkt *pkt,
uint8_t vtc_vhl = NET_IPV6_HDR(pkt)->vtc & 0xf0;

if (IS_ENABLED(CONFIG_NET_IPV6) && vtc_vhl == 0x60) {
return net_ipv6_input(pkt, is_loopback);
return net_ipv6_input(pkt);
} else if (IS_ENABLED(CONFIG_NET_IPV4) && vtc_vhl == 0x40) {
return net_ipv4_input(pkt, is_loopback);
return net_ipv4_input(pkt);
}

NET_DBG("Unknown IP family packet (0x%x)", NET_IPV6_HDR(pkt)->vtc & 0xf0);
Expand All @@ -148,10 +126,10 @@ static inline enum net_verdict process_data(struct net_pkt *pkt,
return NET_DROP;
}

static void processing_data(struct net_pkt *pkt, bool is_loopback)
static void processing_data(struct net_pkt *pkt)
{
again:
switch (process_data(pkt, is_loopback)) {
switch (process_data(pkt)) {
case NET_CONTINUE:
if (IS_ENABLED(CONFIG_NET_L2_VIRTUAL)) {
/* If we have a tunneling packet, feed it back
Expand Down Expand Up @@ -421,7 +399,9 @@ int net_try_send_data(struct net_pkt *pkt, k_timeout_t timeout)
* to RX processing.
*/
NET_DBG("Loopback pkt %p back to us", pkt);
processing_data(pkt, true);
net_pkt_set_loopback(pkt, true);
net_pkt_set_l2_processed(pkt, true);
processing_data(pkt);
ret = 0;
goto err;
}
Expand Down Expand Up @@ -481,7 +461,6 @@ int net_try_send_data(struct net_pkt *pkt, k_timeout_t timeout)

static void net_rx(struct net_if *iface, struct net_pkt *pkt)
{
bool is_loopback = false;
size_t pkt_len;

pkt_len = net_pkt_get_len(pkt);
Expand All @@ -493,12 +472,13 @@ static void net_rx(struct net_if *iface, struct net_pkt *pkt)
if (IS_ENABLED(CONFIG_NET_LOOPBACK)) {
#ifdef CONFIG_NET_L2_DUMMY
if (net_if_l2(iface) == &NET_L2_GET_NAME(DUMMY)) {
is_loopback = true;
net_pkt_set_loopback(pkt, true);
net_pkt_set_l2_processed(pkt, true);
}
#endif
}

processing_data(pkt, is_loopback);
processing_data(pkt);

net_print_statistics();
net_pkt_print();
Expand Down
1 change: 1 addition & 0 deletions subsys/net/ip/net_pkt.c
Original file line number Diff line number Diff line change
Expand Up @@ -2047,6 +2047,7 @@ static void clone_pkt_attributes(struct net_pkt *pkt, struct net_pkt *clone_pkt)
net_pkt_set_rx_timestamping(clone_pkt, net_pkt_is_rx_timestamping(pkt));
net_pkt_set_forwarding(clone_pkt, net_pkt_forwarding(pkt));
net_pkt_set_chksum_done(clone_pkt, net_pkt_is_chksum_done(pkt));
net_pkt_set_loopback(pkt, net_pkt_is_loopback(pkt));
net_pkt_set_ip_reassembled(pkt, net_pkt_is_ip_reassembled(pkt));
net_pkt_set_cooked_mode(clone_pkt, net_pkt_is_cooked_mode(pkt));
net_pkt_set_ipv4_pmtu(clone_pkt, net_pkt_ipv4_pmtu(pkt));
Expand Down
12 changes: 4 additions & 8 deletions subsys/net/ip/net_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,25 +177,21 @@ extern void loopback_enable_address_swap(bool swap_addresses);
#endif /* CONFIG_NET_TEST */

#if defined(CONFIG_NET_NATIVE)
enum net_verdict net_ipv4_input(struct net_pkt *pkt, bool is_loopback);
enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback);
enum net_verdict net_ipv4_input(struct net_pkt *pkt);
enum net_verdict net_ipv6_input(struct net_pkt *pkt);
extern void net_tc_tx_init(void);
extern void net_tc_rx_init(void);
#else
static inline enum net_verdict net_ipv4_input(struct net_pkt *pkt,
bool is_loopback)
static inline enum net_verdict net_ipv4_input(struct net_pkt *pkt)
{
ARG_UNUSED(pkt);
ARG_UNUSED(is_loopback);

return NET_CONTINUE;
}

static inline enum net_verdict net_ipv6_input(struct net_pkt *pkt,
bool is_loopback)
static inline enum net_verdict net_ipv6_input(struct net_pkt *pkt)
{
ARG_UNUSED(pkt);
ARG_UNUSED(is_loopback);

return NET_CONTINUE;
}
Expand Down
11 changes: 5 additions & 6 deletions subsys/net/ip/packet_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,27 @@ LOG_MODULE_REGISTER(net_sockets_raw, CONFIG_NET_SOCKETS_LOG_LEVEL);
#include "connection.h"
#include "packet_socket.h"

enum net_verdict net_packet_socket_input(struct net_pkt *pkt, uint16_t proto)
void net_packet_socket_input(struct net_pkt *pkt,
uint16_t proto,
enum net_sock_type type)
{
sa_family_t orig_family;
enum net_verdict net_verdict;

#if defined(CONFIG_NET_DSA_DEPRECATED)
/*
* For DSA the master port is not supporting raw packets. Only the
* lan1..3 are working with them.
*/
if (dsa_is_port_master(net_pkt_iface(pkt))) {
return NET_CONTINUE;
return;
}
#endif

orig_family = net_pkt_family(pkt);

net_pkt_set_family(pkt, AF_PACKET);

net_verdict = net_conn_packet_input(pkt, proto);
net_conn_packet_input(pkt, proto, type);

net_pkt_set_family(pkt, orig_family);

return net_verdict;
}
Loading