* This function is for checking sockaddr_in6 structure passed * from the application level (usually). * * sin6_scope_id should be set for link-local unicast, link-local and * interface-local multicast addresses. * * If it is zero, then look into default zone ids. If default zone id is * not set or disabled, then return error. */
| 540 | * not set or disabled, then return error. |
| 541 | */ |
| 542 | int |
| 543 | sa6_checkzone(struct sockaddr_in6 *sa6) |
| 544 | { |
| 545 | int scope; |
| 546 | |
| 547 | scope = in6_addrscope(&sa6->sin6_addr); |
| 548 | if (scope == IPV6_ADDR_SCOPE_GLOBAL) |
| 549 | return (sa6->sin6_scope_id ? EINVAL: 0); |
| 550 | if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr) && |
| 551 | scope != IPV6_ADDR_SCOPE_LINKLOCAL && |
| 552 | scope != IPV6_ADDR_SCOPE_INTFACELOCAL) { |
| 553 | if (sa6->sin6_scope_id == 0 && V_ip6_use_defzone != 0) |
| 554 | sa6->sin6_scope_id = V_sid_default.s6id_list[scope]; |
| 555 | return (0); |
| 556 | } |
| 557 | /* |
| 558 | * Since ::1 address always configured on the lo0, we can |
| 559 | * automatically set its zone id, when it is not specified. |
| 560 | * Return error, when specified zone id doesn't match with |
| 561 | * actual value. |
| 562 | */ |
| 563 | if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) { |
| 564 | if (sa6->sin6_scope_id == 0) |
| 565 | sa6->sin6_scope_id = in6_getscopezone(V_loif, scope); |
| 566 | else if (sa6->sin6_scope_id != in6_getscopezone(V_loif, scope)) |
| 567 | return (EADDRNOTAVAIL); |
| 568 | } |
| 569 | /* XXX: we can validate sin6_scope_id here */ |
| 570 | if (sa6->sin6_scope_id != 0) |
| 571 | return (0); |
| 572 | if (V_ip6_use_defzone != 0) |
| 573 | sa6->sin6_scope_id = V_sid_default.s6id_list[scope]; |
| 574 | /* Return error if we can't determine zone id */ |
| 575 | return (sa6->sin6_scope_id ? 0: EADDRNOTAVAIL); |
| 576 | } |
| 577 | |
| 578 | /* |
| 579 | * This function is similar to sa6_checkzone, but it uses given ifp |
no test coverage detected