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 <christina.schoenrogge@garmin.com>
Co-authored-by: Joseph Huang <joseph.huang@garmin.com>
Co-authored-by: Chee Bin Hoh <hohcheebin@gmail.com>
Co-authored-by: hanhui <hanhui03@163.com>
This commit is contained in:
Nate Karstens 2023-05-10 09:58:30 -05:00
parent 4dd7e9f816
commit 70a730df64
3 changed files with 39 additions and 0 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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