Module Name: src Committed By: roy Date: Sat May 2 14:41:32 UTC 2015
Modified Files: src/sys/net: if.h if_spppsubr.c src/sys/netinet: if_arp.c if_inarp.h in.c in.h in_pcb.c in_proto.c in_selsrc.c in_var.h ip_icmp.c ip_input.c raw_ip.c src/sys/sys: sockio.h Log Message: Add IPv4 address flags IN_IFF_TENTATIVE, IN_IFF_DUPLICATED and IN_IFF_DETATCHED to mimic the IPv6 address behaviour. Add SIOCGIFAFLAG_IN ioctl to retrieve the address flag via the ifreq structure. Add IPv4 DAD detection via the ARP methods described in RFC 5227. Add sysctls net.inet.ip.dad_count and net.inet.arp.debug. Discussed on tech-net@ To generate a diff of this commit: cvs rdiff -u -r1.188 -r1.189 src/sys/net/if.h cvs rdiff -u -r1.132 -r1.133 src/sys/net/if_spppsubr.c cvs rdiff -u -r1.162 -r1.163 src/sys/netinet/if_arp.c cvs rdiff -u -r1.44 -r1.45 src/sys/netinet/if_inarp.h cvs rdiff -u -r1.151 -r1.152 src/sys/netinet/in.c cvs rdiff -u -r1.96 -r1.97 src/sys/netinet/in.h cvs rdiff -u -r1.158 -r1.159 src/sys/netinet/in_pcb.c cvs rdiff -u -r1.111 -r1.112 src/sys/netinet/in_proto.c cvs rdiff -u -r1.11 -r1.12 src/sys/netinet/in_selsrc.c cvs rdiff -u -r1.70 -r1.71 src/sys/netinet/in_var.h cvs rdiff -u -r1.137 -r1.138 src/sys/netinet/ip_icmp.c cvs rdiff -u -r1.320 -r1.321 src/sys/netinet/ip_input.c cvs rdiff -u -r1.150 -r1.151 src/sys/netinet/raw_ip.c cvs rdiff -u -r1.32 -r1.33 src/sys/sys/sockio.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/if.h diff -u src/sys/net/if.h:1.188 src/sys/net/if.h:1.189 --- src/sys/net/if.h:1.188 Mon Apr 20 10:19:54 2015 +++ src/sys/net/if.h Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if.h,v 1.188 2015/04/20 10:19:54 roy Exp $ */ +/* $NetBSD: if.h,v 1.189 2015/05/02 14:41:32 roy Exp $ */ /*- * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc. @@ -594,6 +594,7 @@ struct ifreq { struct sockaddr ifru_broadaddr; struct sockaddr_storage ifru_space; short ifru_flags; + int ifru_addrflags; int ifru_metric; int ifru_mtu; int ifru_dlt; @@ -609,6 +610,7 @@ struct ifreq { #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ #define ifr_space ifr_ifru.ifru_space /* sockaddr_storage */ #define ifr_flags ifr_ifru.ifru_flags /* flags */ +#define ifr_addrflags ifr_ifru.ifru_addrflags /* addr flags */ #define ifr_metric ifr_ifru.ifru_metric /* metric */ #define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ #define ifr_dlt ifr_ifru.ifru_dlt /* data link type (DLT_*) */ Index: src/sys/net/if_spppsubr.c diff -u src/sys/net/if_spppsubr.c:1.132 src/sys/net/if_spppsubr.c:1.133 --- src/sys/net/if_spppsubr.c:1.132 Mon Apr 20 10:19:54 2015 +++ src/sys/net/if_spppsubr.c Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_spppsubr.c,v 1.132 2015/04/20 10:19:54 roy Exp $ */ +/* $NetBSD: if_spppsubr.c,v 1.133 2015/05/02 14:41:32 roy Exp $ */ /* * Synchronous PPP/Cisco link level subroutines. @@ -41,7 +41,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.132 2015/04/20 10:19:54 roy Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.133 2015/05/02 14:41:32 roy Exp $"); #if defined(_KERNEL_OPT) #include "opt_inet.h" @@ -4875,7 +4875,7 @@ sppp_set_ip_addrs(struct sppp *sp, uint3 found: { - int error; + int error, hostIsNew; struct sockaddr_in new_sin = *si; struct sockaddr_in new_dst = *dest; @@ -4886,8 +4886,13 @@ found: */ in_ifscrub(ifp, ifatoia(ifa)); - if (myaddr != 0) - new_sin.sin_addr.s_addr = htonl(myaddr); + hostIsNew = 0; + if (myaddr != 0) { + if (new_sin.sin_addr.s_addr != htonl(myaddr)) { + new_sin.sin_addr.s_addr = htonl(myaddr); + hostIsNew = 1; + } + } if (hisaddr != 0) { new_dst.sin_addr.s_addr = htonl(hisaddr); if (new_dst.sin_addr.s_addr != dest->sin_addr.s_addr) { @@ -4895,7 +4900,7 @@ found: *dest = new_dst; /* fix dstaddr in place */ } } - error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 0); + error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 0, hostIsNew); if (debug && error) { log(LOG_DEBUG, "%s: sppp_set_ip_addrs: in_ifinit " @@ -4948,7 +4953,7 @@ found: if (sp->ipcp.flags & IPCP_HISADDR_DYN) /* replace peer addr in place */ dest->sin_addr.s_addr = sp->ipcp.saved_hisaddr; - in_ifinit(ifp, ifatoia(ifa), &new_sin, 0); + in_ifinit(ifp, ifatoia(ifa), &new_sin, 0, 0); (void)pfil_run_hooks(if_pfil, (struct mbuf **)SIOCDIFADDR, ifp, PFIL_IFADDR); } Index: src/sys/netinet/if_arp.c diff -u src/sys/netinet/if_arp.c:1.162 src/sys/netinet/if_arp.c:1.163 --- src/sys/netinet/if_arp.c:1.162 Mon Mar 23 18:33:17 2015 +++ src/sys/netinet/if_arp.c Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_arp.c,v 1.162 2015/03/23 18:33:17 roy Exp $ */ +/* $NetBSD: if_arp.c,v 1.163 2015/05/02 14:41:32 roy Exp $ */ /*- * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc. @@ -68,7 +68,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.162 2015/03/23 18:33:17 roy Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.163 2015/05/02 14:41:32 roy Exp $"); #include "opt_ddb.h" #include "opt_inet.h" @@ -95,6 +95,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1 #include <sys/sysctl.h> #include <sys/socketvar.h> #include <sys/percpu.h> +#include <sys/cprng.h> #include <net/ethertypes.h> #include <net/if.h> @@ -102,6 +103,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1 #include <net/if_token.h> #include <net/if_types.h> #include <net/if_ether.h> +#include <net/net_osdep.h> #include <net/route.h> #include <net/net_stats.h> @@ -142,6 +144,14 @@ int arpt_refresh = (5*60); /* time left #define rt_expire rt_rmx.rmx_expire #define rt_pksent rt_rmx.rmx_pksent +int ip_dad_count = PROBE_NUM; +#ifdef ARP_DEBUG +static int arp_debug = 1; +#else +static int arp_debug = 0; +#endif +#define arplog(x) do { if (arp_debug) log x; } while (/*CONSTCOND*/ 0) + static struct sockaddr *arp_setgate(struct rtentry *, struct sockaddr *, const struct sockaddr *); static void arptfree(struct llinfo_arp *); @@ -153,6 +163,9 @@ static struct llinfo_arp *arplookup(stru static void in_arpinput(struct mbuf *); static void arp_drainstub(void); +static void arp_dad_timer(struct ifaddr *); +static void arp_dad_duplicated(struct ifaddr *); + LIST_HEAD(llinfo_arpq, llinfo_arp) llinfo_arp; struct ifqueue arpintrq = { .ifq_head = NULL, @@ -511,6 +524,14 @@ arp_rtrequest(int req, struct rtentry *r in = &ifatoia(ifa)->ia_addr.sin_addr; + if (ifatoia(ifa)->ia4_flags & + (IN_IFF_NOTREADY | IN_IFF_DETACHED)) + { + arplog((LOG_DEBUG, "arp_request: %s not ready\n", + in_fmtaddr(*in))); + return; + } + arprequest(ifa->ifa_ifp, in, in, CLLADDR(ifa->ifa_ifp->if_sadl)); return; @@ -601,10 +622,17 @@ arp_rtrequest(int req, struct rtentry *r } /* Announce a new entry if requested. */ if (rt->rt_flags & RTF_ANNOUNCE) { - arprequest(ifp, - &satocsin(rt_getkey(rt))->sin_addr, - &satocsin(rt_getkey(rt))->sin_addr, - CLLADDR(satocsdl(gate))); + INADDR_TO_IA(satocsin(rt_getkey(rt))->sin_addr, ia); + while (ia && ia->ia_ifp != ifp) + NEXT_IA_WITH_SAME_ADDR(ia); + if (ia == NULL || + ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED)) + ; + else + arprequest(ifp, + &satocsin(rt_getkey(rt))->sin_addr, + &satocsin(rt_getkey(rt))->sin_addr, + CLLADDR(satocsdl(gate))); } /*FALLTHROUGH*/ case RTM_RESOLVE: @@ -999,16 +1027,6 @@ in_arpinput(struct mbuf *m) if (m->m_flags & (M_BCAST|M_MCAST)) ARP_STATINC(ARP_STAT_RCVMCAST); - /* - * If the target IP address is zero, ignore the packet. - * This prevents the code below from tring to answer - * when we are using IP address zero (booting). - */ - if (in_nullhost(itaddr)) { - ARP_STATINC(ARP_STAT_RCVZEROTPA); - goto out; - } - /* * Search for a matching interface address @@ -1089,13 +1107,38 @@ in_arpinput(struct mbuf *m) /* * If the source IP address is zero, this is an RFC 5227 ARP probe */ - if (in_nullhost(isaddr)) { + if (in_nullhost(isaddr)) ARP_STATINC(ARP_STAT_RCVZEROSPA); - goto reply; + else if (in_hosteq(isaddr, myaddr)) + ARP_STATINC(ARP_STAT_RCVLOCALSPA); + + if (in_nullhost(itaddr)) + ARP_STATINC(ARP_STAT_RCVZEROTPA); + + /* DAD check, RFC 5227 2.1.1, Probe Details */ + if (in_hosteq(isaddr, myaddr) || + (in_nullhost(isaddr) && in_hosteq(itaddr, myaddr))) + { + /* If our address is tentative, mark it as duplicated */ + if (ia->ia4_flags & IN_IFF_TENTATIVE) + arp_dad_duplicated((struct ifaddr *)ia); + /* If our address is unuseable, don't reply */ + if (ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED)) + goto out; } + /* + * If the target IP address is zero, ignore the packet. + * This prevents the code below from tring to answer + * when we are using IP address zero (booting). + */ + if (in_nullhost(itaddr)) + goto out; + + if (in_nullhost(isaddr)) + goto reply; + if (in_hosteq(isaddr, myaddr)) { - ARP_STATINC(ARP_STAT_RCVLOCALSPA); log(LOG_ERR, "duplicate IP address %s sent from link address %s\n", in_fmtaddr(isaddr), lla_snprintf(ar_sha(ah), ah->ar_hln)); @@ -1211,6 +1254,9 @@ reply: } ARP_STATINC(ARP_STAT_RCVREQUEST); if (in_hosteq(itaddr, myaddr)) { + /* If our address is unuseable, don't reply */ + if (ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED)) + goto out; /* I am the target */ tha = ar_tha(ah); if (tha) @@ -1358,19 +1404,321 @@ void arp_ifinit(struct ifnet *ifp, struct ifaddr *ifa) { struct in_addr *ip; + struct in_ifaddr *ia = (struct in_ifaddr *)ifa; /* * Warn the user if another station has this IP address, * but only if the interface IP address is not zero. */ ip = &IA_SIN(ifa)->sin_addr; - if (!in_nullhost(*ip)) + if (!in_nullhost(*ip) && + (ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED)) == 0) arprequest(ifp, ip, ip, CLLADDR(ifp->if_sadl)); ifa->ifa_rtrequest = arp_rtrequest; ifa->ifa_flags |= RTF_CLONING; } +TAILQ_HEAD(dadq_head, dadq); +struct dadq { + TAILQ_ENTRY(dadq) dad_list; + struct ifaddr *dad_ifa; + int dad_count; /* max ARP to send */ + int dad_arp_tcount; /* # of trials to send ARP */ + int dad_arp_ocount; /* ARP sent so far */ + int dad_arp_announce; /* max ARP announcements */ + int dad_arp_acount; /* # of announcements */ + struct callout dad_timer_ch; +}; +MALLOC_JUSTDEFINE(M_IPARP, "ARP DAD", "ARP DAD Structure"); + +static struct dadq_head dadq; +static int dad_init = 0; +static int dad_maxtry = 15; /* max # of *tries* to transmit DAD packet */ + +static struct dadq * +arp_dad_find(struct ifaddr *ifa) +{ + struct dadq *dp; + + TAILQ_FOREACH(dp, &dadq, dad_list) { + if (dp->dad_ifa == ifa) + return dp; + } + return NULL; +} + +static void +arp_dad_starttimer(struct dadq *dp, int ticks) +{ + + callout_reset(&dp->dad_timer_ch, ticks, + (void (*)(void *))arp_dad_timer, (void *)dp->dad_ifa); +} + +static void +arp_dad_stoptimer(struct dadq *dp) +{ + + callout_stop(&dp->dad_timer_ch); +} + +static void +arp_dad_output(struct dadq *dp, struct ifaddr *ifa) +{ + struct in_ifaddr *ia = (struct in_ifaddr *)ifa; + struct ifnet *ifp = ifa->ifa_ifp; + struct in_addr sip; + + dp->dad_arp_tcount++; + if ((ifp->if_flags & IFF_UP) == 0) + return; + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + + dp->dad_arp_tcount = 0; + dp->dad_arp_ocount++; + + memset(&sip, 0, sizeof(sip)); + arprequest(ifa->ifa_ifp, &sip, &ia->ia_addr.sin_addr, + CLLADDR(ifa->ifa_ifp->if_sadl)); +} + +/* + * Start Duplicate Address Detection (DAD) for specified interface address. + */ +void +arp_dad_start(struct ifaddr *ifa) +{ + struct in_ifaddr *ia = (struct in_ifaddr *)ifa; + struct dadq *dp; + + if (!dad_init) { + TAILQ_INIT(&dadq); + dad_init++; + } + + /* + * If we don't need DAD, don't do it. + * - DAD is disabled (ip_dad_count == 0) + */ + if (!(ia->ia4_flags & IN_IFF_TENTATIVE)) { + log(LOG_DEBUG, + "arp_dad_start: called with non-tentative address " + "%s(%s)\n", + in_fmtaddr(ia->ia_addr.sin_addr), + ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); + return; + } + if (!ip_dad_count) { + struct in_addr *ip = &IA_SIN(ifa)->sin_addr; + + ia->ia4_flags &= ~IN_IFF_TENTATIVE; + rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL); + arprequest(ifa->ifa_ifp, ip, ip, + CLLADDR(ifa->ifa_ifp->if_sadl)); + return; + } + if (ifa->ifa_ifp == NULL) + panic("arp_dad_start: ifa->ifa_ifp == NULL"); + if (!(ifa->ifa_ifp->if_flags & IFF_UP)) + return; + if (arp_dad_find(ifa) != NULL) { + /* DAD already in progress */ + return; + } + + dp = malloc(sizeof(*dp), M_IPARP, M_NOWAIT); + if (dp == NULL) { + log(LOG_ERR, "arp_dad_start: memory allocation failed for " + "%s(%s)\n", + in_fmtaddr(ia->ia_addr.sin_addr), + ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); + return; + } + memset(dp, 0, sizeof(*dp)); + callout_init(&dp->dad_timer_ch, CALLOUT_MPSAFE); + TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list); + + arplog((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp), + in_fmtaddr(ia->ia_addr.sin_addr))); + + /* + * Send ARP packet for DAD, ip_dad_count times. + * Note that we must delay the first transmission. + */ + dp->dad_ifa = ifa; + ifaref(ifa); /* just for safety */ + dp->dad_count = ip_dad_count; + dp->dad_arp_announce = 0; /* Will be set when starting to announce */ + dp->dad_arp_acount = dp->dad_arp_ocount = dp->dad_arp_tcount = 0; + + arp_dad_starttimer(dp, cprng_fast32() % (PROBE_WAIT * hz)); +} + +/* + * terminate DAD unconditionally. used for address removals. + */ +void +arp_dad_stop(struct ifaddr *ifa) +{ + struct dadq *dp; + + if (!dad_init) + return; + dp = arp_dad_find(ifa); + if (dp == NULL) { + /* DAD wasn't started yet */ + return; + } + + arp_dad_stoptimer(dp); + + TAILQ_REMOVE(&dadq, dp, dad_list); + free(dp, M_IPARP); + dp = NULL; + ifafree(ifa); +} + +static void +arp_dad_timer(struct ifaddr *ifa) +{ + struct in_ifaddr *ia = (struct in_ifaddr *)ifa; + struct dadq *dp; + struct in_addr *ip; + + mutex_enter(softnet_lock); + KERNEL_LOCK(1, NULL); + + /* Sanity check */ + if (ia == NULL) { + log(LOG_ERR, "arp_dad_timer: called with null parameter\n"); + goto done; + } + dp = arp_dad_find(ifa); + if (dp == NULL) { + log(LOG_ERR, "arp_dad_timer: DAD structure not found\n"); + goto done; + } + if (ia->ia4_flags & IN_IFF_DUPLICATED) { + log(LOG_ERR, "nd4_dad_timer: called with duplicate address " + "%s(%s)\n", + in_fmtaddr(ia->ia_addr.sin_addr), + ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); + goto done; + } + if ((ia->ia4_flags & IN_IFF_TENTATIVE) == 0 && dp->dad_arp_acount == 0){ + log(LOG_ERR, "arp_dad_timer: called with non-tentative address " + "%s(%s)\n", + in_fmtaddr(ia->ia_addr.sin_addr), + ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); + goto done; + } + + /* timeouted with IFF_{RUNNING,UP} check */ + if (dp->dad_arp_tcount > dad_maxtry) { + arplog((LOG_INFO, "%s: could not run DAD, driver problem?\n", + if_name(ifa->ifa_ifp))); + + TAILQ_REMOVE(&dadq, dp, dad_list); + free(dp, M_IPARP); + dp = NULL; + ifafree(ifa); + goto done; + } + + /* Need more checks? */ + if (dp->dad_arp_ocount < dp->dad_count) { + int delay; + + /* + * We have more ARP to go. Send ARP packet for DAD. + */ + arp_dad_output(dp, ifa); + if (dp->dad_arp_ocount < dp->dad_count) + delay = (PROBE_MIN * hz) + + (cprng_fast32() % + ((PROBE_MAX * hz) - (PROBE_MIN * hz))); + else + delay = ANNOUNCE_WAIT * hz; + arp_dad_starttimer(dp, delay); + goto done; + } else if (dp->dad_arp_acount == 0) { + /* + * We are done with DAD. + * No duplicate address found. + */ + ia->ia4_flags &= ~IN_IFF_TENTATIVE; + rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL); + arplog((LOG_DEBUG, + "%s: DAD complete for %s - no duplicates found\n", + if_name(ifa->ifa_ifp), + in_fmtaddr(ia->ia_addr.sin_addr))); + dp->dad_arp_announce = ANNOUNCE_NUM; + goto announce; + } else if (dp->dad_arp_acount < dp->dad_arp_announce) { +announce: + /* + * Announce the address. + */ + ip = &IA_SIN(ifa)->sin_addr; + arprequest(ifa->ifa_ifp, ip, ip, + CLLADDR(ifa->ifa_ifp->if_sadl)); + dp->dad_arp_acount++; + if (dp->dad_arp_acount < dp->dad_arp_announce) { + arp_dad_starttimer(dp, ANNOUNCE_INTERVAL * hz); + goto done; + } + arplog((LOG_DEBUG, + "%s: ARP announcement complete for %s\n", + if_name(ifa->ifa_ifp), + in_fmtaddr(ia->ia_addr.sin_addr))); + } + + TAILQ_REMOVE(&dadq, dp, dad_list); + free(dp, M_IPARP); + dp = NULL; + ifafree(ifa); + +done: + KERNEL_UNLOCK_ONE(NULL); + mutex_exit(softnet_lock); +} + +static void +arp_dad_duplicated(struct ifaddr *ifa) +{ + struct in_ifaddr *ia = (struct in_ifaddr *)ifa; + struct ifnet *ifp; + struct dadq *dp; + + dp = arp_dad_find(ifa); + if (dp == NULL) { + log(LOG_ERR, "arp_dad_duplicated: DAD structure not found\n"); + return; + } + + ifp = ifa->ifa_ifp; + log(LOG_ERR, "%s: DAD detected duplicate IPv4 address %s: " + "ARP out=%d\n", + if_name(ifp), in_fmtaddr(ia->ia_addr.sin_addr), + dp->dad_arp_ocount); + + ia->ia4_flags &= ~IN_IFF_TENTATIVE; + ia->ia4_flags |= IN_IFF_DUPLICATED; + + /* We are done with DAD, with duplicated address found. (failure) */ + arp_dad_stoptimer(dp); + + /* Inform the routing socket that DAD has completed */ + rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL); + + TAILQ_REMOVE(&dadq, dp, dad_list); + free(dp, M_IPARP); + dp = NULL; + ifafree(ifa); +} + /* * Called from 10 Mb/s Ethernet interrupt handlers * when ether packet type ETHERTYPE_REVARP @@ -1734,6 +2082,13 @@ sysctl_net_inet_arp_setup(struct sysctll SYSCTL_DESCR("log ARP packets from non-local network"), NULL, 0, &log_unknown_network, 0, CTL_NET,PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "debug", + SYSCTL_DESCR("Enable ARP DAD debug output"), + NULL, 0, &arp_debug, 0, + CTL_NET, PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL); } #endif /* INET */ Index: src/sys/netinet/if_inarp.h diff -u src/sys/netinet/if_inarp.h:1.44 src/sys/netinet/if_inarp.h:1.45 --- src/sys/netinet/if_inarp.h:1.44 Sun Sep 30 05:13:12 2012 +++ src/sys/netinet/if_inarp.h Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_inarp.h,v 1.44 2012/09/30 05:13:12 dholland Exp $ */ +/* $NetBSD: if_inarp.h,v 1.45 2015/05/02 14:41:32 roy Exp $ */ /* * Copyright (c) 1982, 1986, 1993 @@ -56,6 +56,22 @@ struct sockaddr_inarp { }; #ifdef _KERNEL + +/* ARP timings from RFC5227 */ +#define PROBE_WAIT 1 +#define PROBE_NUM 3 +#define PROBE_MIN 1 +#define PROBE_MAX 2 +#define ANNOUNCE_WAIT 2 +#define ANNOUNCE_NUM 2 +#define ANNOUNCE_INTERVAL 2 +#define MAX_CONFLICTS 10 +#define RATE_LIMIT_INTERVAL 60 +#define DEFEND_INTERVAL 10 + +#include <sys/malloc.h> +MALLOC_DECLARE(M_IPARP); + extern struct ifqueue arpintrq; void arp_ifinit(struct ifnet *, struct ifaddr *); void arp_rtrequest(int, struct rtentry *, const struct rt_addrinfo *); @@ -69,6 +85,9 @@ void arp_drain(void); int arpioctl(u_long, void *); void arpwhohas(struct ifnet *, struct in_addr *); +void arp_dad_start(struct ifaddr *); +void arp_dad_stop(struct ifaddr *); + void revarpinput(struct mbuf *); void in_revarpinput(struct mbuf *); void revarprequest(struct ifnet *); Index: src/sys/netinet/in.c diff -u src/sys/netinet/in.c:1.151 src/sys/netinet/in.c:1.152 --- src/sys/netinet/in.c:1.151 Thu Feb 26 12:58:36 2015 +++ src/sys/netinet/in.c Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: in.c,v 1.151 2015/02/26 12:58:36 roy Exp $ */ +/* $NetBSD: in.c,v 1.152 2015/05/02 14:41:32 roy Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -91,7 +91,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.151 2015/02/26 12:58:36 roy Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.152 2015/05/02 14:41:32 roy Exp $"); #include "opt_inet.h" #include "opt_inet_conf.h" @@ -100,6 +100,7 @@ __KERNEL_RCSID(0, "$NetBSD: in.c,v 1.151 #include <sys/param.h> #include <sys/ioctl.h> #include <sys/errno.h> +#include <sys/kernel.h> #include <sys/malloc.h> #include <sys/socket.h> #include <sys/socketvar.h> @@ -373,6 +374,7 @@ in_control(struct socket *so, u_long cmd case SIOCAIFADDR: case SIOCDIFADDR: case SIOCGIFALIAS: + case SIOCGIFAFLAG_IN: if (ifra->ifra_addr.sin_family == AF_INET) LIST_FOREACH(ia, &IN_IFADDR_HASH(ifra->ifra_addr.sin_addr.s_addr), @@ -382,7 +384,10 @@ in_control(struct socket *so, u_long cmd ifra->ifra_addr.sin_addr)) break; } - if ((cmd == SIOCDIFADDR || cmd == SIOCGIFALIAS) && ia == NULL) + if ((cmd == SIOCDIFADDR || + cmd == SIOCGIFALIAS || + cmd == SIOCGIFAFLAG_IN) && + ia == NULL) return (EADDRNOTAVAIL); if (cmd == SIOCDIFADDR && @@ -391,6 +396,16 @@ in_control(struct socket *so, u_long cmd } /* FALLTHROUGH */ case SIOCSIFADDR: + hostIsNew = 1; + if (ia == NULL || ia->ia_addr.sin_family != AF_INET) + ; + else if (ifra->ifra_addr.sin_len == 0) { + ifra->ifra_addr = ia->ia_addr; + hostIsNew = 0; + } else if (in_hosteq(ia->ia_addr.sin_addr, + ifra->ifra_addr.sin_addr)) + hostIsNew = 0; + /* FALLTHROUGH */ case SIOCSIFDSTADDR: if (ifra->ifra_addr.sin_family != AF_INET) return (EAFNOSUPPORT); @@ -399,7 +414,7 @@ in_control(struct socket *so, u_long cmd if (ifp == NULL) panic("in_control"); - if (cmd == SIOCGIFALIAS) + if (cmd == SIOCGIFALIAS || cmd == SIOCGIFAFLAG_IN) break; if (ia == NULL && @@ -509,7 +524,7 @@ in_control(struct socket *so, u_long cmd case SIOCSIFADDR: error = in_ifinit(ifp, ia, satocsin(ifreq_getaddr(cmd, ifr)), - 1); + 1, hostIsNew); if (error == 0) { (void)pfil_run_hooks(if_pfil, (struct mbuf **)SIOCSIFADDR, ifp, PFIL_IFADDR); @@ -520,20 +535,11 @@ in_control(struct socket *so, u_long cmd in_ifscrub(ifp, ia); ia->ia_sockmask = *satocsin(ifreq_getaddr(cmd, ifr)); ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr; - error = in_ifinit(ifp, ia, NULL, 0); + error = in_ifinit(ifp, ia, NULL, 0, 0); break; case SIOCAIFADDR: maskIsNew = 0; - hostIsNew = 1; - if (ia->ia_addr.sin_family != AF_INET) - ; - else if (ifra->ifra_addr.sin_len == 0) { - ifra->ifra_addr = ia->ia_addr; - hostIsNew = 0; - } else if (in_hosteq(ia->ia_addr.sin_addr, - ifra->ifra_addr.sin_addr)) - hostIsNew = 0; if (ifra->ifra_mask.sin_len) { /* Only scrub if we control the prefix route, * otherwise userland gets a bogus message */ @@ -554,7 +560,8 @@ in_control(struct socket *so, u_long cmd } if (ifra->ifra_addr.sin_family == AF_INET && (hostIsNew || maskIsNew)) { - error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0); + error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0, + hostIsNew); } if ((ifp->if_flags & IFF_BROADCAST) && (ifra->ifra_broadaddr.sin_family == AF_INET)) @@ -577,6 +584,10 @@ in_control(struct socket *so, u_long cmd sizeof(ifra->ifra_broadaddr)); break; + case SIOCGIFAFLAG_IN: + ifr->ifr_addrflags = ia->ia4_flags; + break; + case SIOCDIFADDR: in_purgeaddr(&ia->ia_ifa); (void)pfil_run_hooks(if_pfil, (struct mbuf **)SIOCDIFADDR, @@ -652,6 +663,9 @@ in_purgeaddr(struct ifaddr *ifa) struct ifnet *ifp = ifa->ifa_ifp; struct in_ifaddr *ia = (void *) ifa; + /* stop DAD processing */ + arp_dad_stop(ifa); + in_ifscrub(ifp, ia); in_ifremlocal(ifa); LIST_REMOVE(ia, ia_hash); @@ -870,7 +884,7 @@ in_ifscrub(struct ifnet *ifp, struct in_ */ int in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, - const struct sockaddr_in *sin, int scrub) + const struct sockaddr_in *sin, int scrub, int hostIsNew) { u_int32_t i; struct sockaddr_in oldaddr; @@ -888,6 +902,14 @@ in_ifinit(struct ifnet *ifp, struct in_i ia->ia_addr = *sin; LIST_INSERT_HEAD(&IN_IFADDR_HASH(ia->ia_addr.sin_addr.s_addr), ia, ia_hash); + /* Set IN_IFF flags early for arp_ifinit() */ + if (hostIsNew && if_do_dad(ifp) && !in_nullhost(ia->ia_addr.sin_addr)) { + if (ifp->if_link_state == LINK_STATE_DOWN) + ia->ia4_flags |= IN_IFF_DETACHED; + else + ia->ia4_flags |= IN_IFF_TENTATIVE; + } + /* * Give the interface a chance to initialize * if this is its first address, @@ -956,6 +978,12 @@ in_ifinit(struct ifnet *ifp, struct in_i addr.s_addr = INADDR_ALLHOSTS_GROUP; ia->ia_allhosts = in_addmulti(&addr, ifp); } + + if (hostIsNew && if_do_dad(ifp) && + !in_nullhost(ia->ia_addr.sin_addr) && + ia->ia4_flags & IN_IFF_TENTATIVE) + arp_dad_start((struct ifaddr *)ia); + return (error); bad: splx(s); @@ -1122,6 +1150,101 @@ in_broadcast(struct in_addr in, struct i } /* + * perform DAD when interface becomes IFF_UP. + */ +void +in_if_link_up(struct ifnet *ifp) +{ + struct ifaddr *ifa; + struct in_ifaddr *ia; + + /* Ensure it's sane to run DAD */ + if (ifp->if_link_state == LINK_STATE_DOWN) + return; + if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) + return; + + IFADDR_FOREACH(ifa, ifp) { + if (ifa->ifa_addr->sa_family != AF_INET) + continue; + ia = (struct in_ifaddr *)ifa; + + /* If detached then mark as tentative */ + if (ia->ia4_flags & IN_IFF_DETACHED) { + ia->ia4_flags &= ~IN_IFF_DETACHED; + if (if_do_dad(ifp)) + ia->ia4_flags |= IN_IFF_TENTATIVE; + else if ((ia->ia4_flags & IN_IFF_TENTATIVE) == 0) + rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL); + } + + if (ia->ia4_flags & IN_IFF_TENTATIVE) { + /* Clear the duplicated flag as we're starting DAD. */ + ia->ia4_flags &= ~IN_IFF_DUPLICATED; + arp_dad_start(ifa); + } + } +} + +void +in_if_up(struct ifnet *ifp) +{ + + /* interface may not support link state, so bring it up also */ + in_if_link_up(ifp); +} + +/* + * Mark all addresses as detached. + */ +void +in_if_link_down(struct ifnet *ifp) +{ + struct ifaddr *ifa; + struct in_ifaddr *ia; + + IFADDR_FOREACH(ifa, ifp) { + if (ifa->ifa_addr->sa_family != AF_INET) + continue; + ia = (struct in_ifaddr *)ifa; + + /* Stop DAD processing */ + arp_dad_stop(ifa); + + /* + * Mark the address as detached. + */ + if (!(ia->ia4_flags & IN_IFF_DETACHED)) { + ia->ia4_flags |= IN_IFF_DETACHED; + ia->ia4_flags &= + ~(IN_IFF_TENTATIVE | IN_IFF_DUPLICATED); + rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL); + } + } +} + +void +in_if_down(struct ifnet *ifp) +{ + + in_if_link_down(ifp); +} + +void +in_if_link_state_change(struct ifnet *ifp, int link_state) +{ + + switch (link_state) { + case LINK_STATE_DOWN: + in_if_link_down(ifp); + break; + case LINK_STATE_UP: + in_if_link_up(ifp); + break; + } +} + +/* * in_lookup_multi: look up the in_multi record for a given IP * multicast address on a given interface. If no matching record is * found, return NULL. @@ -1375,7 +1498,7 @@ in_selectsrc(struct sockaddr_in *sin, st if (imo->imo_multicast_ifp != NULL) { ifp = imo->imo_multicast_ifp; IFP_TO_IA(ifp, ia); /* XXX */ - if (ia == 0) { + if (ia == 0 || ia->ia4_flags & IN_IFF_NOTREADY) { *errorp = EADDRNOTAVAIL; return NULL; } @@ -1384,6 +1507,10 @@ in_selectsrc(struct sockaddr_in *sin, st if (ia->ia_ifa.ifa_getifa != NULL) { ia = ifatoia((*ia->ia_ifa.ifa_getifa)(&ia->ia_ifa, sintosa(sin))); + if (ia == NULL) { + *errorp = EADDRNOTAVAIL; + return NULL; + } } #ifdef GETIFA_DEBUG else Index: src/sys/netinet/in.h diff -u src/sys/netinet/in.h:1.96 src/sys/netinet/in.h:1.97 --- src/sys/netinet/in.h:1.96 Tue Feb 10 19:11:52 2015 +++ src/sys/netinet/in.h Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: in.h,v 1.96 2015/02/10 19:11:52 rjs Exp $ */ +/* $NetBSD: in.h,v 1.97 2015/05/02 14:41:32 roy Exp $ */ /* * Copyright (c) 1982, 1986, 1990, 1993 @@ -467,7 +467,8 @@ struct ip_mreq { #define IPCTL_RANDOMID 22 /* use random IP ids (if configured) */ #define IPCTL_LOOPBACKCKSUM 23 /* do IP checksum on loopback */ #define IPCTL_STATS 24 /* IP statistics */ -#define IPCTL_MAXID 25 +#define IPCTL_DAD_COUNT 25 /* DAD packets to send */ +#define IPCTL_MAXID 26 #define IPCTL_NAMES { \ { 0, 0 }, \ @@ -495,6 +496,7 @@ struct ip_mreq { { "random_id", CTLTYPE_INT }, \ { "do_loopback_cksum", CTLTYPE_INT }, \ { "stats", CTLTYPE_STRUCT }, \ + { "dad_count", CTLTYPE_INT }, \ } #endif /* _NETBSD_SOURCE */ @@ -564,6 +566,12 @@ void in_delayed_cksum(struct mbuf *); int in_localaddr(struct in_addr); void in_socktrim(struct sockaddr_in *); +void in_if_link_up(struct ifnet *); +void in_if_link_down(struct ifnet *); +void in_if_up(struct ifnet *); +void in_if_down(struct ifnet *); +void in_if_link_state_change(struct ifnet *, int); + struct route; struct ip_moptions; Index: src/sys/netinet/in_pcb.c diff -u src/sys/netinet/in_pcb.c:1.158 src/sys/netinet/in_pcb.c:1.159 --- src/sys/netinet/in_pcb.c:1.158 Sun Apr 26 16:45:51 2015 +++ src/sys/netinet/in_pcb.c Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: in_pcb.c,v 1.158 2015/04/26 16:45:51 rtr Exp $ */ +/* $NetBSD: in_pcb.c,v 1.159 2015/05/02 14:41:32 roy Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -93,7 +93,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.158 2015/04/26 16:45:51 rtr Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.159 2015/05/02 14:41:32 roy Exp $"); #include "opt_inet.h" #include "opt_ipsec.h" @@ -287,6 +287,8 @@ in_pcbbind_addr(struct inpcb *inp, struc ia = ifatoia(ifa_ifwithaddr(sintosa(sin))); if (ia == NULL) return (EADDRNOTAVAIL); + if (ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED)) + return (EADDRNOTAVAIL); } inp->inp_laddr = sin->sin_addr; Index: src/sys/netinet/in_proto.c diff -u src/sys/netinet/in_proto.c:1.111 src/sys/netinet/in_proto.c:1.112 --- src/sys/netinet/in_proto.c:1.111 Tue Feb 10 19:11:52 2015 +++ src/sys/netinet/in_proto.c Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: in_proto.c,v 1.111 2015/02/10 19:11:52 rjs Exp $ */ +/* $NetBSD: in_proto.c,v 1.112 2015/05/02 14:41:32 roy Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -61,7 +61,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.111 2015/02/10 19:11:52 rjs Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.112 2015/05/02 14:41:32 roy Exp $"); #include "opt_mrouting.h" #include "opt_inet.h" @@ -384,6 +384,8 @@ struct domain inetdomain = { .dom_rtattach = rt_inithead, .dom_rtoffset = 32, .dom_maxrtkey = sizeof(struct ip_pack4), + .dom_if_up = in_if_up, + .dom_if_down = in_if_down, #ifdef IPSELSRC .dom_ifattach = in_domifattach, .dom_ifdetach = in_domifdetach, @@ -391,6 +393,7 @@ struct domain inetdomain = { .dom_ifattach = NULL, .dom_ifdetach = NULL, #endif + .dom_if_link_state_change = in_if_link_state_change, .dom_ifqueues = { NULL, NULL }, .dom_link = { NULL }, .dom_mowner = MOWNER_INIT("",""), Index: src/sys/netinet/in_selsrc.c diff -u src/sys/netinet/in_selsrc.c:1.11 src/sys/netinet/in_selsrc.c:1.12 --- src/sys/netinet/in_selsrc.c:1.11 Tue Feb 25 18:30:12 2014 +++ src/sys/netinet/in_selsrc.c Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: in_selsrc.c,v 1.11 2014/02/25 18:30:12 pooka Exp $ */ +/* $NetBSD: in_selsrc.c,v 1.12 2015/05/02 14:41:32 roy Exp $ */ /*- * Copyright (c) 2005 David Young. All rights reserved. @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in_selsrc.c,v 1.11 2014/02/25 18:30:12 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in_selsrc.c,v 1.12 2015/05/02 14:41:32 roy Exp $"); #include "opt_inet.h" #include "opt_inet_conf.h" @@ -300,6 +300,7 @@ in_getifa(struct ifaddr *ifa, const stru struct in_ifsysctl *isc; struct in_ifselsrc *iss; int best_score[IN_SCORE_SRC_MAX], score[IN_SCORE_SRC_MAX]; + struct in_ifaddr *ia; if (ifa->ifa_addr->sa_family != AF_INET || dst0 == NULL || dst0->sa_family != AF_INET) { /* Possible. */ @@ -346,6 +347,9 @@ in_getifa(struct ifaddr *ifa, const stru if (alt_ifa == ifa || src->sin_family != AF_INET) continue; + ia = (struct in_ifaddr *)alt_ifa; + if (ia->ia4_flags & IN_IFF_NOTREADY) + continue; in_score(score_src, score, NULL, &src->sin_addr, alt_ifa->ifa_preference, idx, &dst->sin_addr); @@ -363,6 +367,13 @@ in_getifa(struct ifaddr *ifa, const stru best_ifa = alt_ifa; } } + + ia = (struct in_ifaddr *)best_ifa; + if (ia->ia4_flags & IN_IFF_NOTREADY) { + errno = EADDRNOTAVAIL; + return NULL; + } + #ifdef GETIFA_DEBUG if (in_selsrc_debug) { printf("%s: choose src %#" PRIx32 " score ", __func__, Index: src/sys/netinet/in_var.h diff -u src/sys/netinet/in_var.h:1.70 src/sys/netinet/in_var.h:1.71 --- src/sys/netinet/in_var.h:1.70 Tue Jul 1 05:49:18 2014 +++ src/sys/netinet/in_var.h Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: in_var.h,v 1.70 2014/07/01 05:49:18 rtr Exp $ */ +/* $NetBSD: in_var.h,v 1.71 2015/05/02 14:41:32 roy Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -66,6 +66,13 @@ #include <sys/queue.h> +#define IN_IFF_TENTATIVE 0x01 /* tentative address */ +#define IN_IFF_DUPLICATED 0x02 /* DAD detected duplicate */ +#define IN_IFF_DETACHED 0x04 /* may be detached from the link */ + +/* do not input/output */ +#define IN_IFF_NOTREADY (IN_IFF_TENTATIVE | IN_IFF_DUPLICATED) + /* * Interface address, Internet version. One of these structures * is allocated for each interface with an Internet address. @@ -92,6 +99,7 @@ struct in_ifaddr { struct in_multi *ia_allhosts; /* multicast address record for the allhosts multicast group */ uint16_t ia_idsalt; /* ip_id salt for this ia */ + int ia4_flags; /* address flags */ }; struct in_aliasreq { @@ -101,6 +109,7 @@ struct in_aliasreq { #define ifra_broadaddr ifra_dstaddr struct sockaddr_in ifra_mask; }; + /* * Given a pointer to an in_ifaddr (ifaddr), * return a pointer to the addr as a sockaddr_in. @@ -217,6 +226,8 @@ struct in_multi { extern pktqueue_t *ip_pktq; +extern int ip_dad_count; /* Duplicate Address Detection probes */ + /* * Structure used by functions below to remember position when stepping * through all of the in_multi records. @@ -240,7 +251,7 @@ int in_multi_lock_held(void); struct ifaddr; int in_ifinit(struct ifnet *, - struct in_ifaddr *, const struct sockaddr_in *, int); + struct in_ifaddr *, const struct sockaddr_in *, int, int); void in_savemkludge(struct in_ifaddr *); void in_restoremkludge(struct in_ifaddr *, struct ifnet *); void in_purgemkludge(struct ifnet *); Index: src/sys/netinet/ip_icmp.c diff -u src/sys/netinet/ip_icmp.c:1.137 src/sys/netinet/ip_icmp.c:1.138 --- src/sys/netinet/ip_icmp.c:1.137 Fri Apr 24 03:20:41 2015 +++ src/sys/netinet/ip_icmp.c Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_icmp.c,v 1.137 2015/04/24 03:20:41 ozaki-r Exp $ */ +/* $NetBSD: ip_icmp.c,v 1.138 2015/05/02 14:41:32 roy Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -94,7 +94,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.137 2015/04/24 03:20:41 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.138 2015/05/02 14:41:32 roy Exp $"); #include "opt_ipsec.h" @@ -703,6 +703,8 @@ icmp_reflect(struct mbuf *m) /* Look for packet addressed to us */ INADDR_TO_IA(t, ia); + if (ia->ia4_flags & IN_IFF_NOTREADY) + ia = NULL; /* look for packet sent to broadcast address */ if (ia == NULL && m->m_pkthdr.rcvif && @@ -712,7 +714,9 @@ icmp_reflect(struct mbuf *m) continue; if (in_hosteq(t,ifatoia(ifa)->ia_broadaddr.sin_addr)) { ia = ifatoia(ifa); - break; + if ((ia->ia4_flags & IN_IFF_NOTREADY) == 0) + break; + ia = NULL; } } } Index: src/sys/netinet/ip_input.c diff -u src/sys/netinet/ip_input.c:1.320 src/sys/netinet/ip_input.c:1.321 --- src/sys/netinet/ip_input.c:1.320 Thu Mar 26 04:05:58 2015 +++ src/sys/netinet/ip_input.c Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.320 2015/03/26 04:05:58 ozaki-r Exp $ */ +/* $NetBSD: ip_input.c,v 1.321 2015/05/02 14:41:32 roy Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -91,7 +91,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.320 2015/03/26 04:05:58 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.321 2015/05/02 14:41:32 roy Exp $"); #include "opt_inet.h" #include "opt_compat_netbsd.h" @@ -593,11 +593,13 @@ ip_input(struct mbuf *m) * * Traditional 4.4BSD did not consult IFF_UP at all. * The behavior here is to treat addresses on !IFF_UP interface - * as not mine. + * or IN_IFF_NOTREADY addresses as not mine. */ downmatch = 0; LIST_FOREACH(ia, &IN_IFADDR_HASH(ip->ip_dst.s_addr), ia_hash) { if (in_hosteq(ia->ia_addr.sin_addr, ip->ip_dst)) { + if (ia->ia4_flags & IN_IFF_NOTREADY) + continue; if (checkif && ia->ia_ifp != ifp) continue; if ((ia->ia_ifp->if_flags & IFF_UP) != 0) @@ -613,6 +615,8 @@ ip_input(struct mbuf *m) if (ifa->ifa_addr->sa_family != AF_INET) continue; ia = ifatoia(ifa); + if (ia->ia4_flags & IN_IFF_NOTREADY) + continue; if (in_hosteq(ip->ip_dst, ia->ia_broadaddr.sin_addr) || in_hosteq(ip->ip_dst, ia->ia_netbroadcast) || /* @@ -1641,6 +1645,14 @@ sysctl_net_inet_ip_setup(struct sysctllo sysctl_net_inet_ip_stats, 0, NULL, 0, CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS, CTL_EOL); + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "dad_count", + SYSCTL_DESCR("Number of Duplicate Address Detection " + "probes to send"), + NULL, 0, &ip_dad_count, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_DAD_COUNT, CTL_EOL); /* anonportalgo RFC6056 subtree */ const struct sysctlnode *portalgo_node; Index: src/sys/netinet/raw_ip.c diff -u src/sys/netinet/raw_ip.c:1.150 src/sys/netinet/raw_ip.c:1.151 --- src/sys/netinet/raw_ip.c:1.150 Sun Apr 26 21:40:49 2015 +++ src/sys/netinet/raw_ip.c Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: raw_ip.c,v 1.150 2015/04/26 21:40:49 rtr Exp $ */ +/* $NetBSD: raw_ip.c,v 1.151 2015/05/02 14:41:32 roy Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -65,7 +65,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1.150 2015/04/26 21:40:49 rtr Exp $"); +__KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1.151 2015/05/02 14:41:32 roy Exp $"); #include "opt_inet.h" #include "opt_compat_netbsd.h" @@ -560,6 +560,7 @@ rip_bind(struct socket *so, struct socka struct sockaddr_in *addr = (struct sockaddr_in *)nam; int error = 0; int s; + struct ifaddr *ia; KASSERT(solocked(so)); KASSERT(inp != NULL); @@ -577,11 +578,19 @@ rip_bind(struct socket *so, struct socka error = EAFNOSUPPORT; goto release; } - if (!in_nullhost(addr->sin_addr) && - ifa_ifwithaddr(sintosa(addr)) == 0) { + if ((ia = ifa_ifwithaddr(sintosa(addr))) == 0 && + !in_nullhost(addr->sin_addr)) + { error = EADDRNOTAVAIL; goto release; } + if (ia && ((struct in_ifaddr *)ia)->ia4_flags & + (IN6_IFF_NOTREADY | IN_IFF_DETACHED)) + { + error = EADDRNOTAVAIL; + goto release; + } + inp->inp_laddr = addr->sin_addr; release: Index: src/sys/sys/sockio.h diff -u src/sys/sys/sockio.h:1.32 src/sys/sys/sockio.h:1.33 --- src/sys/sys/sockio.h:1.32 Sat Oct 5 23:16:54 2013 +++ src/sys/sys/sockio.h Sat May 2 14:41:32 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sockio.h,v 1.32 2013/10/05 23:16:54 christos Exp $ */ +/* $NetBSD: sockio.h,v 1.33 2015/05/02 14:41:32 roy Exp $ */ /*- * Copyright (c) 1982, 1986, 1990, 1993, 1994 @@ -72,6 +72,7 @@ #define SIOCAIFADDR _IOW('i', 26, struct ifaliasreq)/* add/chg IF alias */ #define SIOCGIFALIAS _IOWR('i', 27, struct ifaliasreq)/* get IF alias */ +#define SIOCGIFAFLAG_IN _IOWR('i', 39, struct ifreq) /* get addr flags */ #define SIOCALIFADDR _IOW('i', 28, struct if_laddrreq) /* add IF addr */ #define SIOCGLIFADDR _IOWR('i', 29, struct if_laddrreq) /* get IF addr */