From: Roy Marples Date: Thu, 16 May 2013 14:28:42 +0000 (+0000) Subject: Test BSD kernels for a specific version so we can listen to either X-Git-Tag: v5.99.7~64 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5fe587be91f754eafc554747bdc9c2f987d75adb;p=thirdparty%2Fdhcpcd.git Test BSD kernels for a specific version so we can listen to either RTM_NEWADDR for duplicates, or directly on the wire with a maximum timeout. Warn about this noisily as there is no reason why the kernel cannot be easily patched to support this. --- diff --git a/README b/README index 17eb5108..2ef4c9b3 100644 --- a/README +++ b/README @@ -38,16 +38,6 @@ routes. You can find discussion here: BSD systems where this has been fixed are: NetBSD-5.0 -Some BSD systems announce IPv6 addresses to userland when the address has -been added, not when it's actually ready to use. This is important because -no kernel allows to send from the unspecified address which means userland -cannot be RFC conformation when creating DAD messages so we need to rely on -the kernel implementation. -You can find the discussion here: - http://mail-index.netbsd.org/tech-net/2013/03/15/msg004019.html -BSD systems where this will be fixed are: - NetBSD-7.0 - We try and detect how dhcpcd should interact with system services during the configure stage. If we cannot auto-detect how do to this, or it is wrong then you can change this by passing shell commands to --service-exists, diff --git a/if-bsd.c b/if-bsd.c index d664d4d1..136fab2d 100644 --- a/if-bsd.c +++ b/if-bsd.c @@ -481,7 +481,7 @@ manage_link(int fd) struct sockaddr_dl sdl; unsigned char *hwaddr; #endif -#ifdef INET6 +#if defined(INET6) && !defined(LISTEN_DAD) struct in6_addr ia6; struct sockaddr_in6 *sin6; #endif @@ -606,7 +606,7 @@ manage_link(int fd) &rt.dest, &rt.net, &rt.gate); break; #endif -#ifdef INET6 +#if defined(INET6) && !defined(LISTEN_DAD) case AF_INET6: sin6 = (struct sockaddr_in6*) rti_info[RTAX_IFA]; diff --git a/ipv6.h b/ipv6.h index 870cb0e4..d730c78a 100644 --- a/ipv6.h +++ b/ipv6.h @@ -37,6 +37,32 @@ #define ROUNDUP8(a) (1 + (((a) - 1) | 7)) +/* + * BSD kernels don't inform userland of DAD results. + * Also, for RTM_NEWADDR messages the address flags could be + * undefined leading to false positive duplicate address errors. + * As such we listen for duplicate addresses on the wire and + * wait the maxium possible length of time as dictated by the DAD transmission + * counter and RFC timings. + * See the discussion here: + * http://mail-index.netbsd.org/tech-net/2013/03/15/msg004019.html + */ +#ifdef BSD +# define LISTEN_DAD +#endif + +/* This was fixed in NetBSD */ +#ifdef __NetBSD_Prereq__ +# if __NetBSD_Prereq__(6, 99, 20) +# undef LISTEN_DAD +# endif +#endif + +#ifdef LISTEN_DAD +# warning kernel does not report DAD results to userland +# warning listening to duplicated addresses on the wire +#endif + struct ipv6_addr { TAILQ_ENTRY(ipv6_addr) next; struct interface *iface; diff --git a/ipv6ns.c b/ipv6ns.c index 16cc15ec..ba1eb56e 100644 --- a/ipv6ns.c +++ b/ipv6ns.c @@ -164,6 +164,12 @@ ipv6ns_open(void) atexit(ipv6ns_cleanup); #endif +#ifdef LISTEN_DAD + syslog(LOG_WARNING, "kernel does not report DAD results to userland"); + syslog(LOG_WARNING, + "warning listening to duplicated addresses on the wire"); +#endif + len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); sndbuf = calloc(1, len); if (sndbuf == NULL)