Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch #9977: New socket option IPV6_RECVPKTINFO #19

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/api/sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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: {
Expand Down
9 changes: 9 additions & 0 deletions src/include/lwip/sockets.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
59 changes: 42 additions & 17 deletions test/unit/api/test_sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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);

Expand All @@ -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 */
Expand All @@ -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);
Expand All @@ -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)
{
Expand All @@ -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
Expand Down