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
addr_is_unspec(const struct sockaddr * addr,socklen_t addr_len)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
addr_is_valid_multicast(const ip_addr_t * ipaddr)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
addr_get_inet(const struct sockaddr * addr,socklen_t addr_len,uint8_t type,ip_addr_t * ipaddr,int kame,uint16_t * port)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
addr_put_inet(struct sockaddr * addr,socklen_t * addr_len,const ip_addr_t * ipaddr,int kame,uint16_t port)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
addr_get_link(const struct sockaddr * addr,socklen_t addr_len,char * name,size_t name_max,uint8_t * hwaddr,size_t hwaddr_len)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
addr_put_link(struct sockaddr * addr,socklen_t * addr_len,uint32_t ifindex,uint32_t type,const char * name,const uint8_t * hwaddr,size_t hwaddr_len)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
addr_get_netmask(const struct sockaddr * addr,socklen_t addr_len,uint8_t type,unsigned int * prefix,ip_addr_t * ipaddr)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
addr_make_netmask(uint8_t * addr,socklen_t addr_len,unsigned int prefix)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
addr_put_netmask(struct sockaddr * addr,socklen_t * addr_len,uint8_t type,unsigned int prefix)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
addr_normalize(ip_addr_t * dst,const ip_addr_t * src,unsigned int prefix)582 addr_normalize(ip_addr_t * dst, const ip_addr_t * src, unsigned int prefix)
583 {
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;
590
591 type = IP_GET_TYPE(src);
592
593 memset(dst, 0, sizeof(*dst));
594 IP_SET_TYPE(dst, type);
595
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) */
603
604 break;
605
606 case IPADDR_TYPE_V6:
607 ip6_addr_set_zone(ip_2_ip6(dst), ip6_addr_zone(ip_2_ip6(src)));
608
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) */
614
615 break;
616
617 default:
618 panic("unknown IP address type: %u", type);
619 }
620
621 byte = prefix / NBBY;
622 bit = prefix % NBBY;
623
624 assert(byte + !!bit <= addr_len);
625
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++;
632 }
633 }
634
635 /*
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.
638 */
639 unsigned int
addr_get_common_bits(const ip_addr_t * ipaddr1,const ip_addr_t * ipaddr2,unsigned int max)640 addr_get_common_bits(const ip_addr_t * ipaddr1, const ip_addr_t * ipaddr2,
641 unsigned int max)
642 {
643 unsigned int addr_len, prefix, bit;
644 const uint8_t *addr1, *addr2;
645 uint8_t byte;
646
647 switch (IP_GET_TYPE(ipaddr1)) {
648 case IPADDR_TYPE_V4:
649 assert(IP_IS_V4(ipaddr2));
650
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);
654
655 break;
656
657 case IPADDR_TYPE_V6:
658 assert(IP_IS_V6(ipaddr2));
659
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);
663
664 break;
665
666 default:
667 panic("unknown IP address type: %u", IP_GET_TYPE(ipaddr1));
668 }
669
670 if (addr_len > max * NBBY)
671 addr_len = max * NBBY;
672
673 prefix = 0;
674
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;
682 }
683 }
684
685 if (prefix > max)
686 prefix = max;
687
688 return prefix;
689 }
690
691 /*
692 * Convert the given IPv4 address to an IPv4-mapped IPv6 address.
693 */
694 void
addr_make_v4mapped_v6(ip_addr_t * dst,const ip4_addr_t * src)695 addr_make_v4mapped_v6(ip_addr_t * dst, const ip4_addr_t * src)
696 {
697
698 IP_ADDR6(dst, 0, 0, PP_HTONL(0x0000ffffUL), ip4_addr_get_u32(src));
699 }
700