ipv6_addr_t *gnrc_ipv6_netif_match_prefix(kernel_pid_t pid, const ipv6_addr_t *prefix) { ipv6_addr_t *res = NULL; gnrc_ipv6_netif_t *iface = gnrc_ipv6_netif_get(pid); mutex_lock(&(iface->mutex)); if (_find_by_prefix_unsafe(&res, iface, prefix, NULL) > 0) { mutex_unlock(&(iface->mutex)); return res; } mutex_unlock(&(iface->mutex)); return NULL; }
static ng_ipv6_addr_t *_match_prefix(kernel_pid_t pid, const ng_ipv6_addr_t *addr, bool only_unicast) { ng_ipv6_addr_t *res = NULL; ng_ipv6_netif_t *iface = ng_ipv6_netif_get(pid); mutex_lock(&(iface->mutex)); if (_find_by_prefix_unsafe(&res, iface, addr, only_unicast) > 0) { mutex_unlock(&(iface->mutex)); return res; } mutex_unlock(&(iface->mutex)); return NULL; }
kernel_pid_t ng_ipv6_netif_find_by_prefix(ng_ipv6_addr_t **out, const ng_ipv6_addr_t *prefix) { uint8_t best_match = 0; ng_ipv6_addr_t *tmp_res = NULL; kernel_pid_t res = KERNEL_PID_UNDEF; for (int i = 0; i < NG_NETIF_NUMOF; i++) { uint8_t match; mutex_lock(&(ipv6_ifs[i].mutex)); match = _find_by_prefix_unsafe(&tmp_res, ipv6_ifs + i, prefix, false); if (match > best_match) { if (out != NULL) { *out = tmp_res; } res = ipv6_ifs[i].pid; best_match = match; } mutex_unlock(&(ipv6_ifs[i].mutex)); } #if ENABLE_DEBUG if (res != KERNEL_PID_UNDEF) { DEBUG("Found %s on interface %" PRIkernel_pid " globally matching ", ng_ipv6_addr_to_str(addr_str, *out, sizeof(addr_str)), res); DEBUG("%s by %" PRIu8 " bits\n", ng_ipv6_addr_to_str(addr_str, prefix, sizeof(addr_str)), best_match); } else { DEBUG("Did not found any address globally matching %s\n", ng_ipv6_addr_to_str(addr_str, prefix, sizeof(addr_str))); } #endif return res; }
/** @brief Find the best candidate among the configured addresses * for a certain destination address according to the 8 rules * specified in RFC 6734, section 5. * @see <a href="http://tools.ietf.org/html/rfc6724#section-5"> * RFC6724, section 5 * </a> * * @param[in] iface The interface for sending. * @param[in] dst The destination IPv6 address. * @param[in, out] candidate_set The preselected set of candidate addresses as * a bitfield. * * @pre @p dst is not unspecified. * * @return The best matching candidate found on @p iface, may be NULL if none * is found. */ static ipv6_addr_t *_source_address_selection(gnrc_ipv6_netif_t *iface, const ipv6_addr_t *dst, uint8_t *candidate_set) { /* create temporary set for assigning "points" to candidates wining in the * corresponding rules. */ uint8_t winner_set[GNRC_IPV6_NETIF_ADDR_NUMOF]; memset(winner_set, 0, GNRC_IPV6_NETIF_ADDR_NUMOF); uint8_t max_pts = 0; /* _create_candidate_set() assures that `dest` is not unspecified and if * `dst` is loopback rule 1 will fire anyway. */ uint8_t dst_scope = _get_scope(dst, true); DEBUG("finding the best match within the source address candidates\n"); for (int i = 0; i < GNRC_IPV6_NETIF_ADDR_NUMOF; i++) { gnrc_ipv6_netif_addr_t *iter = &(iface->addrs[i]); DEBUG("Checking address: %s\n", ipv6_addr_to_str(addr_str, &(iter->addr), sizeof(addr_str))); /* entries which are not part of the candidate set can be ignored */ if (!(bf_isset(candidate_set, i))) { DEBUG("Not part of the candidate set - skipping\n"); continue; } /* Rule 1: if we have an address configured that equals the destination * use this one as source */ if (ipv6_addr_equal(&(iter->addr), dst)) { DEBUG("Ease one - rule 1\n"); return &(iter->addr); } /* Rule 2: Prefer appropriate scope. */ /* both link local */ uint8_t candidate_scope = _get_scope(&(iter->addr), false); if (candidate_scope == dst_scope) { DEBUG("winner for rule 2 (same scope) found\n"); winner_set[i] += RULE_2A_PTS; if (winner_set[i] > max_pts) { max_pts = RULE_2A_PTS; } } else if (candidate_scope < dst_scope) { DEBUG("winner for rule 2 (smaller scope) found\n"); winner_set[i] += RULE_2B_PTS; if (winner_set[i] > max_pts) { max_pts = winner_set[i]; } } /* Rule 3: Avoid deprecated addresses. */ if (iter->preferred > 0) { DEBUG("winner for rule 3 found\n"); winner_set[i] += RULE_3_PTS; if (winner_set[i] > max_pts) { max_pts = winner_set[i]; } } /* Rule 4: Prefer home addresses. * Does not apply, gnrc does not support Mobile IP. * TODO: update as soon as gnrc supports Mobile IP */ /* Rule 5: Prefer outgoing interface. * RFC 6724 says: * "It is RECOMMENDED that the candidate source addresses be the set of * unicast addresses assigned to the interface that will be used to * send to the destination (the "outgoing" interface). On routers, * the candidate set MAY include unicast addresses assigned to any * interface that forwards packets, subject to the restrictions * described below." * Currently this implementation uses ALWAYS source addresses assigned * to the outgoing interface. Hence, Rule 5 is always fulfilled. */ /* Rule 6: Prefer matching label. * Flow labels are currently not supported by gnrc. * TODO: update as soon as gnrc supports flow labels */ /* Rule 7: Prefer temporary addresses. * Temporary addresses are currently not supported by gnrc. * TODO: update as soon as gnrc supports temporary addresses */ } /* reset candidate set to mark winners */ memset(candidate_set, 0, (GNRC_IPV6_NETIF_ADDR_NUMOF / 8) + 1); /* check if we have a clear winner */ /* collect candidates with maximum points */ for (int i = 0; i < GNRC_IPV6_NETIF_ADDR_NUMOF; i++) { if (winner_set[i] == max_pts) { bf_set(candidate_set, i); } } /* otherwise apply rule 8: Use longest matching prefix. */ ipv6_addr_t *res = NULL; _find_by_prefix_unsafe(&res, iface, dst, candidate_set); return res; }