From 70a730df6456b69932104c3992766d55c0b8f13b Mon Sep 17 00:00:00 2001 From: Nate Karstens Date: Wed, 10 May 2023 09:58:30 -0500 Subject: [PATCH] Implement IPV6_RECVPKTINFO socket option Implements the IPV6_RECVPKTINFO socket option for receiving ancillary data about an IPv6 packet. Also fixes an issue where the interface index was not being copied and updates IP_PKTINFO flag to use netconn flags macros. Based on work from https://savannah.nongnu.org/patch/?9554 Co-authored-by: Christina Schoenrogge Co-authored-by: Joseph Huang Co-authored-by: Chee Bin Hoh Co-authored-by: hanhui --- src/api/sockets.c | 29 +++++++++++++++++++++++++++++ src/core/pbuf.c | 1 + src/include/lwip/sockets.h | 9 +++++++++ 3 files changed, 39 insertions(+) diff --git a/src/api/sockets.c b/src/api/sockets.c index 425c0231..64c9f485 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -1214,6 +1214,23 @@ lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16 } #endif /* LWIP_IPV4 */ } +#if LWIP_IPV6 + else if (IP_IS_V6(&buf->toaddr)) { + 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 */ @@ -3676,6 +3693,18 @@ 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) { + netconn_set_flags(sock->conn, NETCONN_FLAG_PKTINFO); + } else { + netconn_clear_flags(sock->conn, NETCONN_FLAG_PKTINFO); + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_RECVPKTINFO, ..) -> %d\n", + s, *(const int *)optval)); + break; +#endif /* LWIP_NETBUF_RECVINFO */ #if LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP case IPV6_MULTICAST_IF: LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); diff --git a/src/core/pbuf.c b/src/core/pbuf.c index eec83706..361b7194 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -1343,6 +1343,7 @@ pbuf_clone(pbuf_layer layer, pbuf_type type, struct pbuf *p) return NULL; } err = pbuf_copy(q, p); + q->if_idx = p->if_idx; LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */ LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); return q; diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index 4ae9c38e..c00098e4 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -299,6 +299,8 @@ struct linger { #define IPV6_CHECKSUM 7 /* RFC3542: calculate and insert the ICMPv6 checksum for raw sockets. */ #define IPV6_UNICAST_HOPS 16 /* RFC3493: hop limit in outgoing unicast IPv6 packets */ #define IPV6_V6ONLY 27 /* RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. */ +#define IPV6_RECVPKTINFO 49 /* RFC3542: receive ancillary data for packet */ +#define IPV6_PKTINFO 50 /* RFC3542: ancillary data for a packet */ #endif /* LWIP_IPV6 */ #if LWIP_UDP && LWIP_UDPLITE @@ -343,6 +345,13 @@ struct in_pktinfo { }; #endif /* LWIP_IPV4 */ +#if LWIP_IPV6 +struct in6_pktinfo { + struct in6_addr ipi6_addr; + int ipi6_ifindex; +}; +#endif /* LWIP_IPV6 */ + #if LWIP_IPV6_MLD /* * Options and types related to IPv6 multicast membership