diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 0d60fbc59d8f..7e25043d826c 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -863,6 +863,41 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
863 | goto out_err_release; | 863 | goto out_err_release; |
864 | } | 864 | } |
865 | 865 | ||
866 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | ||
867 | /* | ||
868 | * Here if the dst entry we've looked up | ||
869 | * has a neighbour entry that is in the INCOMPLETE | ||
870 | * state and the src address from the flow is | ||
871 | * marked as OPTIMISTIC, we release the found | ||
872 | * dst entry and replace it instead with the | ||
873 | * dst entry of the nexthop router | ||
874 | */ | ||
875 | if (!((*dst)->neighbour->nud_state & NUD_VALID)) { | ||
876 | struct inet6_ifaddr *ifp; | ||
877 | struct flowi fl_gw; | ||
878 | int redirect; | ||
879 | |||
880 | ifp = ipv6_get_ifaddr(&fl->fl6_src, (*dst)->dev, 1); | ||
881 | |||
882 | redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC); | ||
883 | if (ifp) | ||
884 | in6_ifa_put(ifp); | ||
885 | |||
886 | if (redirect) { | ||
887 | /* | ||
888 | * We need to get the dst entry for the | ||
889 | * default router instead | ||
890 | */ | ||
891 | dst_release(*dst); | ||
892 | memcpy(&fl_gw, fl, sizeof(struct flowi)); | ||
893 | memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr)); | ||
894 | *dst = ip6_route_output(sk, &fl_gw); | ||
895 | if ((err = (*dst)->error)) | ||
896 | goto out_err_release; | ||
897 | } | ||
898 | } | ||
899 | #endif | ||
900 | |||
866 | return 0; | 901 | return 0; |
867 | 902 | ||
868 | out_err_release: | 903 | out_err_release: |