Remove building with NOCRYPTO option
[minix.git] / minix / net / lwip / addr.c
blob246a31fa8700be0c67db7fe85c2ec2721656a5d0
1 /* LWIP service - addr.c - socket address verification and conversion */
3 #include "lwip.h"
5 /*
6 * Return TRUE if the given socket address is of type AF_UNSPEC, or FALSE
7 * otherwise.
8 */
9 int
10 addr_is_unspec(const struct sockaddr * addr, socklen_t addr_len)
13 return (addr_len >= offsetof(struct sockaddr, sa_data) &&
14 addr->sa_family == AF_UNSPEC);
18 * Check whether the given multicast address is generally valid. This check
19 * should not be moved into addr_get_inet(), as we do not want to forbid
20 * creating routes for such addresses, for example. We do however apply the
21 * restrictions here to all provided source and destination addresses. Return
22 * TRUE if the address is an acceptable multicast address, or FALSE otherwise.
24 int
25 addr_is_valid_multicast(const ip_addr_t * ipaddr)
27 uint8_t scope;
29 assert(ip_addr_ismulticast(ipaddr));
31 /* We apply restrictions to IPv6 multicast addresses only. */
32 if (IP_IS_V6(ipaddr)) {
33 scope = ip6_addr_multicast_scope(ip_2_ip6(ipaddr));
35 if (scope == IP6_MULTICAST_SCOPE_RESERVED0 ||
36 scope == IP6_MULTICAST_SCOPE_RESERVEDF)
37 return FALSE;
40 * We do not impose restrictions on the three defined embedded
41 * flags, even though we put no effort into supporting them,
42 * especially in terms of automatically creating routes for
43 * all cases. We do force the fourth flag to be zero.
44 * Unfortunately there is no lwIP macro to check for this flag.
46 if (ip_2_ip6(ipaddr)->addr[0] & PP_HTONL(0x00800000UL))
47 return FALSE;
49 /* Prevent KAME-embedded zone IDs from entering the system. */
50 if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN) &&
51 (ip_2_ip6(ipaddr)->addr[0] & PP_HTONL(0x0000ffffUL)))
52 return FALSE;
55 return TRUE;
59 * Load a sockaddr structure, as copied from userland, as a lwIP-style IP
60 * address and (optionally) a port number. The expected type of IP address is
61 * given as 'type', which must be one of IPADDR_TYPE_{V4,ANY,V6}. If it is
62 * IPADDR_TYPE_V4, 'addr' is expected to point to a sockaddr_in structure. If
63 * it is IPADDR_TYPE_{ANY,V6}, 'addr' is expected to point to a sockaddr_in6
64 * structure. For the _ANY case, the result will be an _ANY address only if it
65 * is the unspecified (all-zeroes) address and a _V6 address in all other
66 * cases. For the _V6 case, the result will always be a _V6 address. The
67 * length of the structure pointed to by 'addr' is given as 'addr_len'. If the
68 * boolean 'kame' flag is set, addresses will be interpreted to be KAME style,
69 * meaning that for scoped IPv6 addresses, the zone is embedded in the address
70 * rather than given in sin6_scope_id. On success, store the resulting IP
71 * address in 'ipaddr'. If 'port' is not NULL, store the port number in it;
72 * otherwise, ignore the port number. On any parsing failure, return an
73 * appropriate negative error code.
75 int
76 addr_get_inet(const struct sockaddr * addr, socklen_t addr_len, uint8_t type,
77 ip_addr_t * ipaddr, int kame, uint16_t * port)
79 struct sockaddr_in sin;
80 struct sockaddr_in6 sin6;
81 ip6_addr_t *ip6addr;
82 uint32_t ifindex;
84 switch (type) {
85 case IPADDR_TYPE_V4:
86 if (addr_len != sizeof(sin))
87 return EINVAL;
90 * Getting around strict aliasing problems. Oh, the irony of
91 * doing an extra memcpy so that the compiler can do a better
92 * job at optimizing..
94 memcpy(&sin, addr, sizeof(sin));
96 if (sin.sin_family != AF_INET)
97 return EAFNOSUPPORT;
99 ip_addr_set_ip4_u32(ipaddr, sin.sin_addr.s_addr);
101 if (port != NULL)
102 *port = ntohs(sin.sin_port);
104 return OK;
106 case IPADDR_TYPE_ANY:
107 case IPADDR_TYPE_V6:
108 if (addr_len != sizeof(sin6))
109 return EINVAL;
111 /* Again, strict aliasing.. */
112 memcpy(&sin6, addr, sizeof(sin6));
114 if (sin6.sin6_family != AF_INET6)
115 return EAFNOSUPPORT;
117 memset(ipaddr, 0, sizeof(*ipaddr));
120 * This is a bit ugly, but NetBSD does not expose s6_addr32 and
121 * s6_addr is a series of bytes, which is a mismatch for lwIP.
122 * The alternative would be another memcpy..
124 ip6addr = ip_2_ip6(ipaddr);
125 assert(sizeof(ip6addr->addr) == sizeof(sin6.sin6_addr));
126 memcpy(ip6addr->addr, &sin6.sin6_addr, sizeof(ip6addr->addr));
129 * If the address may have a scope, extract the zone ID.
130 * Where the zone ID is depends on the 'kame' parameter: KAME-
131 * style addresses have it embedded within the address, whereas
132 * non-KAME addresses use the (misnamed) sin6_scope_id field.
134 if (ip6_addr_has_scope(ip6addr, IP6_UNKNOWN)) {
135 if (kame) {
136 ifindex =
137 ntohl(ip6addr->addr[0]) & 0x0000ffffUL;
139 ip6addr->addr[0] &= PP_HTONL(0xffff0000UL);
140 } else {
142 * Reject KAME-style addresses for normal
143 * socket calls, to save ourselves the trouble
144 * of mixed address styles elsewhere.
146 if (ip6addr->addr[0] & PP_HTONL(0x0000ffffUL))
147 return EINVAL;
149 ifindex = sin6.sin6_scope_id;
153 * Reject invalid zone IDs. This also enforces that
154 * no zone IDs wider than eight bits enter the system.
155 * As a side effect, it is not possible to add routes
156 * for invalid zones, but that should be no problem.
158 if (ifindex != 0 &&
159 ifdev_get_by_index(ifindex) == NULL)
160 return ENXIO;
162 ip6_addr_set_zone(ip6addr, ifindex);
163 } else
164 ip6_addr_clear_zone(ip6addr);
167 * Set the type to ANY if it was ANY and the address itself is
168 * ANY as well. Otherwise, we are binding to a specific IPv6
169 * address, so IPV6_V6ONLY stops being relevant and we should
170 * leave the address set to V6. Destination addresses for ANY
171 * are set to V6 elsewhere.
173 if (type == IPADDR_TYPE_ANY && ip6_addr_isany(ip6addr))
174 IP_SET_TYPE(ipaddr, type);
175 else
176 IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6);
178 if (port != NULL)
179 *port = ntohs(sin6.sin6_port);
181 return OK;
183 default:
184 return EAFNOSUPPORT;
189 * Store an lwIP-style IP address and port number as a sockaddr structure
190 * (sockaddr_in or sockaddr_in6, depending on the given IP address) to be
191 * copied to userland. The result is stored in the buffer pointed to by
192 * 'addr'. Before the call, 'addr_len' must be set to the size of this buffer.
193 * This is an internal check to prevent buffer overflows, and must not be used
194 * to validate input, since a mismatch will trigger a panic. After the call,
195 * 'addr_len' will be set to the size of the resulting structure. The lwIP-
196 * style address is given as 'ipaddr'. If the boolean 'kame' flag is set, the
197 * address will be stored KAME-style, meaning that for scoped IPv6 addresses,
198 * the address zone will be stored embedded in the address rather than in
199 * sin6_scope_id. If relevant, 'port' contains the port number in host-byte
200 * order; otherwise it should be set to zone.
202 void
203 addr_put_inet(struct sockaddr * addr, socklen_t * addr_len,
204 const ip_addr_t * ipaddr, int kame, uint16_t port)
206 struct sockaddr_in sin;
207 struct sockaddr_in6 sin6;
208 const ip6_addr_t *ip6addr;
209 uint32_t zone;
211 switch (IP_GET_TYPE(ipaddr)) {
212 case IPADDR_TYPE_V4:
213 if (*addr_len < sizeof(sin))
214 panic("provided address buffer too small");
216 memset(&sin, 0, sizeof(sin));
218 sin.sin_len = sizeof(sin);
219 sin.sin_family = AF_INET;
220 sin.sin_port = htons(port);
221 sin.sin_addr.s_addr = ip_addr_get_ip4_u32(ipaddr);
223 memcpy(addr, &sin, sizeof(sin));
224 *addr_len = sizeof(sin);
226 break;
228 case IPADDR_TYPE_ANY:
229 case IPADDR_TYPE_V6:
230 if (*addr_len < sizeof(sin6))
231 panic("provided address buffer too small");
233 ip6addr = ip_2_ip6(ipaddr);
235 memset(&sin6, 0, sizeof(sin6));
237 sin6.sin6_len = sizeof(sin6);
238 sin6.sin6_family = AF_INET6;
239 sin6.sin6_port = htons(port);
240 memcpy(&sin6.sin6_addr, ip6addr->addr, sizeof(sin6.sin6_addr));
243 * If the IPv6 address has a zone set, it must be scoped, and
244 * we put the zone in the result. It may occur that a scoped
245 * IPv6 address does not have a zone here though, for example
246 * if packet routing fails for sendto() with a zoneless address
247 * on an unbound socket, resulting in an RTM_MISS message. In
248 * such cases, simply leave the zone index blank in the result.
250 if (ip6_addr_has_zone(ip6addr)) {
251 assert(ip6_addr_has_scope(ip6addr, IP6_UNKNOWN));
253 zone = ip6_addr_zone(ip6addr);
254 assert(zone <= UINT8_MAX);
256 if (kame)
257 sin6.sin6_addr.s6_addr[3] = zone;
258 else
259 sin6.sin6_scope_id = zone;
262 memcpy(addr, &sin6, sizeof(sin6));
263 *addr_len = sizeof(sin6);
265 break;
267 default:
268 panic("unknown IP address type: %u", IP_GET_TYPE(ipaddr));
273 * Load a link-layer sockaddr structure (sockaddr_dl), as copied from userland,
274 * and return the contained name and/or hardware address. The address is
275 * provided as 'addr', with length 'addr_len'. On success, return OK. If
276 * 'name' is not NULL, it must be of size 'name_max', and will be used to store
277 * the (null-terminated) interface name in the given structure if present, or
278 * the empty string if not. If 'hwaddr' is not NULL, it will be used to store
279 * the hardware address in the given structure, which must in that case be
280 * present and exactly 'hwaddr_len' bytes long. On any parsing failure, return
281 * an appropriate negative error code.
284 addr_get_link(const struct sockaddr * addr, socklen_t addr_len, char * name,
285 size_t name_max, uint8_t * hwaddr, size_t hwaddr_len)
287 struct sockaddr_dlx sdlx;
288 size_t nlen, alen;
290 if (addr_len < offsetof(struct sockaddr_dlx, sdlx_data))
291 return EINVAL;
294 * We cannot prevent callers from passing in massively oversized
295 * sockaddr_dl structure. However, we insist that all the actual data
296 * be contained within the size of our sockaddr_dlx version.
298 if (addr_len > sizeof(sdlx))
299 addr_len = sizeof(sdlx);
301 memcpy(&sdlx, addr, addr_len);
303 if (sdlx.sdlx_family != AF_LINK)
304 return EAFNOSUPPORT;
306 /* Address selectors are not currently supported. */
307 if (sdlx.sdlx_slen != 0)
308 return EINVAL;
310 nlen = (size_t)sdlx.sdlx_nlen;
311 alen = (size_t)sdlx.sdlx_alen;
313 /* The nlen and alen fields are 8-bit, so no risks of overflow here. */
314 if (addr_len < offsetof(struct sockaddr_dlx, sdlx_data) + nlen + alen)
315 return EINVAL;
318 * Copy out the name, truncating it if needed. The name in the
319 * sockaddr is not null terminated, so we have to do that. If the
320 * sockaddr has no name, copy out an empty name.
322 if (name != NULL) {
323 assert(name_max > 0);
325 if (name_max > nlen + 1)
326 name_max = nlen + 1;
328 memcpy(name, sdlx.sdlx_data, name_max - 1);
329 name[name_max - 1] = '\0';
333 * Copy over the hardware address. For simplicity, we require that the
334 * caller specify the exact hardware address length.
336 if (hwaddr != NULL) {
337 if (alen != hwaddr_len)
338 return EINVAL;
340 memcpy(hwaddr, sdlx.sdlx_data + nlen, hwaddr_len);
343 return OK;
347 * Store a link-layer sockaddr structure (sockaddr_dl), to be copied to
348 * userland. The result is stored in the buffer pointed to by 'addr'. Before
349 * the call, 'addr_len' must be set to the size of this buffer. This is an
350 * internal check to prevent buffer overflows, and must not be used to validate
351 * input, since a mismatch will trigger a panic. After the call, 'addr_len'
352 * will be set to the size of the resulting structure. The given interface
353 * index 'ifindex' and (IFT_) interface type 'type' will always be stored in
354 * the resulting structure. If 'name' is not NULL, it must be a null-
355 * terminated interface name string which will be included in the structure.
356 * If 'hwaddr' is not NULL, it must be a hardware address of length
357 * 'hwaddr_len', which will also be included in the structure.
359 void
360 addr_put_link(struct sockaddr * addr, socklen_t * addr_len, uint32_t ifindex,
361 uint32_t type, const char * name, const uint8_t * hwaddr,
362 size_t hwaddr_len)
364 struct sockaddr_dlx sdlx;
365 size_t name_len;
366 socklen_t len;
368 name_len = (name != NULL) ? strlen(name) : 0;
370 if (hwaddr == NULL)
371 hwaddr_len = 0;
373 assert(name_len < IFNAMSIZ);
374 assert(hwaddr_len <= NETIF_MAX_HWADDR_LEN);
376 len = offsetof(struct sockaddr_dlx, sdlx_data) + name_len + hwaddr_len;
378 if (*addr_len < len)
379 panic("provided address buffer too small");
381 memset(&sdlx, 0, sizeof(sdlx));
382 sdlx.sdlx_len = len;
383 sdlx.sdlx_family = AF_LINK;
384 sdlx.sdlx_index = ifindex;
385 sdlx.sdlx_type = type;
386 sdlx.sdlx_nlen = name_len;
387 sdlx.sdlx_alen = hwaddr_len;
388 if (name_len > 0)
389 memcpy(sdlx.sdlx_data, name, name_len);
390 if (hwaddr_len > 0)
391 memcpy(sdlx.sdlx_data + name_len, hwaddr, hwaddr_len);
393 memcpy(addr, &sdlx, len);
394 *addr_len = len;
398 * Convert an IPv4 or IPv6 netmask, given as sockaddr structure 'addr', to a
399 * prefix length. The length of the sockaddr structure is given as 'addr_len'.
400 * For consistency with addr_get_inet(), the expected address type is given as
401 * 'type', and must be either IPADDR_TYPE_V4 or IPADDR_TYPE_V6. On success,
402 * return OK with the number of set prefix bits returned in 'prefix', and
403 * optionally with a lwIP representation of the netmask stored in 'ipaddr' (if
404 * not NULL). On failure, return an appropriate negative error code. Note
405 * that this function does not support compressed IPv4 network masks; such
406 * addresses must be expanded before a call to this function.
409 addr_get_netmask(const struct sockaddr * addr, socklen_t addr_len,
410 uint8_t type, unsigned int * prefix, ip_addr_t * ipaddr)
412 struct sockaddr_in sin;
413 struct sockaddr_in6 sin6;
414 unsigned int byte, bit;
415 uint32_t val;
417 switch (type) {
418 case IPADDR_TYPE_V4:
419 if (addr_len != sizeof(sin))
420 return EINVAL;
422 memcpy(&sin, addr, sizeof(sin));
424 if (sin.sin_family != AF_INET)
425 return EAFNOSUPPORT;
427 val = ntohl(sin.sin_addr.s_addr);
429 /* Find the first zero bit. */
430 for (bit = 0; bit < IP4_BITS; bit++)
431 if (!(val & (1 << (IP4_BITS - bit - 1))))
432 break;
434 *prefix = bit;
436 /* All bits after the first zero bit must also be zero. */
437 if (bit < IP4_BITS &&
438 (val & ((1 << (IP4_BITS - bit - 1)) - 1)))
439 return EINVAL;
441 if (ipaddr != NULL)
442 ip_addr_set_ip4_u32(ipaddr, sin.sin_addr.s_addr);
444 return OK;
446 case IPADDR_TYPE_V6:
447 if (addr_len != sizeof(sin6))
448 return EINVAL;
450 memcpy(&sin6, addr, sizeof(sin6));
452 if (sin6.sin6_family != AF_INET6)
453 return EAFNOSUPPORT;
455 /* Find the first zero bit. */
456 for (byte = 0; byte < __arraycount(sin6.sin6_addr.s6_addr);
457 byte++)
458 if (sin6.sin6_addr.s6_addr[byte] != 0xff)
459 break;
461 /* If all bits are set, there is nothing more to do. */
462 if (byte == __arraycount(sin6.sin6_addr.s6_addr)) {
463 *prefix = __arraycount(sin6.sin6_addr.s6_addr) * NBBY;
465 return OK;
468 for (bit = 0; bit < NBBY; bit++)
469 if (!(sin6.sin6_addr.s6_addr[byte] &
470 (1 << (NBBY - bit - 1))))
471 break;
473 *prefix = byte * NBBY + bit;
475 /* All bits after the first zero bit must also be zero. */
476 if (bit < NBBY && (sin6.sin6_addr.s6_addr[byte] &
477 ((1 << (NBBY - bit - 1)) - 1)))
478 return EINVAL;
480 for (byte++; byte < __arraycount(sin6.sin6_addr.s6_addr);
481 byte++)
482 if (sin6.sin6_addr.s6_addr[byte] != 0)
483 return EINVAL;
485 if (ipaddr != NULL) {
486 ip_addr_set_zero_ip6(ipaddr);
488 memcpy(ip_2_ip6(ipaddr)->addr, &sin6.sin6_addr,
489 sizeof(ip_2_ip6(ipaddr)->addr));
492 return OK;
494 default:
495 panic("unknown IP address type: %u", type);
500 * Generate a raw network mask based on the given prefix length.
502 void
503 addr_make_netmask(uint8_t * addr, socklen_t addr_len, unsigned int prefix)
505 unsigned int byte, bit;
507 byte = prefix / NBBY;
508 bit = prefix % NBBY;
510 assert(byte + !!bit <= addr_len);
512 if (byte > 0)
513 memset(addr, 0xff, byte);
514 if (bit != 0)
515 addr[byte++] = (uint8_t)(0xff << (NBBY - bit));
516 if (byte < addr_len)
517 memset(&addr[byte], 0, addr_len - byte);
521 * Store a network mask as a sockaddr structure, in 'addr'. Before the call,
522 * 'addr_len' must be set to the memory size of 'addr'. The address type is
523 * given as 'type', and must be either IPADDR_TYPE_V4 or IPADDR_TYPE_V6. The
524 * prefix length from which to generate the network mask is given as 'prefix'.
525 * Upon return, 'addr_len' is set to the size of the resulting sockaddr
526 * structure.
528 void
529 addr_put_netmask(struct sockaddr * addr, socklen_t * addr_len, uint8_t type,
530 unsigned int prefix)
532 struct sockaddr_in sin;
533 struct sockaddr_in6 sin6;
535 switch (type) {
536 case IPADDR_TYPE_V4:
537 if (*addr_len < sizeof(sin))
538 panic("provided address buffer too small");
540 assert(prefix <= IP4_BITS);
542 memset(&sin, 0, sizeof(sin));
543 sin.sin_len = sizeof(sin);
544 sin.sin_family = AF_INET;
546 addr_make_netmask((uint8_t *)&sin.sin_addr.s_addr,
547 sizeof(sin.sin_addr.s_addr), prefix);
549 memcpy(addr, &sin, sizeof(sin));
550 *addr_len = sizeof(sin);
552 break;
554 case IPADDR_TYPE_V6:
555 if (*addr_len < sizeof(sin6))
556 panic("provided address buffer too small");
558 assert(prefix <= IP6_BITS);
560 memset(&sin6, 0, sizeof(sin6));
561 sin6.sin6_len = sizeof(sin6);
562 sin6.sin6_family = AF_INET6;
564 addr_make_netmask(sin6.sin6_addr.s6_addr,
565 sizeof(sin6.sin6_addr.s6_addr), prefix);
567 memcpy(addr, &sin6, sizeof(sin6));
568 *addr_len = sizeof(sin6);
570 break;
572 default:
573 panic("unknown IP address type: %u", type);
578 * Normalize the given address in 'src' to the given number of prefix bits,
579 * setting all other bits to zero. Return the result in 'dst'.
581 void
582 addr_normalize(ip_addr_t * dst, const ip_addr_t * src, unsigned int prefix)
584 #if !defined(NDEBUG)
585 unsigned int addr_len;
586 #endif /* !defined(NDEBUG) */
587 unsigned int byte, bit;
588 const uint8_t *srcaddr;
589 uint8_t type, *dstaddr;
591 type = IP_GET_TYPE(src);
593 memset(dst, 0, sizeof(*dst));
594 IP_SET_TYPE(dst, type);
596 switch (type) {
597 case IPADDR_TYPE_V4:
598 srcaddr = (const uint8_t *)&ip_2_ip4(src)->addr;
599 dstaddr = (uint8_t *)&ip_2_ip4(dst)->addr;
600 #if !defined(NDEBUG)
601 addr_len = sizeof(ip_2_ip4(src)->addr);
602 #endif /* !defined(NDEBUG) */
604 break;
606 case IPADDR_TYPE_V6:
607 ip6_addr_set_zone(ip_2_ip6(dst), ip6_addr_zone(ip_2_ip6(src)));
609 srcaddr = (const uint8_t *)&ip_2_ip6(src)->addr;
610 dstaddr = (uint8_t *)&ip_2_ip6(dst)->addr;
611 #if !defined(NDEBUG)
612 addr_len = sizeof(ip_2_ip6(src)->addr);
613 #endif /* !defined(NDEBUG) */
615 break;
617 default:
618 panic("unknown IP address type: %u", type);
621 byte = prefix / NBBY;
622 bit = prefix % NBBY;
624 assert(byte + !!bit <= addr_len);
626 if (byte > 0)
627 memcpy(dstaddr, srcaddr, byte);
628 if (bit != 0) {
629 dstaddr[byte] =
630 srcaddr[byte] & (uint8_t)(0xff << (NBBY - bit));
631 byte++;
636 * Return the number of common bits between the given two addresses, up to the
637 * given maximum. Thus, return a value between 0 and 'max' inclusive.
639 unsigned int
640 addr_get_common_bits(const ip_addr_t * ipaddr1, const ip_addr_t * ipaddr2,
641 unsigned int max)
643 unsigned int addr_len, prefix, bit;
644 const uint8_t *addr1, *addr2;
645 uint8_t byte;
647 switch (IP_GET_TYPE(ipaddr1)) {
648 case IPADDR_TYPE_V4:
649 assert(IP_IS_V4(ipaddr2));
651 addr1 = (const uint8_t *)&ip_2_ip4(ipaddr1)->addr;
652 addr2 = (const uint8_t *)&ip_2_ip4(ipaddr2)->addr;
653 addr_len = sizeof(ip_2_ip4(ipaddr1)->addr);
655 break;
657 case IPADDR_TYPE_V6:
658 assert(IP_IS_V6(ipaddr2));
660 addr1 = (const uint8_t *)&ip_2_ip6(ipaddr1)->addr;
661 addr2 = (const uint8_t *)&ip_2_ip6(ipaddr2)->addr;
662 addr_len = sizeof(ip_2_ip6(ipaddr1)->addr);
664 break;
666 default:
667 panic("unknown IP address type: %u", IP_GET_TYPE(ipaddr1));
670 if (addr_len > max * NBBY)
671 addr_len = max * NBBY;
673 prefix = 0;
675 for (prefix = 0; addr_len > 0; addr1++, addr2++, prefix += NBBY) {
676 if ((byte = (*addr1 ^ *addr2)) != 0) {
677 /* TODO: see if we want a lookup table for this. */
678 for (bit = 0; bit < NBBY; bit++, prefix++)
679 if (byte & (1 << (NBBY - bit - 1)))
680 break;
681 break;
685 if (prefix > max)
686 prefix = max;
688 return prefix;
692 * Convert the given IPv4 address to an IPv4-mapped IPv6 address.
694 void
695 addr_make_v4mapped_v6(ip_addr_t * dst, const ip4_addr_t * src)
698 IP_ADDR6(dst, 0, 0, PP_HTONL(0x0000ffffUL), ip4_addr_get_u32(src));