* Look up rt_addrinfo for a specific fib. Note that if rti_ifa is defined, * it will be referenced so the caller must free it. * * Assume basic consistency checks are executed by callers: * RTAX_DST exists, if RTF_GATEWAY is set, RTAX_GATEWAY exists as well. */
| 510 | * RTAX_DST exists, if RTF_GATEWAY is set, RTAX_GATEWAY exists as well. |
| 511 | */ |
| 512 | int |
| 513 | rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) |
| 514 | { |
| 515 | const struct sockaddr *dst, *gateway, *ifpaddr, *ifaaddr; |
| 516 | struct epoch_tracker et; |
| 517 | int needref, error, flags; |
| 518 | |
| 519 | dst = info->rti_info[RTAX_DST]; |
| 520 | gateway = info->rti_info[RTAX_GATEWAY]; |
| 521 | ifpaddr = info->rti_info[RTAX_IFP]; |
| 522 | ifaaddr = info->rti_info[RTAX_IFA]; |
| 523 | flags = info->rti_flags; |
| 524 | |
| 525 | /* |
| 526 | * ifp may be specified by sockaddr_dl |
| 527 | * when protocol address is ambiguous. |
| 528 | */ |
| 529 | error = 0; |
| 530 | needref = (info->rti_ifa == NULL); |
| 531 | NET_EPOCH_ENTER(et); |
| 532 | |
| 533 | /* If we have interface specified by the ifindex in the address, use it */ |
| 534 | if (info->rti_ifp == NULL && ifpaddr != NULL && |
| 535 | ifpaddr->sa_family == AF_LINK) { |
| 536 | const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)ifpaddr; |
| 537 | if (sdl->sdl_index != 0) |
| 538 | info->rti_ifp = ifnet_byindex(sdl->sdl_index); |
| 539 | } |
| 540 | /* |
| 541 | * If we have source address specified, try to find it |
| 542 | * TODO: avoid enumerating all ifas on all interfaces. |
| 543 | */ |
| 544 | if (info->rti_ifa == NULL && ifaaddr != NULL) |
| 545 | info->rti_ifa = ifa_ifwithaddr(ifaaddr); |
| 546 | if (info->rti_ifa == NULL) { |
| 547 | const struct sockaddr *sa; |
| 548 | |
| 549 | /* |
| 550 | * Most common use case for the userland-supplied routes. |
| 551 | * |
| 552 | * Choose sockaddr to select ifa. |
| 553 | * -- if ifp is set -- |
| 554 | * Order of preference: |
| 555 | * 1) IFA address |
| 556 | * 2) gateway address |
| 557 | * Note: for interface routes link-level gateway address |
| 558 | * is specified to indicate the interface index without |
| 559 | * specifying RTF_GATEWAY. In this case, ignore gateway |
| 560 | * Note: gateway AF may be different from dst AF. In this case, |
| 561 | * ignore gateway |
| 562 | * 3) final destination. |
| 563 | * 4) if all of these fails, try to get at least link-level ifa. |
| 564 | * -- else -- |
| 565 | * try to lookup gateway or dst in the routing table to get ifa |
| 566 | */ |
| 567 | if (info->rti_info[RTAX_IFA] != NULL) |
| 568 | sa = info->rti_info[RTAX_IFA]; |
| 569 | else if ((info->rti_flags & RTF_GATEWAY) != 0 && |
no test coverage detected