net: connection: Cleanup packet input processing

Part of the socket matching criteria for AF_PACKET family took place
inside conn_raw_socket() function, and some of it was redundant with
what already was checked in net_conn_packet_input(). Moreover, if the
packet cloning for packet socket failed for whatever reason, the packet
was reported as NET_DROP, which was confusing.
Finally, conn_raw_socket() updated network stats, which didn't really
work as net stats are only collected for UDP/TCP protocols and not for
L2 level protocols.

Therefore, cleanup the processing by:
  * Moving all socket matching criteria into net_conn_packet_input()
    for clarity,
  * Drop unneeded net stats functions,
  * Clarify NET_DROP strategy for packet socket input.
    net_conn_packet_input() should only be responsible for delivering
    packets to respective packet sockets, it should not decide whether
    to drop the packet or not - it's L2/L3 processing code
    responsibility. Therefore, assume this function forwards packet for
    further processing by default, and only allow small optimization to
    return NET_OK if the packet socket was really the only endpoint in
    the system.
  * And finally, since now conn_raw_socket() responsibility was to clone
    the packet for the respective socket, and was almost identical to a
    corresponding function for raw IP sockets, unify the two functions.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2025-04-16 16:11:41 +02:00 committed by Benjamin Cabé
commit 379e71def3
2 changed files with 40 additions and 94 deletions

View file

