* Determine the appropriate scope zone ID for in6 and ifp. If ret_id is * non NULL, it is set to the zone ID. If the zone ID needs to be embedded * in the in6_addr structure, in6 will be modified. * * ret_id - unnecessary? */
| 390 | * ret_id - unnecessary? |
| 391 | */ |
| 392 | int |
| 393 | in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id) |
| 394 | { |
| 395 | int scope; |
| 396 | u_int32_t zoneid = 0; |
| 397 | struct scope6_id *sid; |
| 398 | |
| 399 | /* |
| 400 | * special case: the loopback address can only belong to a loopback |
| 401 | * interface. |
| 402 | */ |
| 403 | if (IN6_IS_ADDR_LOOPBACK(in6)) { |
| 404 | if (!(ifp->if_flags & IFF_LOOPBACK)) |
| 405 | return (EINVAL); |
| 406 | } else { |
| 407 | scope = in6_addrscope(in6); |
| 408 | if (scope == IPV6_ADDR_SCOPE_INTFACELOCAL || |
| 409 | scope == IPV6_ADDR_SCOPE_LINKLOCAL) { |
| 410 | /* |
| 411 | * Currently we use interface indices as the |
| 412 | * zone IDs for interface-local and link-local |
| 413 | * scopes. |
| 414 | */ |
| 415 | zoneid = ifp->if_index; |
| 416 | in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */ |
| 417 | } else if (scope != IPV6_ADDR_SCOPE_GLOBAL) { |
| 418 | struct epoch_tracker et; |
| 419 | |
| 420 | NET_EPOCH_ENTER(et); |
| 421 | if (ifp->if_afdata[AF_INET6] == NULL) { |
| 422 | NET_EPOCH_EXIT(et); |
| 423 | return (ENETDOWN); |
| 424 | } |
| 425 | sid = SID(ifp); |
| 426 | zoneid = sid->s6id_list[scope]; |
| 427 | NET_EPOCH_EXIT(et); |
| 428 | } |
| 429 | } |
| 430 | |
| 431 | if (ret_id != NULL) |
| 432 | *ret_id = zoneid; |
| 433 | |
| 434 | return (0); |
| 435 | } |
| 436 | |
| 437 | /* |
| 438 | * Just clear the embedded scope identifier. Return 0 if the original address |
no test coverage detected