+/* Convert an AF_INET socket address into the equivalent IPv4-mapped AF_INET6
+ * address.
+ */
+static void map_ipv4_sockaddr(struct sockaddr_in6 *a6,
+ const struct sockaddr_in *a4)
+{
+ size_t i;
+ in_addr_t a = ntohl(a4->sin_addr.s_addr);
+
+ a6->sin6_family = AF_INET6;
+ a6->sin6_port = a4->sin_port;
+ a6->sin6_scope_id = 0;
+ a6->sin6_flowinfo = 0;
+ for (i = 0; i < 10; i++) a6->sin6_addr.s6_addr[i] = 0;
+ for (i = 10; i < 12; i++) a6->sin6_addr.s6_addr[i] = 0xff;
+ for (i = 0; i < 4; i++) a6->sin6_addr.s6_addr[15 - i] = (a >> 8*i)&0xff;
+}
+
+/* Convert an AF_INET6 socket address containing an IPv4-mapped IPv6 address
+ * into the equivalent AF_INET4 address. Return zero on success, or -1 if
+ * the address has the wrong form.
+ */
+static int unmap_ipv4_sockaddr(struct sockaddr_in *a4,
+ const struct sockaddr_in6 *a6)
+{
+ size_t i;
+ in_addr_t a;
+
+ for (i = 0; i < 10; i++) if (a6->sin6_addr.s6_addr[i] != 0) return (-1);
+ for (i = 10; i < 12; i++) if (a6->sin6_addr.s6_addr[i] != 0xff) return (-1);
+ for (i = 0, a = 0; i < 4; i++) a |= a6->sin6_addr.s6_addr[15 - i] << 8*i;
+ a4->sin_family = AF_INET;
+ a4->sin_port = a6->sin6_port;
+ a4->sin_addr.s_addr = htonl(a);
+ return (0);
+}
+