From 1712b06a64637e4e6ab56d65749ee74edee3fa78 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 16 Nov 2016 22:58:38 +0100 Subject: [PATCH] Work on dual-stack netconn IPv6 netconns are created as IPADDR_TYPE_ANY raw/udp/tcp PCBs internally bind, connect and sendto now accept IPv6 mapped IPv4 addresses or IPv4 addresses as argument getaddr and receive functions now return IPv6 mapped IPv4 addresses instead of IPv4 addresses This behavior is close to BSD socket API --- src/api/api_lib.c | 71 ++++++++++++++++++++++++++++++++++++++++-- src/api/api_msg.c | 62 +++++++----------------------------- src/include/lwip/api.h | 1 + 3 files changed, 81 insertions(+), 53 deletions(-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index b4fc403d..9be38b71 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -231,6 +231,14 @@ netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) err = netconn_apimsg(lwip_netconn_do_getaddr, &msg); #endif /* LWIP_MPU_COMPATIBLE */ API_MSG_VAR_FREE(msg); + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Map IPv4 addresses to IPv6 mapped IPv4 */ + if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4(addr)) { + ip4_2_ipv6_mapped_ipv4(ip_2_ip6(addr), ip_2_ip4(addr)); + IP_SET_TYPE(addr, IPADDR_TYPE_V6); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ return err; } @@ -250,6 +258,7 @@ err_t netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) { API_MSG_VAR_DECLARE(msg); + ip_addr_t ipaddr; err_t err; LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); @@ -258,10 +267,28 @@ netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) if (addr == NULL) { addr = IP4_ADDR_ANY; } + + ip_addr_copy(ipaddr, *addr); + + #if 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 0, use IP_ANY_TYPE to bind + */ + if ((netconn_get_ipv6only(conn) == 0) && + ip_addr_cmp(&ipaddr, IP6_ADDR_ANY)) { + ip_addr_copy(ipaddr, *IP_ANY_TYPE); + } + + /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ + if (IP_IS_V6_VAL(ipaddr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&ipaddr))) { + unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(&ipaddr)); + IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).conn = conn; - API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); + API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(&ipaddr); API_MSG_VAR_REF(msg).msg.bc.port = port; err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg)); API_MSG_VAR_FREE(msg); @@ -282,6 +309,7 @@ err_t netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) { API_MSG_VAR_DECLARE(msg); + ip_addr_t ipaddr; err_t err; LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); @@ -291,9 +319,27 @@ netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) addr = IP4_ADDR_ANY; } + ip_addr_copy(ipaddr, *addr); + + #if 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 0, use IP_ANY_TYPE to bind + */ + if ((netconn_get_ipv6only(conn) == 0) && + ip_addr_cmp(&ipaddr, IP6_ADDR_ANY)) { + ip_addr_copy(ipaddr, *IP_ANY_TYPE); + } + + /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ + if (IP_IS_V6_VAL(ipaddr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&ipaddr))) { + unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(&ipaddr)); + IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).conn = conn; - API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); + API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(&ipaddr); API_MSG_VAR_REF(msg).msg.bc.port = port; err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg)); API_MSG_VAR_FREE(msg); @@ -561,8 +607,18 @@ netconn_recv_data(struct netconn *conn, void **new_buf) #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ #if (LWIP_UDP || LWIP_RAW) { + struct netbuf* nbuf = (struct netbuf*)buf; + LWIP_ASSERT("buf != NULL", buf != NULL); - len = netbuf_len((struct netbuf *)buf); + len = netbuf_len(nbuf); + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Map IPv4 addresses to IPv6 mapped IPv4 */ + if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4_VAL(nbuf->addr)) { + ip4_2_ipv6_mapped_ipv4(ip_2_ip6(&nbuf->addr), ip_2_ip4(&nbuf->addr)); + IP_SET_TYPE_VAL(nbuf->addr, IPADDR_TYPE_V6); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ } #endif /* (LWIP_UDP || LWIP_RAW) */ @@ -697,6 +753,15 @@ netconn_send(struct netconn *conn, struct netbuf *buf) LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ + if (IP_IS_V6_VAL(buf->addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&buf->addr))) { + unmap_ipv6_mapped_ipv4(ip_2_ip4(&buf->addr), ip_2_ip6(&buf->addr)); + IP_SET_TYPE_VAL(buf->addr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).conn = conn; API_MSG_VAR_REF(msg).msg.b = buf; diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 2b76f077..e19a6a0c 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -545,13 +545,18 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) static void pcb_new(struct api_msg *msg) { - LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); + enum lwip_ip_addr_type iptype; + LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); + + /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */ + iptype = NETCONNTYPE_ISIPV6(netconn_type(msg->conn))? IPADDR_TYPE_ANY : IPADDR_TYPE_V4; + /* Allocate a PCB for this connection */ switch(NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: - msg->conn->pcb.raw = raw_new(msg->msg.n.proto); + msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto); if (msg->conn->pcb.raw != NULL) { raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); } @@ -559,7 +564,7 @@ pcb_new(struct api_msg *msg) #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: - msg->conn->pcb.udp = udp_new(); + msg->conn->pcb.udp = udp_new_ip_type(iptype); if (msg->conn->pcb.udp != NULL) { #if LWIP_UDPLITE if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { @@ -575,7 +580,7 @@ pcb_new(struct api_msg *msg) #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: - msg->conn->pcb.tcp = tcp_new(); + msg->conn->pcb.tcp = tcp_new_ip_type(iptype); if (msg->conn->pcb.tcp != NULL) { setup_tcp(msg->conn); } @@ -589,15 +594,6 @@ pcb_new(struct api_msg *msg) if (msg->conn->pcb.ip == NULL) { msg->err = ERR_MEM; } -#if 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 /* LWIP_IPV4 && LWIP_IPV6 */ } /** @@ -1114,37 +1110,20 @@ lwip_netconn_do_bind(void *m) } else { msg->err = ERR_VAL; if (msg->conn->pcb.tcp != NULL) { - const ip_addr_t *ipaddr = API_EXPR_REF(msg->msg.bc.ipaddr); - -#if 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(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 */ - ipaddr = IP_ANY_TYPE; - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: - msg->err = raw_bind(msg->conn->pcb.raw, ipaddr); + msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); break; #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: - msg->err = udp_bind(msg->conn->pcb.udp, ipaddr, msg->msg.bc.port); + msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); break; #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: - msg->err = tcp_bind(msg->conn->pcb.tcp, ipaddr, msg->msg.bc.port); + msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); break; #endif /* LWIP_TCP */ default: @@ -1398,15 +1377,6 @@ lwip_netconn_do_send(void *m) } else { msg->err = ERR_CONN; if (msg->conn->pcb.tcp != NULL) { - -#if LWIP_IPV4 && LWIP_IPV6 - /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ - if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn)) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&msg->msg.b->addr))) { - unmap_ipv6_mapped_ipv4(ip_2_ip4(&msg->msg.b->addr), ip_2_ip6(&msg->msg.b->addr)); - IP_SET_TYPE(&msg->msg.b->addr, IPADDR_TYPE_V4); - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: @@ -1720,14 +1690,6 @@ lwip_netconn_do_getaddr(void *m) ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), msg->conn->pcb.ip->remote_ip); } - -#if LWIP_IPV4 && LWIP_IPV6 - /* Dual-stack: Map IPv4 addresses to IPv6 */ - if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn)) && IP_IS_V4_VAL(API_EXPR_DEREF(msg->msg.ad.ipaddr))) { - ip4_2_ipv6_mapped_ipv4(ip_2_ip6(&API_EXPR_DEREF(msg->msg.ad.ipaddr)), ip_2_ip4(&API_EXPR_DEREF(msg->msg.ad.ipaddr))); - IP_SET_TYPE_VAL(API_EXPR_DEREF(msg->msg.ad.ipaddr), IPADDR_TYPE_V6); - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ msg->err = ERR_OK; switch (NETCONNTYPE_GROUP(msg->conn->type)) { diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index e8620dd8..d1394533 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -90,6 +90,7 @@ extern "C" { #define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF3) == NETCONN_UDPLITE) #define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF3) == NETCONN_UDPNOCHKSUM) #else /* LWIP_IPV6 */ +#define NETCONNTYPE_ISIPV6(t) (0) #define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE) #define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM) #endif /* LWIP_IPV6 */