/* * XXX: ip6_route is too eager to return single/default netif, and * forwarding logic is different from the logic to select outgoing * interface for our own packets anyway. */ static struct netif * ip6_route_fwd(struct ip6_addr *dest) { struct netif *netif; s8_t i; /* Link-local addresses are not routable. */ if (ip6_addr_islinklocal(dest)) { return NULL; } /* See if the destination subnet matches a configured address. */ for(netif = netif_list; netif != NULL; netif = netif->next) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { return netif; } } } /* Get the netif for a suitable router. */ i = nd6_select_router(dest, NULL); if (i >= 0) { if (default_router_list[i].neighbor_entry != NULL) { if (default_router_list[i].neighbor_entry->netif != NULL) { return default_router_list[i].neighbor_entry->netif; } } } /* no matching netif found */ return NULL; }
/** * Finds the appropriate network interface for a given IPv6 address. It tries to select * a netif following a sequence of heuristics: * 1) if there is only 1 netif, return it * 2) if the destination is a link-local address, try to match the src address to a netif. * this is a tricky case because with multiple netifs, link-local addresses only have * meaning within a particular subnet/link. * 3) tries to match the destination subnet to a configured address * 4) tries to find a router * 5) tries to match the source address to the netif * 6) returns the default netif, if configured * * @param src the source IPv6 address, if known * @param dest the destination IPv6 address for which to find the route * @return the netif on which to send to reach dest */ struct netif * ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) { struct netif *netif; s8_t i; #ifdef LWIP_HOOK_IP6_ROUTE netif = LWIP_HOOK_IP6_ROUTE(src, dest); if (netif != NULL) { return netif; } #endif /* If single netif configuration, fast return. */ if ((netif_list != NULL) && (netif_list->next == NULL)) { if (!netif_is_up(netif_list) || !netif_is_link_up(netif_list)) { return NULL; } return netif_list; } /* Special processing for link-local addresses. */ if (ip6_addr_islinklocal(dest)) { if (ip6_addr_isany(src)) { /* Use default netif, if Up. */ if (!netif_is_up(netif_default) || !netif_is_link_up(netif_default)) { return NULL; } return netif_default; } /* Try to find the netif for the source address, checking that link is up. */ for (netif = netif_list; netif != NULL; netif = netif->next) { if (!netif_is_up(netif) || !netif_is_link_up(netif)) { continue; } for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_cmp(src, netif_ip6_addr(netif, i))) { return netif; } } } /* netif not found, use default netif, if up */ if (!netif_is_up(netif_default) || !netif_is_link_up(netif_default)) { return NULL; } return netif_default; } /* See if the destination subnet matches a configured address. */ for (netif = netif_list; netif != NULL; netif = netif->next) { if (!netif_is_up(netif) || !netif_is_link_up(netif)) { continue; } for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { return netif; } } } /* Get the netif for a suitable router. */ i = nd6_select_router(dest, NULL); if (i >= 0) { if (default_router_list[i].neighbor_entry != NULL) { if (default_router_list[i].neighbor_entry->netif != NULL) { if (netif_is_up(default_router_list[i].neighbor_entry->netif) && netif_is_link_up(default_router_list[i].neighbor_entry->netif)) { return default_router_list[i].neighbor_entry->netif; } } } } /* try with the netif that matches the source address. */ if (!ip6_addr_isany(src)) { for (netif = netif_list; netif != NULL; netif = netif->next) { if (!netif_is_up(netif) || !netif_is_link_up(netif)) { continue; } for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_cmp(src, netif_ip6_addr(netif, i))) { return netif; } } } } #if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF /* loopif is disabled, loopback traffic is passed through any netif */ if (ip6_addr_isloopback(dest)) { /* don't check for link on loopback traffic */ if (netif_is_up(netif_default)) { return netif_default; } /* default netif is not up, just use any netif for loopback traffic */ for (netif = netif_list; netif != NULL; netif = netif->next) { if (netif_is_up(netif)) { return netif; } } return NULL; } #endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */ /* no matching netif found, use default netif, if up */ if (!netif_is_up(netif_default) || !netif_is_link_up(netif_default)) { return NULL; } return netif_default; }
/** * Finds the appropriate network interface for a given IPv6 address. It tries to select * a netif following a sequence of heuristics: * 1) if there is only 1 netif, return it * 2) if the destination is a link-local address, try to match the src address to a netif. * this is a tricky case because with multiple netifs, link-local addresses only have * meaning within a particular subnet/link. * 3) tries to match the destination subnet to a configured address * 4) tries to find a router * 5) tries to match the source address to the netif * 6) returns the default netif, if configured * * @param src the source IPv6 address, if known * @param dest the destination IPv6 address for which to find the route * @return the netif on which to send to reach dest */ struct netif * ip6_route(struct ip6_addr *src, struct ip6_addr *dest) { struct netif *netif; s8_t i; /* If single netif configuration, fast return. */ if ((netif_list != NULL) && (netif_list->next == NULL)) { return netif_list; } /* Special processing for link-local addresses. */ if (ip6_addr_islinklocal(dest)) { if (ip6_addr_isany(src)) { /* Use default netif. */ return netif_default; } /* Try to find the netif for the source address. */ for(netif = netif_list; netif != NULL; netif = netif->next) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_cmp(src, netif_ip6_addr(netif, i))) { return netif; } } } /* netif not found, use default netif */ return netif_default; } /* See if the destination subnet matches a configured address. */ for(netif = netif_list; netif != NULL; netif = netif->next) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { return netif; } } } /* Get the netif for a suitable router. */ i = nd6_select_router(dest, NULL); if (i >= 0) { if (default_router_list[i].neighbor_entry != NULL) { if (default_router_list[i].neighbor_entry->netif != NULL) { return default_router_list[i].neighbor_entry->netif; } } } /* try with the netif that matches the source address. */ if (!ip6_addr_isany(src)) { for(netif = netif_list; netif != NULL; netif = netif->next) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_cmp(src, netif_ip6_addr(netif, i))) { return netif; } } } } /* no matching netif found, use default netif */ return netif_default; }