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 #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 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 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