diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 1a733e6c..6037ac99 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -248,6 +248,16 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, return; } +#if ESP_LWIP && LWIP_IPV6 + /* This should be eventually moved to a flag on the UDP PCB, and this drop can happen + more correctly in udp_input(). This will also allow icmp_dest_unreach() to be called. */ + if (conn->flags & NETCONN_FLAG_IPV6_V6ONLY && !ip_current_is_v6()) { + LWIP_DEBUGF(API_MSG_DEBUG, ("recv_udp: Dropping IPv4 UDP packet (IPv6-only socket)")); + pbuf_free(p); + return; + } +#endif /* ESP_LWIP && LWIP_IPV6 */ + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); if (buf == NULL) { pbuf_free(p); @@ -668,6 +678,15 @@ pcb_new(struct api_msg *msg) if (msg->conn->pcb.ip == NULL) { msg->err = ERR_MEM; } +#if ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 + else { + if (NETCONNTYPE_ISIPV6(msg->conn->type)) { + /* Convert IPv4 PCB manually to an IPv6 PCB */ + IP_SET_TYPE_VAL(msg->conn->pcb.ip->local_ip, IPADDR_TYPE_V6); + IP_SET_TYPE_VAL(msg->conn->pcb.ip->remote_ip, IPADDR_TYPE_V6); + } + } +#endif /* ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 */ } /** @@ -1233,6 +1252,20 @@ lwip_netconn_do_bind(void *m) err_t err; if (msg->conn->pcb.tcp != NULL) { +#if ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 + /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY, + * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to bind + */ + if (ip_addr_cmp(API_EXPR_REF(msg->msg.bc.ipaddr), IP6_ADDR_ANY) && + (netconn_get_ipv6only(msg->conn) == 0)) { + /* change PCB type to IPADDR_TYPE_ANY */ + IP_SET_TYPE_VAL(msg->conn->pcb.ip->local_ip, IPADDR_TYPE_ANY); + IP_SET_TYPE_VAL(msg->conn->pcb.ip->remote_ip, IPADDR_TYPE_ANY); + + /* bind to IPADDR_TYPE_ANY */ + API_EXPR_REF(msg->msg.bc.ipaddr) = IP_ANY_TYPE; + } +#endif /* ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 */ switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: @@ -1548,6 +1581,14 @@ lwip_netconn_do_send(void *m) struct api_msg *msg = (struct api_msg *)m; err_t err = netconn_err(msg->conn); + +#if ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 + if ((msg->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) &&IP_IS_V4MAPPEDV6(&msg->msg.b->addr)) { + LWIP_DEBUGF(API_MSG_DEBUG, ("lwip_netconn_do_send: Dropping IPv4 packet on IPv6-only socket")); + msg->err = ERR_VAL; + } +#endif /* ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 */ + if (err == ERR_OK) { if (msg->conn->pcb.tcp != NULL) { switch (NETCONNTYPE_GROUP(msg->conn->type)) { diff --git a/src/api/netdb.c b/src/api/netdb.c index ee782978..77ce7dfc 100644 --- a/src/api/netdb.c +++ b/src/api/netdb.c @@ -335,6 +335,11 @@ lwip_getaddrinfo(const char *nodename, const char *servname, type = NETCONN_DNS_IPV4; } else if (ai_family == AF_INET6) { type = NETCONN_DNS_IPV6; +#if ESP_LWIP + if (hints->ai_flags & AI_V4MAPPED) { + type = NETCONN_DNS_IPV6_IPV4; + } +#endif /* ESP_LWIP */ } #endif /* LWIP_IPV4 && LWIP_IPV6 */ err = netconn_gethostbyname_addrtype(nodename, &addr, type); @@ -351,6 +356,14 @@ lwip_getaddrinfo(const char *nodename, const char *servname, } } +#if ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 + if (ai_family == AF_INET6 && (hints->ai_flags & AI_V4MAPPED) + && IP_GET_TYPE(&addr) == IPADDR_TYPE_V4) { + /* Convert native V4 address to a V4-mapped IPV6 address */ + ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&addr), ip_2_ip4(&addr)); + } +#endif /* ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 */ + total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage); if (nodename != NULL) { namelen = strlen(nodename); diff --git a/src/core/udp.c b/src/core/udp.c index 0b609d33..066862e7 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -540,9 +540,20 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, if (!IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { return ERR_VAL; } +#if ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 + /* Unwrap IPV4-mapped IPV6 addresses and convert to native IPV4 here */ + if (IP_IS_V4MAPPEDV6(dst_ip)) { + ip_addr_t dest_ipv4; + unmap_ipv4_mapped_ipv6(ip_2_ip4(&dest_ipv4), ip_2_ip6(dst_ip)); +#if LWIP_CHECKSUM_ON_COPY + return udp_sendto_chksum(pcb, p, &dest_ipv4, dst_port, have_chksum, chksum); +#else + return udp_sendto(pcb, p, &dest_ipv4, dst_port); +#endif /* LWIP_CHECKSUM_ON_COPY */ + } +#endif /* ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 */ LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); - if (pcb->netif_idx != NETIF_NO_INDEX) { netif = netif_get_by_index(pcb->netif_idx); } else { diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index 2f977709..ddeb3475 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -133,6 +133,11 @@ extern const ip_addr_t ip_addr_any_type; ip_2_ip6(ipaddr)->addr[3] = 0; \ ip6_addr_clear_zone(ip_2_ip6(ipaddr)); }while(0) +#if ESP_LWIP && LWIP_IPV6 +#define IP_V6_EQ_PART(ipaddr, WORD, VAL) (ip_2_ip6(ipaddr)->addr[WORD] == htonl(VAL)) +#define IP_IS_V4MAPPEDV6(ipaddr) (IP_IS_V6(ipaddr) && IP_V6_EQ_PART(ipaddr, 0, 0) && IP_V6_EQ_PART(ipaddr, 1, 0) && IP_V6_EQ_PART(ipaddr, 2, 0x0000FFFF)) +#endif /* ESP_LWIP && LWIP_IPV6 */ + /** @ingroup ipaddr */ #define ip_addr_copy(dest, src) do{ IP_SET_TYPE_VAL(dest, IP_GET_TYPE(&src)); if(IP_IS_V6_VAL(src)){ \ ip6_addr_copy(*ip_2_ip6(&(dest)), *ip_2_ip6(&(src))); }else{ \