return;
}
+#if 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
+
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
if (buf == NULL) {
pbuf_free(p);
if (ERR_IS_FATAL(msg->conn->last_err)) {
msg->err = msg->conn->last_err;
+#if LWIP_IPV4 && LWIP_IPV6
+ } else 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 /* LWIP_IPV4 && LWIP_IPV6 */
} else {
msg->err = ERR_CONN;
if (msg->conn->pcb.tcp != NULL) {
* @param res pointer to a pointer where to store the result (set to NULL on failure)
* @return 0 on success, non-zero on failure
*
- * @todo: implement AI_V4MAPPED, AI_ADDRCONFIG
+ * @todo: implement AI_ADDRCONFIG
*/
int
lwip_getaddrinfo(const char *nodename, const char *servname,
type = NETCONN_DNS_IPV4;
} else if (ai_family == AF_INET6) {
type = NETCONN_DNS_IPV6;
+ if (hints->ai_flags & AI_V4MAPPED) {
+ type = NETCONN_DNS_IPV6_IPV4;
+ }
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
err = netconn_gethostbyname_addrtype(nodename, &addr, type);
}
}
+#if 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 */
+ ip_addr_make_ip4_mapped_ip6(&addr, &addr);
+ }
+#endif
+
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage);
if (nodename != NULL) {
namelen = strlen(nodename);
switch (optname) {
case IPV6_V6ONLY:
LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
- /* @todo: this does not work for datagram sockets, yet */
- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
- return ENOPROTOOPT;
- }
*(int*)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n",
s, *(int *)optval));
case IPPROTO_IPV6:
switch (optname) {
case IPV6_V6ONLY:
- /* @todo: this does not work for datagram sockets, yet */
-#if CONFIG_MDNS
- //LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
-#else
- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
-#endif
+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int);
if (*(const int*)optval) {
netconn_set_ipv6only(sock->conn, 1);
} else {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
+#if 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;
+ ip_addr_ip4_from_mapped_ip6(&dest_ipv4, dst_ip);
+#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UP
+ 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 && CHECKSUM_GEN_UP */
+ }
+#endif /* LWIP_IPV4 && LWIP_IPV6 */
+
#if LWIP_IPV6 || (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS)
if (ip_addr_ismulticast(dst_ip_route)) {
#if LWIP_IPV6
#define IP_IS_V6_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V6)
#define IP_IS_V6(ipaddr) (((ipaddr) != NULL) && IP_IS_V6_VAL(*(ipaddr)))
+
+#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))
+
#define IP_SET_TYPE_VAL(ipaddr, iptype) do { (ipaddr).type = (iptype); }while(0)
#define IP_SET_TYPE(ipaddr, iptype) do { if((ipaddr) != NULL) { IP_SET_TYPE_VAL(*(ipaddr), iptype); }}while(0)
#define IP_GET_TYPE(ipaddr) ((ipaddr)->type)
((IP_IS_V6(addr)) ? ip6addr_ntoa_r(ip_2_ip6(addr), buf, buflen) : ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen)))
int ipaddr_aton(const char *cp, ip_addr_t *addr);
+/* Map an IPv4 ip_addr into an IPV6 ip_addr, using format
+ defined in RFC4291 2.5.5.2.
+
+ Safe to call when dest==src.
+*/
+#define ip_addr_make_ip4_mapped_ip6(dest, src) do { \
+ u32_t tmp = ip_2_ip4(src)->addr; \
+ IP_ADDR6((dest), 0x0, 0x0, htonl(0x0000FFFF), tmp); \
+ } while(0)
+
+/* Convert an IPv4 mapped V6 address to an IPV4 address.
+
+ Check IP_IS_V4MAPPEDV6(src) before using this.
+
+ Safe to call when dest == src.
+*/
+#define ip_addr_ip4_from_mapped_ip6(dest, src) do { \
+ ip_2_ip4(dest)->addr = ip_2_ip6(src)->addr[3]; \
+ IP_SET_TYPE(dest, IPADDR_TYPE_V4); \
+ } while(0)
+
#else /* LWIP_IPV4 && LWIP_IPV6 */
#define IP_ADDR_PCB_VERSION_MATCH(addr, pcb) 1