From e65202f8257e55b09e6309b1aa405b5e6a017f0d Mon Sep 17 00:00:00 2001 From: James Smith Date: Tue, 3 Jul 2012 13:16:04 -0600 Subject: [PATCH 1/3] Applied patch by James Smith to implement IPV6_V6ONLY support in sockets and netconns. Change-Id: I2ecd8e218703114890b2d678cc1ccf997a16f5e3 --- src/api/api_msg.c | 16 +++++++-- src/api/sockets.c | 74 ++++++++++++++++++++++++++++++++++++++ src/include/lwip/api.h | 6 ++++ src/include/lwip/sockets.h | 10 ++++++ 4 files changed, 104 insertions(+), 2 deletions(-) diff --git a/src/api/api_msg.c b/src/api/api_msg.c index d46cd13e..7ec9cfba 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -1076,11 +1076,23 @@ lwip_netconn_do_listen(struct api_msg_msg *msg) if (msg->conn->pcb.tcp != NULL) { if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { if (msg->conn->state == NETCONN_NONE) { + struct tcp_pcb* lpcb; +#if LWIP_IPV6 + if ((msg->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) == 0) { #if TCP_LISTEN_BACKLOG - struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); + lpcb = tcp_listen_dual_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); #else /* TCP_LISTEN_BACKLOG */ - struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp); + lpcb = tcp_listen_dual(msg->conn->pcb.tcp); #endif /* TCP_LISTEN_BACKLOG */ + } else +#endif /* LWIP_IPV6 */ + { +#if TCP_LISTEN_BACKLOG + lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); +#else /* TCP_LISTEN_BACKLOG */ + lpcb = tcp_listen(msg->conn->pcb.tcp); +#endif /* TCP_LISTEN_BACKLOG */ + } if (lpcb == NULL) { /* in this case, the old pcb is still allocated */ msg->err = ERR_MEM; diff --git a/src/api/sockets.c b/src/api/sockets.c index 1b236a84..8a05aed6 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -1664,6 +1664,24 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) } /* switch (optname) */ break; #endif /* LWIP_TCP */ + +#if LWIP_IPV6 +/* Level: IPPROTO_IPV6 */ + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + if (*optlen < sizeof(int)) { + err = EINVAL; + } + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; +#endif /* LWIP_IPV6 */ + #if LWIP_UDP && LWIP_UDPLITE /* Level: IPPROTO_UDPLITE */ case IPPROTO_UDPLITE: @@ -1902,6 +1920,23 @@ lwip_getsockopt_internal(void *arg) } /* switch (optname) */ break; #endif /* LWIP_TCP */ + +#if LWIP_IPV6 +/* Level: IPPROTO_IPV6 */ + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + *(int*)optval = ((sock->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) ? 1 : 0); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n", + s, *(int *)optval)); + break; + default: + LWIP_ASSERT("unhandled optname", 0); + break; + } /* switch (optname) */ + break; +#endif /* LWIP_IPV6 */ + #if LWIP_UDP && LWIP_UDPLITE /* Level: IPPROTO_UDPLITE */ case IPPROTO_UDPLITE: @@ -2081,6 +2116,24 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt } /* switch (optname) */ break; #endif /* LWIP_TCP */ + +#if LWIP_IPV6 +/* Level: IPPROTO_IPV6 */ + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + if (optlen < sizeof(int)) { + err = EINVAL; + } + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; +#endif /* LWIP_IPV6 */ + #if LWIP_UDP && LWIP_UDPLITE /* Level: IPPROTO_UDPLITE */ case IPPROTO_UDPLITE: @@ -2310,6 +2363,27 @@ lwip_setsockopt_internal(void *arg) } /* switch (optname) */ break; #endif /* LWIP_TCP*/ + +#if LWIP_IPV6 +/* Level: IPPROTO_IPV6 */ + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + if (*(int*)optval) { + sock->conn->flags |= NETCONN_FLAG_IPV6_V6ONLY; + } else { + sock->conn->flags &= ~NETCONN_FLAG_IPV6_V6ONLY; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n", + s, ((sock->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) ? 1 : 0))); + break; + default: + LWIP_ASSERT("unhandled optname", 0); + break; + } /* switch (optname) */ + break; +#endif /* LWIP_IPV6 */ + #if LWIP_UDP && LWIP_UDPLITE /* Level: IPPROTO_UDPLITE */ case IPPROTO_UDPLITE: diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index 4c985800..ac58eebb 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -73,6 +73,12 @@ extern "C" { /** If a nonblocking write has been rejected before, poll_tcp needs to check if the netconn is writable again */ #define NETCONN_FLAG_CHECK_WRITESPACE 0x10 +#if LWIP_IPV6 +/** If this flag is set then only IPv6 communication is allowed on the + netconn. As per RFC#3493 this features defaults to OFF allowing + dual-stack usage by default. */ +#define NETCONN_FLAG_IPV6_V6ONLY 0x20 +#endif /* LWIP_IPV6 */ /* Helpers to process several netconn_types by the same code */ diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index 697f200d..73461374 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -148,6 +148,9 @@ struct linger { #define IPPROTO_IP 0 #define IPPROTO_TCP 6 #define IPPROTO_UDP 17 +#if LWIP_IPV6 +#define IPPROTO_IPV6 41 +#endif /* LWIP_IPV6 */ #define IPPROTO_UDPLITE 136 /* Flags we can use with send and recv. */ @@ -175,6 +178,13 @@ struct linger { #define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ #endif /* LWIP_TCP */ +#if LWIP_IPV6 +/* + * Options for level IPPROTO_IPV6 + */ +#define IPV6_V6ONLY 27 /* RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. */ +#endif /* LWIP_IPV6 */ + #if LWIP_UDP && LWIP_UDPLITE /* * Options for level IPPROTO_UDPLITE From 6c12e5bfbe41b022ee8af9672dd541e745a68d9a Mon Sep 17 00:00:00 2001 From: Ivan Delamer Date: Tue, 3 Jul 2012 14:39:25 -0600 Subject: [PATCH 2/3] Allow setting/getting socket option IPV6_V6ONLY for stream sockets only, as datagram sockets do not support dual IP versions yet. Change-Id: I2d89bdaa06b19dc0c553c7be6ac6e9a71d3ce8a5 --- src/api/sockets.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/api/sockets.c b/src/api/sockets.c index 8a05aed6..66036712 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -1673,6 +1673,9 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) if (*optlen < sizeof(int)) { err = EINVAL; } + /* @todo: this does not work for datagram sockets, yet */ + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) + return 0; break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", @@ -2125,6 +2128,11 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt if (optlen < sizeof(int)) { err = EINVAL; } + + /* @todo: this does not work for datagram sockets, yet */ + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) + return 0; + break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", From 97b8abf16cb5ebca14f71f0036eef50c9cd88a9c Mon Sep 17 00:00:00 2001 From: James Smith Date: Tue, 24 Jul 2012 10:34:09 -0600 Subject: [PATCH 3/3] Fix bug #36857: tcp_listen_dual_with_backlog() only works with ANY address Change-Id: I092a4c9978d88040214fc44a4c4b353be618d76c --- src/core/tcp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/tcp.c b/src/core/tcp.c index 05e7c7d8..a0cbb159 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -591,11 +591,12 @@ tcp_listen_dual_with_backlog(struct tcp_pcb *pcb, u8_t backlog) { struct tcp_pcb *lpcb; - if (!ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { - return NULL; - } lpcb = tcp_listen_with_backlog(pcb, backlog); - if (lpcb != NULL) { + if ((lpcb != NULL) && + ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { + /* The default behavior is to accept connections on either + * IPv4 or IPv6, if not bound. */ + /* @see NETCONN_FLAG_IPV6_V6ONLY for changing this behavior */ ((struct tcp_pcb_listen*)lpcb)->accept_any_ip_version = 1; } return lpcb;