|
@@ -886,22 +886,45 @@ static int ip6_dst_lookup_tail(struct sock *sk,
|
|
#endif
|
|
#endif
|
|
int err;
|
|
int err;
|
|
|
|
|
|
- if (!*dst)
|
|
|
|
- *dst = ip6_route_output(net, sk, fl6);
|
|
|
|
-
|
|
|
|
- err = (*dst)->error;
|
|
|
|
- if (err)
|
|
|
|
- goto out_err_release;
|
|
|
|
|
|
+ /* The correct way to handle this would be to do
|
|
|
|
+ * ip6_route_get_saddr, and then ip6_route_output; however,
|
|
|
|
+ * the route-specific preferred source forces the
|
|
|
|
+ * ip6_route_output call _before_ ip6_route_get_saddr.
|
|
|
|
+ *
|
|
|
|
+ * In source specific routing (no src=any default route),
|
|
|
|
+ * ip6_route_output will fail given src=any saddr, though, so
|
|
|
|
+ * that's why we try it again later.
|
|
|
|
+ */
|
|
|
|
+ if (ipv6_addr_any(&fl6->saddr) && (!*dst || !(*dst)->error)) {
|
|
|
|
+ struct rt6_info *rt;
|
|
|
|
+ bool had_dst = *dst != NULL;
|
|
|
|
|
|
- if (ipv6_addr_any(&fl6->saddr)) {
|
|
|
|
- struct rt6_info *rt = (struct rt6_info *) *dst;
|
|
|
|
|
|
+ if (!had_dst)
|
|
|
|
+ *dst = ip6_route_output(net, sk, fl6);
|
|
|
|
+ rt = (*dst)->error ? NULL : (struct rt6_info *)*dst;
|
|
err = ip6_route_get_saddr(net, rt, &fl6->daddr,
|
|
err = ip6_route_get_saddr(net, rt, &fl6->daddr,
|
|
sk ? inet6_sk(sk)->srcprefs : 0,
|
|
sk ? inet6_sk(sk)->srcprefs : 0,
|
|
&fl6->saddr);
|
|
&fl6->saddr);
|
|
if (err)
|
|
if (err)
|
|
goto out_err_release;
|
|
goto out_err_release;
|
|
|
|
+
|
|
|
|
+ /* If we had an erroneous initial result, pretend it
|
|
|
|
+ * never existed and let the SA-enabled version take
|
|
|
|
+ * over.
|
|
|
|
+ */
|
|
|
|
+ if (!had_dst && (*dst)->error) {
|
|
|
|
+ dst_release(*dst);
|
|
|
|
+ *dst = NULL;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (!*dst)
|
|
|
|
+ *dst = ip6_route_output(net, sk, fl6);
|
|
|
|
+
|
|
|
|
+ err = (*dst)->error;
|
|
|
|
+ if (err)
|
|
|
|
+ goto out_err_release;
|
|
|
|
+
|
|
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
|
|
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
|
|
/*
|
|
/*
|
|
* Here if the dst entry we've looked up
|
|
* Here if the dst entry we've looked up
|