aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
authorMarkus Stenberg <markus.stenberg@iki.fi>2015-05-05 06:36:59 -0400
committerDavid S. Miller <davem@davemloft.net>2015-05-09 15:58:41 -0400
commite16e888b525503be05b3aea64190e8b3bdef44d0 (patch)
tree7894cd9304ab18668c2d003bfa3e8c8c3a31e41f /net/ipv6/ip6_output.c
parent0a801445db4cb00bc900fd89b1e5eb7d7b581d7e (diff)
ipv6: Fixed source specific default route handling.
If there are only IPv6 source specific default routes present, the host gets -ENETUNREACH on e.g. connect() because ip6_dst_lookup_tail calls ip6_route_output first, and given source address any, it fails, and ip6_route_get_saddr is never called. The change is to use the ip6_route_get_saddr, even if the initial ip6_route_output fails, and then doing ip6_route_output _again_ after we have appropriate source address available. Note that this is '99% fix' to the problem; a correct fix would be to do route lookups only within addrconf.c when picking a source address, and never call ip6_route_output before source address has been populated. Signed-off-by: Markus Stenberg <markus.stenberg@iki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c39
1 files changed, 31 insertions, 8 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 7fde1f265c90..c21777565c58 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -886,22 +886,45 @@ static int ip6_dst_lookup_tail(struct sock *sk,
886#endif 886#endif
887 int err; 887 int err;
888 888
889 if (!*dst) 889 /* The correct way to handle this would be to do
890 *dst = ip6_route_output(net, sk, fl6); 890 * ip6_route_get_saddr, and then ip6_route_output; however,
891 891 * the route-specific preferred source forces the
892 err = (*dst)->error; 892 * ip6_route_output call _before_ ip6_route_get_saddr.
893 if (err) 893 *
894 goto out_err_release; 894 * In source specific routing (no src=any default route),
895 * ip6_route_output will fail given src=any saddr, though, so
896 * that's why we try it again later.
897 */
898 if (ipv6_addr_any(&fl6->saddr) && (!*dst || !(*dst)->error)) {
899 struct rt6_info *rt;
900 bool had_dst = *dst != NULL;
895 901
896 if (ipv6_addr_any(&fl6->saddr)) { 902 if (!had_dst)
897 struct rt6_info *rt = (struct rt6_info *) *dst; 903 *dst = ip6_route_output(net, sk, fl6);
904 rt = (*dst)->error ? NULL : (struct rt6_info *)*dst;
898 err = ip6_route_get_saddr(net, rt, &fl6->daddr, 905 err = ip6_route_get_saddr(net, rt, &fl6->daddr,
899 sk ? inet6_sk(sk)->srcprefs : 0, 906 sk ? inet6_sk(sk)->srcprefs : 0,
900 &fl6->saddr); 907 &fl6->saddr);
901 if (err) 908 if (err)
902 goto out_err_release; 909 goto out_err_release;
910
911 /* If we had an erroneous initial result, pretend it
912 * never existed and let the SA-enabled version take
913 * over.
914 */
915 if (!had_dst && (*dst)->error) {
916 dst_release(*dst);
917 *dst = NULL;
918 }
903 } 919 }
904 920
921 if (!*dst)
922 *dst = ip6_route_output(net, sk, fl6);
923
924 err = (*dst)->error;
925 if (err)
926 goto out_err_release;
927
905#ifdef CONFIG_IPV6_OPTIMISTIC_DAD 928#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
906 /* 929 /*
907 * Here if the dst entry we've looked up 930 * Here if the dst entry we've looked up