From d8dc5446174ac9540d0723e847a6c32218465b34 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 30 Aug 2019 12:18:03 +0300 Subject: [PATCH 1/2] net: conn: Deliver multicast pkt to all interested parties If we receive a multicast IPv4 or IPv6 packet, then we need to deliver it to all sockets that have installed a handler for it. Signed-off-by: Jukka Rissanen --- subsys/net/ip/connection.c | 78 +++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c index 6ab3cce666a0..e99b7a3bc916 100644 --- a/subsys/net/ip/connection.c +++ b/subsys/net/ip/connection.c @@ -28,6 +28,9 @@ LOG_MODULE_REGISTER(net_conn, CONFIG_NET_CONN_LOG_LEVEL); #include "connection.h" #include "net_stats.h" +/** How long to wait for when cloning multicast packet */ +#define CLONE_TIMEOUT K_MSEC(100) + /** Is this connection used or not */ #define NET_CONN_IN_USE BIT(0) @@ -504,6 +507,7 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, { struct net_if *pkt_iface = net_pkt_iface(pkt); struct net_conn *best_match = NULL; + bool is_mcast_pkt = false, mcast_pkt_delivered = false; s16_t best_rank = -1; struct net_conn *conn; u16_t src_port; @@ -546,6 +550,20 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, " family %d", net_proto2str(net_pkt_family(pkt), proto), pkt, ntohs(src_port), ntohs(dst_port), net_pkt_family(pkt)); + /* If we receive a packet with multicast destination address, we might + * need to deliver the packet to multiple recipients. + */ + if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) { + if (net_ipv4_is_addr_mcast(&ip_hdr->ipv4->dst)) { + is_mcast_pkt = true; + } + } else if (IS_ENABLED(CONFIG_NET_IPV6) && + net_pkt_family(pkt) == AF_INET6) { + if (net_ipv6_is_addr_mcast(&ip_hdr->ipv6->dst)) { + is_mcast_pkt = true; + } + } + SYS_SLIST_FOR_EACH_CONTAINER(&conn_used, conn, node) { if (conn->proto != proto) { continue; @@ -598,8 +616,42 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, } if (best_rank < NET_CONN_RANK(conn->flags)) { - best_rank = NET_CONN_RANK(conn->flags); - best_match = conn; + struct net_pkt *mcast_pkt; + + if (!is_mcast_pkt) { + best_rank = NET_CONN_RANK(conn->flags); + best_match = conn; + + continue; + } + + /* If we have a multicast packet, and we found + * a match, then deliver the packet immediately + * to the handler. As there might be several + * sockets interested about these, we need to + * clone the received pkt. + */ + + NET_DBG("[%p] mcast match found cb %p ud %p", + conn, conn->cb, conn->user_data); + + mcast_pkt = net_pkt_clone(pkt, CLONE_TIMEOUT); + if (!mcast_pkt) { + goto drop; + } + + if (conn->cb(conn, mcast_pkt, ip_hdr, + proto_hdr, conn->user_data) == + NET_DROP) { + net_stats_update_per_proto_drop( + pkt_iface, proto); + net_pkt_unref(mcast_pkt); + } else { + net_stats_update_per_proto_recv( + pkt_iface, proto); + } + + mcast_pkt_delivered = true; } } else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) || IS_ENABLED(CONFIG_NET_SOCKETS_CAN)) { @@ -608,6 +660,16 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, } } + if (is_mcast_pkt && mcast_pkt_delivered) { + /* As one or more multicast packets have already been delivered + * in the loop above, we shall not call the callback again here + */ + + net_pkt_unref(pkt); + + return NET_OK; + } + conn = best_match; if (conn) { NET_DBG("[%p] match found cb %p ud %p rank 0x%02x", @@ -625,16 +687,14 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, NET_DBG("No match found."); - /* If the destination address is multicast address, - * we will not send an ICMP error as that makes no sense. + /* Do not send ICMP error for Packet socket as that makes no + * sense here. */ if (IS_ENABLED(CONFIG_NET_IPV6) && - net_pkt_family(pkt) == AF_INET6 && - net_ipv6_is_addr_mcast(&ip_hdr->ipv6->dst)) { + net_pkt_family(pkt) == AF_INET6 && is_mcast_pkt) { ; } else if (IS_ENABLED(CONFIG_NET_IPV4) && - net_pkt_family(pkt) == AF_INET && - net_ipv4_is_addr_mcast(&ip_hdr->ipv4->dst)) { + net_pkt_family(pkt) == AF_INET && is_mcast_pkt) { ; } else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) && net_pkt_family(pkt) == AF_PACKET) { @@ -643,7 +703,7 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, conn_send_icmp_error(pkt); if (IS_ENABLED(CONFIG_NET_TCP) && proto == IPPROTO_TCP) { - net_stats_update_tcp_seg_connrst(net_pkt_iface(pkt)); + net_stats_update_tcp_seg_connrst(pkt_iface); } } From c004bf735b84ab7e1195153c65df57c0072969ff Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 30 Aug 2019 15:18:03 +0300 Subject: [PATCH 2/2] tests: net: dhcpv4: Increase the buffer count Test requires more network buffers to work properly. Signed-off-by: Jukka Rissanen --- tests/net/dhcpv4/prj.conf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/net/dhcpv4/prj.conf b/tests/net/dhcpv4/prj.conf index c229a5d7e680..60d161aafdc0 100644 --- a/tests/net/dhcpv4/prj.conf +++ b/tests/net/dhcpv4/prj.conf @@ -4,10 +4,10 @@ CONFIG_NET_L2_DUMMY=y CONFIG_NET_UDP=y CONFIG_NET_DHCPV4=y CONFIG_NET_BUF=y -CONFIG_NET_PKT_RX_COUNT=4 -CONFIG_NET_PKT_TX_COUNT=4 -CONFIG_NET_BUF_RX_COUNT=7 -CONFIG_NET_BUF_TX_COUNT=7 +CONFIG_NET_PKT_RX_COUNT=5 +CONFIG_NET_PKT_TX_COUNT=5 +CONFIG_NET_BUF_RX_COUNT=8 +CONFIG_NET_BUF_TX_COUNT=8 CONFIG_NET_LOG=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y