From 149e52f2c5092b68a58440df2908521cc43480d1 Mon Sep 17 00:00:00 2001 From: Marcus Dreier <115097+clabom@users.noreply.github.com> Date: Wed, 9 Aug 2023 16:46:06 +0200 Subject: [PATCH] Patch #9977: New socket option IPV6_RECVPKTINFO --- src/api/sockets.c | 26 ++++++++++++++++ src/include/lwip/sockets.h | 9 ++++++ test/unit/api/test_sockets.c | 59 +++++++++++++++++++++++++----------- 3 files changed, 77 insertions(+), 17 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index b9111943..e017a52d 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -1213,6 +1213,22 @@ lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16 msg->msg_flags |= MSG_CTRUNC; } #endif /* LWIP_IPV4 */ + } else if (IP_IS_V6(&buf->toaddr)) { +#if LWIP_IPV6 + if (msg->msg_controllen >= CMSG_SPACE(sizeof(struct in6_pktinfo))) { + struct cmsghdr *chdr = CMSG_FIRSTHDR(msg); /* This will always return a header!! */ + struct in6_pktinfo *pkti = (struct in6_pktinfo *)CMSG_DATA(chdr); + chdr->cmsg_level = IPPROTO_IPV6; + chdr->cmsg_type = IPV6_PKTINFO; + chdr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + pkti->ipi6_ifindex = buf->p->if_idx; + inet6_addr_from_ip6addr(&pkti->ipi6_addr, ip_2_ip6(netbuf_destaddr(buf))); + msg->msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); + wrote_msg = 1; + } else { + msg->msg_flags |= MSG_CTRUNC; + } +#endif /* LWIP_IPV6 */ } } #endif /* LWIP_NETBUF_RECVINFO */ @@ -3656,6 +3672,16 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n", s, (netconn_get_ipv6only(sock->conn) ? 1 : 0))); break; +#if LWIP_NETBUF_RECVINFO + case IPV6_RECVPKTINFO: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); + if (*(const int *)optval) { + sock->conn->flags |= NETCONN_FLAG_PKTINFO; + } else { + sock->conn->flags &= ~NETCONN_FLAG_PKTINFO; + } + break; +#endif /* LWIP_NETBUF_RECVINFO */ #if LWIP_IPV6_MLD case IPV6_JOIN_GROUP: case IPV6_LEAVE_GROUP: { diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index b6f3d524..fd58027d 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -298,6 +298,8 @@ struct linger { */ #define IPV6_CHECKSUM 7 /* RFC3542: calculate and insert the ICMPv6 checksum for raw sockets. */ #define IPV6_V6ONLY 27 /* RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. */ +#define IPV6_RECVPKTINFO 49 /* RFC3542: enables the receiving of ancillary data via setsockopt() */ +#define IPV6_PKTINFO 50 /* RFC3542: ancillary data in recvmsg() received */ #endif /* LWIP_IPV6 */ #if LWIP_UDP && LWIP_UDPLITE @@ -338,6 +340,13 @@ struct in_pktinfo { }; #endif /* LWIP_IPV4 */ +#if LWIP_IPV6 +struct in6_pktinfo { + unsigned int ipi6_ifindex; /* Interface index */ + struct in6_addr ipi6_addr; /* Destination (from header) address */ +}; +#endif /* LWIP_IPV6 */ + #if LWIP_IPV6_MLD /* * Options and types related to IPv6 multicast membership diff --git a/test/unit/api/test_sockets.c b/test/unit/api/test_sockets.c index 3faa5ff9..01c6d6d7 100644 --- a/test/unit/api/test_sockets.c +++ b/test/unit/api/test_sockets.c @@ -10,6 +10,7 @@ #include "lwip/priv/tcp_priv.h" #include "lwip/api.h" +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) static int test_sockets_get_used_count(void) @@ -255,7 +256,7 @@ static void test_sockets_msgapi_update_iovs(struct msghdr *msg, size_t bytes) /* note: this modifies the underyling iov_base and iov_len for a partial read for an individual vector. This updates the msg->msg_iov pointer to skip fully consumed vectors */ - + /* process fully consumed vectors */ for (i = 0; i < msg->msg_iovlen; i++) { if (msg->msg_iov[i].iov_len <= bytes) { @@ -395,7 +396,7 @@ static void test_sockets_msgapi_tcp(int domain) /* note: since we always receive after sending, there will be open space in the send buffer */ fail_unless(ret > 0); - + bytes_written += ret; if (bytes_written < TOTAL_DATA_SZ) { test_sockets_msgapi_update_iovs(&smsg, (size_t)ret); @@ -432,7 +433,7 @@ static void test_sockets_msgapi_tcp(int domain) } } while(ret > 0); } - + ret = lwip_close(s1); fail_unless(ret == 0); ret = lwip_close(s2); @@ -544,7 +545,6 @@ static void test_sockets_msgapi_udp(int domain) fail_unless(ret == 0); } -#if LWIP_IPV4 static void test_sockets_msgapi_cmsg(int domain) { int s, ret, enable; @@ -553,10 +553,10 @@ static void test_sockets_msgapi_cmsg(int domain) struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg; - struct in_pktinfo *pktinfo; u8_t rcv_buf[4]; u8_t snd_buf[4] = {0xDE, 0xAD, 0xBE, 0xEF}; - u8_t cmsg_buf[CMSG_SPACE(sizeof(struct in_pktinfo))]; + u8_t cmsg_buf[CMSG_SPACE(MAX(sizeof(struct in_pktinfo), + sizeof(struct in6_pktinfo)))]; test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size); @@ -571,7 +571,15 @@ static void test_sockets_msgapi_cmsg(int domain) fail_unless(ret == 0); enable = 1; - ret = lwip_setsockopt(s, IPPROTO_IP, IP_PKTINFO, &enable, sizeof(enable)); + if (domain == AF_INET) { +#if LWIP_IPV4 + ret = lwip_setsockopt(s, IPPROTO_IP, IP_PKTINFO, &enable, sizeof(enable)); +#endif + } else { +#if LWIP_IPV6 + ret = lwip_setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable, sizeof(enable)); +#endif + } fail_unless(ret == 0); /* Receive full message, including control message */ @@ -588,25 +596,42 @@ static void test_sockets_msgapi_cmsg(int domain) memset(rcv_buf, 0, sizeof(rcv_buf)); ret = lwip_sendto(s, snd_buf, sizeof(snd_buf), 0, (struct sockaddr*)&addr_storage, addr_size); fail_unless(ret == sizeof(snd_buf)); - + tcpip_thread_poll_one(); ret = lwip_recvmsg(s, &msg, 0); fail_unless(ret == sizeof(rcv_buf)); fail_unless(!memcmp(rcv_buf, snd_buf, sizeof(rcv_buf))); - + /* Verify message header */ cmsg = CMSG_FIRSTHDR(&msg); fail_unless(cmsg != NULL); fail_unless(cmsg->cmsg_len > 0); - fail_unless(cmsg->cmsg_level == IPPROTO_IP); - fail_unless(cmsg->cmsg_type == IP_PKTINFO); - /* Verify message data */ - pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg); - /* We only have loopback interface enabled */ - fail_unless(pktinfo->ipi_ifindex == 1); - fail_unless(pktinfo->ipi_addr.s_addr == PP_HTONL(INADDR_LOOPBACK)); + if (domain == AF_INET) { + struct in_pktinfo *pktinfo; + + fail_unless(cmsg->cmsg_level == IPPROTO_IP); + fail_unless(cmsg->cmsg_type == IP_PKTINFO); + + /* Verify message data */ + pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg); + /* We only have loopback interface enabled */ + fail_unless(pktinfo->ipi_ifindex == 1); + fail_unless(pktinfo->ipi_addr.s_addr == PP_HTONL(INADDR_LOOPBACK)); + } else { + struct in6_pktinfo *pktinfo; + struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT; + + fail_unless(cmsg->cmsg_level == IPPROTO_IPV6); + fail_unless(cmsg->cmsg_type == IPV6_PKTINFO); + + /* Verify message data */ + pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg); + /* We only have loopback interface enabled */ + fail_unless(pktinfo->ipi6_ifindex == 1); + fail_unless(!memcmp(&pktinfo->ipi6_addr, &lo6, sizeof(pktinfo->ipi6_addr))); + } /* Verify there are no additional messages */ cmsg = CMSG_NXTHDR(&msg, cmsg); @@ -632,7 +657,6 @@ static void test_sockets_msgapi_cmsg(int domain) ret = lwip_close(s); fail_unless(ret == 0); } -#endif /* LWIP_IPV4 */ START_TEST(test_sockets_msgapis) { @@ -645,6 +669,7 @@ START_TEST(test_sockets_msgapis) #if LWIP_IPV6 test_sockets_msgapi_udp(AF_INET6); test_sockets_msgapi_tcp(AF_INET6); + test_sockets_msgapi_cmsg(AF_INET6); #endif } END_TEST