static void dn_nsp_send(struct sk_buff *skb) { struct sock *sk = skb->sk; struct dn_scp *scp = DN_SK(sk); struct dst_entry *dst; struct flowi fl; skb_reset_transport_header(skb); scp->stamp = jiffies; dst = sk_dst_check(sk, 0); if (dst) { try_again: skb_dst_set(skb, dst); dst_output(skb); return; } memset(&fl, 0, sizeof(fl)); fl.oif = sk->sk_bound_dev_if; fl.fld_src = dn_saddr2dn(&scp->addr); fl.fld_dst = dn_saddr2dn(&scp->peer); dn_sk_ports_copy(&fl, scp); fl.proto = DNPROTO_NSP; if (dn_route_output_sock(&sk->sk_dst_cache, &fl, sk, 0) == 0) { dst = sk_dst_get(sk); sk->sk_route_caps = dst->dev->features; goto try_again; } sk->sk_err = EHOSTUNREACH; if (!sock_flag(sk, SOCK_DEAD)) sk->sk_state_change(sk); }
/** * ip6_sk_dst_lookup - perform socket cached route lookup on flow * @sk: socket which provides the dst cache and route info * @dst: pointer to dst_entry * for result * @fl: flow to lookup * * This function performs a route lookup on the given flow with the * possibility of using the cached route in the socket if it is valid. * It will take the socket dst lock when operating on the dst cache. * As a result, this function can only be used in process context. * * It returns zero on success, or a standard errno code on error. */ int ip6_sk_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) { *dst = NULL; if (sk) { *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); *dst = ip6_sk_dst_check(sk, *dst, fl); } return ip6_dst_lookup_tail(sk, dst, fl); }
/** * ip6_sk_dst_lookup_flow - perform socket cached route lookup on flow * @sk: socket which provides the dst cache and route info * @fl6: flow to lookup * @final_dst: final destination address for ipsec lookup * * This function performs a route lookup on the given flow with the * possibility of using the cached route in the socket if it is valid. * It will take the socket dst lock when operating on the dst cache. * As a result, this function can only be used in process context. * * It returns a valid dst pointer on success, or a pointer encoded * error code. */ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, const struct in6_addr *final_dst) { struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); dst = ip6_sk_dst_check(sk, dst, fl6); if (!dst) dst = ip6_dst_lookup_flow(sk, fl6, final_dst); return dst; }
/** * ip6_sk_dst_lookup_flow - perform socket cached route lookup on flow * @sk: socket which provides the dst cache and route info * @fl6: flow to lookup * @final_dst: final destination address for ipsec lookup * * This function performs a route lookup on the given flow with the * possibility of using the cached route in the socket if it is valid. * It will take the socket dst lock when operating on the dst cache. * As a result, this function can only be used in process context. * * It returns a valid dst pointer on success, or a pointer encoded * error code. */ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, const struct in6_addr *final_dst) { struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); int err; dst = ip6_sk_dst_check(sk, dst, fl6); err = ip6_dst_lookup_tail(sock_net(sk), sk, &dst, fl6); if (err) return ERR_PTR(err); if (final_dst) fl6->daddr = *final_dst; return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); }
/** * ip6_sk_dst_lookup_flow - perform socket cached route lookup on flow * @sk: socket which provides the dst cache and route info * @fl6: flow to lookup * @final_dst: final destination address for ipsec lookup * @can_sleep: we are in a sleepable context * * This function performs a route lookup on the given flow with the * possibility of using the cached route in the socket if it is valid. * It will take the socket dst lock when operating on the dst cache. * As a result, this function can only be used in process context. * * It returns a valid dst pointer on success, or a pointer encoded * error code. */ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, const struct in6_addr *final_dst, bool can_sleep) { struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); int err; dst = ip6_sk_dst_check(sk, dst, fl6); err = ip6_dst_lookup_tail(sk, &dst, fl6); if (err) return ERR_PTR(err); if (final_dst) ipv6_addr_copy(&fl6->daddr, final_dst); if (can_sleep) fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); }
int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) { int err = 0; *dst = NULL; if (sk) { struct ipv6_pinfo *np = inet6_sk(sk); *dst = sk_dst_check(sk, np->dst_cookie); if (*dst) { struct rt6_info *rt = (struct rt6_info*)*dst; /* Yes, checking route validity in not connected case is not very simple. Take into account, that we do not support routing by source, TOS, and MSG_DONTROUTE --ANK (980726) 1. If route was host route, check that cached destination is current. If it is network route, we still may check its validity using saved pointer to the last used address: daddr_cache. We do not want to save whole address now, (because main consumer of this service is tcp, which has not this problem), so that the last trick works only on connected sockets. 2. oif also should be the same. */ if (((rt->rt6i_dst.plen != 128 || !ipv6_addr_equal(&fl->fl6_dst, &rt->rt6i_dst.addr)) && (np->daddr_cache == NULL || !ipv6_addr_equal(&fl->fl6_dst, np->daddr_cache))) || (fl->oif && fl->oif != (*dst)->dev->ifindex)) { dst_release(*dst); *dst = NULL; } } } if (*dst == NULL) *dst = ip6_route_output(sk, fl); if ((err = (*dst)->error)) goto out_err_release; if (ipv6_addr_any(&fl->fl6_src)) { err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); if (err) { #if IP6_DEBUG >= 2 printk(KERN_DEBUG "ip6_dst_lookup: " "no available source address\n"); #endif goto out_err_release; } } return 0; out_err_release: dst_release(*dst); *dst = NULL; return err; }