xref: /minix/minix/net/lwip/addr.c (revision bb9622b5)
1 /* LWIP service - addr.c - socket address verification and conversion */
2 
3 #include "lwip.h"
4 
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)
11 {
12 
13 	return (addr_len >= offsetof(struct sockaddr, sa_data) &&
14 	    addr->sa_family == AF_UNSPEC);
15 }
16 
17 /*
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.
23  */
24 int
25 addr_is_valid_multicast(const ip_addr_t * ipaddr)
26 {
27 	uint8_t scope;
28 
29 	assert(ip_addr_ismulticast(ipaddr));
30 
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));
34 
35 		if (scope == IP6_MULTICAST_SCOPE_RESERVED0 ||
36 		    scope == IP6_MULTICAST_SCOPE_RESERVEDF)
37 			return FALSE;
38 
39 		/*
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.
45 		 */
46 		if (ip_2_ip6(ipaddr)->addr[0] & PP_HTONL(0x00800000UL))
47 			return FALSE;
48 
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;
53 	}
54 
55 	return TRUE;
56 }
57 
58 /*
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.
74  */
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)
78 {
79 	struct sockaddr_in sin;
80 	struct sockaddr_in6 sin6;
81 	ip6_addr_t *ip6addr;
82 	uint32_t ifindex;
83 
84 	switch (type) {
85 	case IPADDR_TYPE_V4:
86 		if (addr_len != sizeof(sin))
87 			return EINVAL;
88 
89 		/*
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..
93 		 */
94 		memcpy(&sin, addr, sizeof(sin));
95 
96 		if (sin.sin_family != AF_INET)
97 			return EAFNOSUPPORT;
98 
99 		ip_addr_set_ip4_u32(ipaddr, sin.sin_addr.s_addr);
100 
101 		if (port != NULL)
102 			*port = ntohs(sin.sin_port);
103 
104 		return OK;
105 
106 	case IPADDR_TYPE_ANY:
107 	case IPADDR_TYPE_V6:
108 		if (addr_len != sizeof(sin6))
109 			return EINVAL;
110 
111 		/* Again, strict aliasing.. */
112 		memcpy(&sin6, addr, sizeof(sin6));
113 
114 		if (sin6.sin6_family != AF_INET6)
115 			return EAFNOSUPPORT;
116 
117 		memset(ipaddr, 0, sizeof(*ipaddr));
118 
119 		/*
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..
123 		 */
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));
127 
128 		/*
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.
133 		 */
134 		if (ip6_addr_has_scope(ip6addr, IP6_UNKNOWN)) {
135 			if (kame) {
136 				ifindex =
137 				    ntohl(ip6addr->addr[0]) & 0x0000ffffUL;
138 
139 				ip6addr->addr[0] &= PP_HTONL(0xffff0000UL);
140 			} else {
141 				/*
142 				 * Reject KAME-style addresses for normal
143 				 * socket calls, to save ourselves the trouble
144 				 * of mixed address styles elsewhere.
145 				 */
146 				if (ip6addr->addr[0] & PP_HTONL(0x0000ffffUL))
147 					return EINVAL;
148 
149 				ifindex = sin6.sin6_scope_id;
150 			}
151 
152 			/*
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.
157 			 */
158 			if (ifindex != 0 &&
159 			    ifdev_get_by_index(ifindex) == NULL)
160 				return ENXIO;
161 
162 			ip6_addr_set_zone(ip6addr, ifindex);
163 		} else
164 			ip6_addr_clear_zone(ip6addr);
165 
166 		/*
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.
172 		 */
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);
177 
178 		if (port != NULL)
179 			*port = ntohs(sin6.sin6_port);
180 
181 		return OK;
182 
183 	default:
184 		return EAFNOSUPPORT;
185 	}
186 }
187 
188 /*
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.
201  */
202 void
203 addr_put_inet(struct sockaddr * addr, socklen_t * addr_len,
204 	const ip_addr_t * ipaddr, int kame, uint16_t port)
205 {
206 	struct sockaddr_in sin;
207 	struct sockaddr_in6 sin6;
208 	const ip6_addr_t *ip6addr;
209 	uint32_t zone;
210 
211 	switch (IP_GET_TYPE(ipaddr)) {
212 	case IPADDR_TYPE_V4:
213 		if (*addr_len < sizeof(sin))
214 			panic("provided address buffer too small");
215 
216 		memset(&sin, 0, sizeof(sin));
217 
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);
222 
223 		memcpy(addr, &sin, sizeof(sin));
224 		*addr_len = sizeof(sin);
225 
226 		break;
227 
228 	case IPADDR_TYPE_ANY:
229 	case IPADDR_TYPE_V6:
230 		if (*addr_len < sizeof(sin6))
231 			panic("provided address buffer too small");
232 
233 		ip6addr = ip_2_ip6(ipaddr);
234 
235 		memset(&sin6, 0, sizeof(sin6));
236 
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));
241 
242 		/*
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.
249 		 */
250 		if (ip6_addr_has_zone(ip6addr)) {
251 			assert(ip6_addr_has_scope(ip6addr, IP6_UNKNOWN));
252 
253 			zone = ip6_addr_zone(ip6addr);
254 			assert(zone <= UINT8_MAX);
255 
256 			if (kame)
257 				sin6.sin6_addr.s6_addr[3] = zone;
258 			else
259 				sin6.sin6_scope_id = zone;
260 		}
261 
262 		memcpy(addr, &sin6, sizeof(sin6));
263 		*addr_len = sizeof(sin6);
264 
265 		break;
266 
267 	default:
268 		panic("unknown IP address type: %u", IP_GET_TYPE(ipaddr));
269 	}
270 }
271 
272 /*
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.
282  */
283 int
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)
286 {
287 	struct sockaddr_dlx sdlx;
288 	size_t nlen, alen;
289 
290 	if (addr_len < offsetof(struct sockaddr_dlx, sdlx_data))
291 		return EINVAL;
292 
293 	/*
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.
297 	 */
298 	if (addr_len > sizeof(sdlx))
299 		addr_len = sizeof(sdlx);
300 
301 	memcpy(&sdlx, addr, addr_len);
302 
303 	if (sdlx.sdlx_family != AF_LINK)
304 		return EAFNOSUPPORT;
305 
306 	/* Address selectors are not currently supported. */
307 	if (sdlx.sdlx_slen != 0)
308 		return EINVAL;
309 
310 	nlen = (size_t)sdlx.sdlx_nlen;
311 	alen = (size_t)sdlx.sdlx_alen;
312 
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;
316 
317 	/*
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.
321 	 */
322 	if (name != NULL) {
323 		assert(name_max > 0);
324 
325 		if (name_max > nlen + 1)
326 			name_max = nlen + 1;
327 
328 		memcpy(name, sdlx.sdlx_data, name_max - 1);
329 		name[name_max - 1] = '\0';
330 	}
331 
332 	/*
333 	 * Copy over the hardware address.  For simplicity, we require that the
334 	 * caller specify the exact hardware address length.
335 	 */
336 	if (hwaddr != NULL) {
337 		if (alen != hwaddr_len)
338 			return EINVAL;
339 
340 		memcpy(hwaddr, sdlx.sdlx_data + nlen, hwaddr_len);
341 	}
342 
343 	return OK;
344 }
345 
346 /*
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.
358  */
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)
363 {
364 	struct sockaddr_dlx sdlx;
365 	size_t name_len;
366 	socklen_t len;
367 
368 	name_len = (name != NULL) ? strlen(name) : 0;
369 
370 	if (hwaddr == NULL)
371 		hwaddr_len = 0;
372 
373 	assert(name_len < IFNAMSIZ);
374 	assert(hwaddr_len <= NETIF_MAX_HWADDR_LEN);
375 
376 	len = offsetof(struct sockaddr_dlx, sdlx_data) + name_len + hwaddr_len;
377 
378 	if (*addr_len < len)
379 		panic("provided address buffer too small");
380 
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);
392 
393 	memcpy(addr, &sdlx, len);
394 	*addr_len = len;
395 }
396 
397 /*
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.
407  */
408 int
409 addr_get_netmask(const struct sockaddr * addr, socklen_t addr_len,
410 	uint8_t type, unsigned int * prefix, ip_addr_t * ipaddr)
411 {
412 	struct sockaddr_in sin;
413 	struct sockaddr_in6 sin6;
414 	unsigned int byte, bit;
415 	uint32_t val;
416 
417 	switch (type) {
418 	case IPADDR_TYPE_V4:
419 		if (addr_len != sizeof(sin))
420 			return EINVAL;
421 
422 		memcpy(&sin, addr, sizeof(sin));
423 
424 		if (sin.sin_family != AF_INET)
425 			return EAFNOSUPPORT;
426 
427 		val = ntohl(sin.sin_addr.s_addr);
428 
429 		/* Find the first zero bit. */
430 		for (bit = 0; bit < IP4_BITS; bit++)
431 			if (!(val & (1 << (IP4_BITS - bit - 1))))
432 				break;
433 
434 		*prefix = bit;
435 
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;
440 
441 		if (ipaddr != NULL)
442 			ip_addr_set_ip4_u32(ipaddr, sin.sin_addr.s_addr);
443 
444 		return OK;
445 
446 	case IPADDR_TYPE_V6:
447 		if (addr_len != sizeof(sin6))
448 			return EINVAL;
449 
450 		memcpy(&sin6, addr, sizeof(sin6));
451 
452 		if (sin6.sin6_family != AF_INET6)
453 			return EAFNOSUPPORT;
454 
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;
460 
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;
464 
465 			return OK;
466 		}
467 
468 		for (bit = 0; bit < NBBY; bit++)
469 			if (!(sin6.sin6_addr.s6_addr[byte] &
470 			    (1 << (NBBY - bit - 1))))
471 				break;
472 
473 		*prefix = byte * NBBY + bit;
474 
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;
479 
480 		for (byte++; byte < __arraycount(sin6.sin6_addr.s6_addr);
481 		    byte++)
482 			if (sin6.sin6_addr.s6_addr[byte] != 0)
483 				return EINVAL;
484 
485 		if (ipaddr != NULL) {
486 			ip_addr_set_zero_ip6(ipaddr);
487 
488 			memcpy(ip_2_ip6(ipaddr)->addr, &sin6.sin6_addr,
489 			    sizeof(ip_2_ip6(ipaddr)->addr));
490 		}
491 
492 		return OK;
493 
494 	default:
495 		panic("unknown IP address type: %u", type);
496 	}
497 }
498 
499 /*
500  * Generate a raw network mask based on the given prefix length.
501  */
502 void
503 addr_make_netmask(uint8_t * addr, socklen_t addr_len, unsigned int prefix)
504 {
505 	unsigned int byte, bit;
506 
507 	byte = prefix / NBBY;
508 	bit = prefix % NBBY;
509 
510 	assert(byte + !!bit <= addr_len);
511 
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);
518 }
519 
520 /*
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.
527  */
528 void
529 addr_put_netmask(struct sockaddr * addr, socklen_t * addr_len, uint8_t type,
530 	unsigned int prefix)
531 {
532 	struct sockaddr_in sin;
533 	struct sockaddr_in6 sin6;
534 
535 	switch (type) {
536 	case IPADDR_TYPE_V4:
537 		if (*addr_len < sizeof(sin))
538 			panic("provided address buffer too small");
539 
540 		assert(prefix <= IP4_BITS);
541 
542 		memset(&sin, 0, sizeof(sin));
543 		sin.sin_len = sizeof(sin);
544 		sin.sin_family = AF_INET;
545 
546 		addr_make_netmask((uint8_t *)&sin.sin_addr.s_addr,
547 		    sizeof(sin.sin_addr.s_addr), prefix);
548 
549 		memcpy(addr, &sin, sizeof(sin));
550 		*addr_len = sizeof(sin);
551 
552 		break;
553 
554 	case IPADDR_TYPE_V6:
555 		if (*addr_len < sizeof(sin6))
556 			panic("provided address buffer too small");
557 
558 		assert(prefix <= IP6_BITS);
559 
560 		memset(&sin6, 0, sizeof(sin6));
561 		sin6.sin6_len = sizeof(sin6);
562 		sin6.sin6_family = AF_INET6;
563 
564 		addr_make_netmask(sin6.sin6_addr.s6_addr,
565 		    sizeof(sin6.sin6_addr.s6_addr), prefix);
566 
567 		memcpy(addr, &sin6, sizeof(sin6));
568 		*addr_len = sizeof(sin6);
569 
570 		break;
571 
572 	default:
573 		panic("unknown IP address type: %u", type);
574 	}
575 }
576 
577 /*
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'.
580  */
581 void
582 addr_normalize(ip_addr_t * dst, const ip_addr_t * src, unsigned int prefix)
583 {
584 	unsigned int addr_len, byte, bit;
585 	const uint8_t *srcaddr;
586 	uint8_t type, *dstaddr;
587 
588 	type = IP_GET_TYPE(src);
589 
590 	memset(dst, 0, sizeof(*dst));
591 	IP_SET_TYPE(dst, type);
592 
593 	switch (type) {
594 	case IPADDR_TYPE_V4:
595 		srcaddr = (const uint8_t *)&ip_2_ip4(src)->addr;
596 		dstaddr = (uint8_t *)&ip_2_ip4(dst)->addr;
597 		addr_len = sizeof(ip_2_ip4(src)->addr);
598 
599 		break;
600 
601 	case IPADDR_TYPE_V6:
602 		ip6_addr_set_zone(ip_2_ip6(dst), ip6_addr_zone(ip_2_ip6(src)));
603 
604 		srcaddr = (const uint8_t *)&ip_2_ip6(src)->addr;
605 		dstaddr = (uint8_t *)&ip_2_ip6(dst)->addr;
606 		addr_len = sizeof(ip_2_ip6(src)->addr);
607 
608 		break;
609 
610 	default:
611 		panic("unknown IP address type: %u", type);
612 	}
613 
614 	byte = prefix / NBBY;
615 	bit = prefix % NBBY;
616 
617 	assert(byte + !!bit <= addr_len);
618 
619 	if (byte > 0)
620 		memcpy(dstaddr, srcaddr, byte);
621 	if (bit != 0) {
622 		dstaddr[byte] =
623 		    srcaddr[byte] & (uint8_t)(0xff << (NBBY - bit));
624 		byte++;
625 	}
626 }
627 
628 /*
629  * Return the number of common bits between the given two addresses, up to the
630  * given maximum.  Thus, return a value between 0 and 'max' inclusive.
631  */
632 unsigned int
633 addr_get_common_bits(const ip_addr_t * ipaddr1, const ip_addr_t * ipaddr2,
634 	unsigned int max)
635 {
636 	unsigned int addr_len, prefix, bit;
637 	const uint8_t *addr1, *addr2;
638 	uint8_t byte;
639 
640 	switch (IP_GET_TYPE(ipaddr1)) {
641 	case IPADDR_TYPE_V4:
642 		assert(IP_IS_V4(ipaddr2));
643 
644 		addr1 = (const uint8_t *)&ip_2_ip4(ipaddr1)->addr;
645 		addr2 = (const uint8_t *)&ip_2_ip4(ipaddr2)->addr;
646 		addr_len = sizeof(ip_2_ip4(ipaddr1)->addr);
647 
648 		break;
649 
650 	case IPADDR_TYPE_V6:
651 		assert(IP_IS_V6(ipaddr2));
652 
653 		addr1 = (const uint8_t *)&ip_2_ip6(ipaddr1)->addr;
654 		addr2 = (const uint8_t *)&ip_2_ip6(ipaddr2)->addr;
655 		addr_len = sizeof(ip_2_ip6(ipaddr1)->addr);
656 
657 		break;
658 
659 	default:
660 		panic("unknown IP address type: %u", IP_GET_TYPE(ipaddr1));
661 	}
662 
663 	if (addr_len > max * NBBY)
664 		addr_len = max * NBBY;
665 
666 	prefix = 0;
667 
668 	for (prefix = 0; addr_len > 0; addr1++, addr2++, prefix += NBBY) {
669 		if ((byte = (*addr1 ^ *addr2)) != 0) {
670 			/* TODO: see if we want a lookup table for this. */
671 			for (bit = 0; bit < NBBY; bit++, prefix++)
672 				if (byte & (1 << (NBBY - bit - 1)))
673 					break;
674 			break;
675 		}
676 	}
677 
678 	if (prefix > max)
679 		prefix = max;
680 
681 	return prefix;
682 }
683 
684 /*
685  * Convert the given IPv4 address to an IPv4-mapped IPv6 address.
686  */
687 void
688 addr_make_v4mapped_v6(ip_addr_t * dst, const ip4_addr_t * src)
689 {
690 
691 	IP_ADDR6(dst, 0, 0, PP_HTONL(0x0000ffffUL), ip4_addr_get_u32(src));
692 }
693