@ -590,69 +590,41 @@ static bool is_iface_matching(struct net_conn *conn, struct net_pkt *pkt)
return (net_pkt_iface(pkt) == net_context_get_iface(conn->context)); return (net_pkt_iface(pkt) == net_context_get_iface(conn->context));
} }
#if defined(CONFIG_NET_SOCKETS_PACKET) #if defined(CONFIG_NET_SOCKETS_PACKET) || defined(CONFIG_NET_SOCKETS_INET_RAW)
static enum net_verdict conn_raw_socket(struct net_pkt *pkt, static void conn_raw_socket_deliver(struct net_pkt *pkt, struct net_conn *conn,
struct net_conn *conn, uint8_t proto) bool is_ip)
{ {
enum net_sock_type type = net_context_get_type(conn->context);
if (proto == ETH_P_ALL) {
if ((type == SOCK_DGRAM && !net_pkt_is_l2_processed(pkt)) ||
(type == SOCK_RAW && net_pkt_is_l2_processed(pkt))) {
return NET_CONTINUE;
}
}
/*
* After l2 processed only deliver protocol matched pkt,
* unless the connection protocol is all packets
*/
if (type == SOCK_DGRAM && net_pkt_is_l2_processed(pkt) &&
conn->proto != ETH_P_ALL &&
conn->proto != net_pkt_ll_proto_type(pkt)) {
return NET_CONTINUE;
}
if (!(conn->flags & NET_CONN_LOCAL_ADDR_SET)) {
return NET_CONTINUE;
}
struct net_if *pkt_iface = net_pkt_iface(pkt);
struct sockaddr_ll *local;
struct net_pkt *raw_pkt; struct net_pkt *raw_pkt;
struct net_pkt_cursor cur;
local = (struct sockaddr_ll *)&conn->local_addr; net_pkt_cursor_backup(pkt, &cur);
net_pkt_cursor_init(pkt);
if (local->sll_ifindex != net_if_get_by_iface(pkt_iface)) { NET_DBG("[%p] raw%s match found cb %p ud %p", conn, is_ip ? " IP" : "",
return NET_CONTINUE; conn->cb, conn->user_data);
}
NET_DBG("[%p] raw match found cb %p ud %p", conn, conn->cb,
conn->user_data);
raw_pkt = net_pkt_clone(pkt, K_MSEC(CONFIG_NET_CONN_PACKET_CLONE_TIMEOUT)); raw_pkt = net_pkt_clone(pkt, K_MSEC(CONFIG_NET_CONN_PACKET_CLONE_TIMEOUT));
if (!raw_pkt) { if (raw_pkt == NULL) {
net_stats_update_per_proto_drop(pkt_iface, proto); NET_WARN("pkt cloning failed, pkt %p not delivered", pkt);
NET_WARN("pkt cloning failed, pkt %p dropped", pkt); goto out;
return NET_DROP;
} }
if (conn->cb(conn, raw_pkt, NULL, NULL, conn->user_data) == NET_DROP) { if (conn->cb(conn, raw_pkt, NULL, NULL, conn->user_data) == NET_DROP) {
net_stats_update_per_proto_drop(pkt_iface, proto);
net_pkt_unref(raw_pkt); net_pkt_unref(raw_pkt);
} else {
net_stats_update_per_proto_recv(pkt_iface, proto);
} }
return NET_OK; out:
net_pkt_cursor_restore(pkt, &cur);
} }
#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) enum net_verdict net_conn_packet_input(struct net_pkt *pkt, uint16_t proto)
{ {
bool raw_pkt_delivered = false; bool raw_sock_found = false;
bool raw_pkt_continue = false; bool raw_pkt_continue = false;
struct sockaddr_ll *local;
struct net_conn *conn; struct net_conn *conn;
enum net_verdict ret;
/* Only accept input with AF_PACKET family. */ /* Only accept input with AF_PACKET family. */
if (net_pkt_family(pkt) != AF_PACKET) { if (net_pkt_family(pkt) != AF_PACKET) {
@ -685,7 +657,11 @@ enum net_verdict net_conn_packet_input(struct net_pkt *pkt, uint16_t proto)
* with this packet regardless the result. * with this packet regardless the result.
*/ */
raw_pkt_continue = true; raw_pkt_continue = true;
continue; continue; /* L2 not processed yet */
}
if (conn->type == SOCK_RAW && net_pkt_is_l2_processed(pkt)) {
continue; /* L2 already processed */
} }
if (conn->proto == 0) { if (conn->proto == 0) {
@ -703,25 +679,23 @@ enum net_verdict net_conn_packet_input(struct net_pkt *pkt, uint16_t proto)
/* Apply protocol-specific matching criteria... */ /* Apply protocol-specific matching criteria... */
ret = conn_raw_socket(pkt, conn, proto); if (!(conn->flags & NET_CONN_LOCAL_ADDR_SET)) {
if (ret == NET_DROP) { continue;
k_mutex_unlock(&conn_lock);
goto drop;
} else if (ret == NET_OK) {
raw_pkt_delivered = true;
} }
local = (struct sockaddr_ll *)&conn->local_addr;
if (local->sll_ifindex != net_if_get_by_iface(net_pkt_iface(pkt))) {
continue;
}
conn_raw_socket_deliver(pkt, conn, false);
raw_sock_found = true;
} }
k_mutex_unlock(&conn_lock); k_mutex_unlock(&conn_lock);
if (raw_pkt_continue) { if (!raw_pkt_continue && raw_sock_found) {
/* When there is open connection different than AF_PACKET this
* packet shall be also handled in the upper net stack layers.
*/
return NET_CONTINUE;
}
if (raw_pkt_delivered) {
/* As one or more raw socket packets have already been delivered /* As one or more raw socket packets have already been delivered
* in the loop above, report NET_OK. * in the loop above, report NET_OK.
*/ */
@ -729,10 +703,10 @@ enum net_verdict net_conn_packet_input(struct net_pkt *pkt, uint16_t proto)
return NET_OK; return NET_OK;
} }
drop: /* When there is open connection different than AF_PACKET this
net_stats_update_per_proto_drop(net_pkt_iface(pkt), proto); * packet shall be also handled in the upper net stack layers.
*/
return NET_DROP; return NET_CONTINUE;
} }
#else #else
enum net_verdict net_conn_packet_input(struct net_pkt *pkt, uint16_t proto) enum net_verdict net_conn_packet_input(struct net_pkt *pkt, uint16_t proto)
@ -745,30 +719,6 @@ enum net_verdict net_conn_packet_input(struct net_pkt *pkt, uint16_t proto)
#endif /* defined(CONFIG_NET_SOCKETS_PACKET) */ #endif /* defined(CONFIG_NET_SOCKETS_PACKET) */
#if defined(CONFIG_NET_SOCKETS_INET_RAW) #if defined(CONFIG_NET_SOCKETS_INET_RAW)
static void conn_raw_ip_socket(struct net_pkt *pkt, struct net_conn *conn)
{
struct net_pkt *raw_pkt;
struct net_pkt_cursor cur;
net_pkt_cursor_backup(pkt, &cur);
net_pkt_cursor_init(pkt);
NET_DBG("[%p] raw IP match found cb %p ud %p", conn, conn->cb,
conn->user_data);
raw_pkt = net_pkt_clone(pkt, K_MSEC(CONFIG_NET_CONN_PACKET_CLONE_TIMEOUT));
if (raw_pkt == NULL) {
goto out;
}
if (conn->cb(conn, raw_pkt, NULL, NULL, conn->user_data) == NET_DROP) {
net_pkt_unref(raw_pkt);
}
out:
net_pkt_cursor_restore(pkt, &cur);
}
enum net_verdict net_conn_raw_ip_input(struct net_pkt *pkt, enum net_verdict net_conn_raw_ip_input(struct net_pkt *pkt,
union net_ip_header *ip_hdr, union net_ip_header *ip_hdr,
uint8_t proto) uint8_t proto)
@ -810,7 +760,7 @@ enum net_verdict net_conn_raw_ip_input(struct net_pkt *pkt,
continue; /* wrong local address */ continue; /* wrong local address */
} }
conn_raw_ip_socket(pkt, conn); conn_raw_socket_deliver(pkt, conn, true);
} }
k_mutex_unlock(&conn_lock); k_mutex_unlock(&conn_lock);

View file

@ -43,9 +43,5 @@ enum net_verdict net_packet_socket_input(struct net_pkt *pkt, uint16_t proto)
net_pkt_set_family(pkt, orig_family); net_pkt_set_family(pkt, orig_family);
if (net_verdict == NET_DROP) { return net_verdict;
return NET_CONTINUE;
} else {
return net_verdict;
}
} }