tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
IPv4 Address Flags
Hi List
As discussed here [1], a few people voiced their opinion that they
didn't like address removal when the carrier drops and would rather
re-negotiate at carrier up. The first step of doing this is to add IPv6
address flag semantics to IPv4 addresses.
This patch adds the following flags to IPv4 and mimics the IPv6
behaviour of the same flags:
IN_IFF_TENTATIVE
IN_IFF_DUPLICATED
IN_IFF_DETACHED
IN_IFF_NOTREADY (IN_IFF_TENTATIVE | IN_IFF_DUPLICATED)
ioctl SIOCGIFAFLAG_IN has been added to retrieve the flags using a ifreq
struct (ifaliasreq is probably better but then we run into compatibility
issues, also why IN_IFF_NODAD is not implemented).
ifconfig(8) has been modified to report the new flags and wait for
tentative to vanish via -w alongside the IPv6 addresses.
sysctl(8) now has these new values:
net.inet.ip.dad_count=3
net.inet.arp.debug=0
DAD is implemented according to RFC 5227.
A future patch could be made to implement address defence from the RFC,
but this is optional (although required for IPv4LL, but dhcpcd will
handle that).
It's easy to see this patch working, simply run ntpd, reboot and watch
it complain that it cannot bind to IPv4 tentative addresses.
Commentary welcome, especially on ideas of how to make IN_IFF_NODAD or
ifaliasreq work with the above.
Roy
[1] http://mail-index.netbsd.org/tech-net/2015/04/07/msg005053.html
Index: sbin/ifconfig/af_inet.c
===================================================================
RCS file: /cvsroot/src/sbin/ifconfig/af_inet.c,v
retrieving revision 1.15
diff -u -r1.15 af_inet.c
--- sbin/ifconfig/af_inet.c 13 Dec 2010 17:35:08 -0000 1.15
+++ sbin/ifconfig/af_inet.c 21 Apr 2015 08:30:16 -0000
@@ -137,6 +137,21 @@
strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
printf(" broadcast %s", hbuf);
}
+
+#ifdef IN_IFF_TENTATIVE
+ memcpy(&ifr.ifr_addr, &creq->ifra_addr, creq->ifra_addr.sin_len);
+ if (prog_ioctl(s, SIOCGIFAFLAG_IN, &ifr) == -1) {
+ if (errno != EADDRNOTAVAIL)
+ warn("SIOCGIFAFLAG_IN");
+ } else {
+ if (ifr.ifr_flags4 & IN_IFF_TENTATIVE)
+ printf(" tentative");
+ if (ifr.ifr_flags4 & IN_IFF_DUPLICATED)
+ printf(" duplicated");
+ if (ifr.ifr_flags4 & IN_IFF_DETACHED)
+ printf(" detached");
+ }
+#endif
}
static void
Index: sbin/ifconfig/ifconfig.c
===================================================================
RCS file: /cvsroot/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.233
diff -u -r1.233 ifconfig.c
--- sbin/ifconfig/ifconfig.c 12 Sep 2014 08:54:26 -0000 1.233
+++ sbin/ifconfig/ifconfig.c 21 Apr 2015 08:30:16 -0000
@@ -515,10 +515,14 @@
static int
wait_dad_exec(prop_dictionary_t env, prop_dictionary_t oenv)
{
-#ifdef INET6
bool waiting;
struct ifaddrs *ifaddrs, *ifa;
+#ifdef IN_IFF_TENTATIVE
+ struct ifreq ifr;
+#endif
+#ifdef INET6
struct in6_ifreq ifr6;
+#endif
int s;
const struct timespec ts = { .tv_sec = 0, .tv_nsec = WAIT_DAD };
const struct timespec add = { .tv_sec = wflag_secs, .tv_nsec = 0};
@@ -539,6 +543,22 @@
if (ifa->ifa_addr == NULL)
continue;
switch (ifa->ifa_addr->sa_family) {
+#ifdef IN_IFF_TENTATIVE
+ case AF_INET:
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name,
+ ifa->ifa_name, sizeof(ifr.ifr_name));
+ ifr.ifr_addr = *ifa->ifa_addr;
+ if ((s = getsock(AF_INET)) == -1)
+ err(EXIT_FAILURE,
+ "%s: getsock", __func__);
+ if (ioctl(s, SIOCGIFAFLAG_IN, &ifr) == -1)
+ err(EXIT_FAILURE, "SIOCGIFAFLAG_IN");
+ if (ifr.ifr_flags4 & IN_IFF_TENTATIVE)
+ waiting = true;
+ break;
+#endif
+#ifdef INET6
case AF_INET6:
memset(&ifr6, 0, sizeof(ifr6));
strncpy(ifr6.ifr_name,
@@ -552,13 +572,13 @@
err(EXIT_FAILURE, "SIOCGIFAFLAG_IN6");
if (ifr6.ifr_ifru.ifru_flags6 &
IN6_IFF_TENTATIVE)
- {
waiting = true;
- break;
- }
+ break;
+#endif
}
if (waiting)
break;
+
}
if (!waiting)
break;
@@ -572,7 +592,6 @@
}
freeifaddrs(ifaddrs);
-#endif
exit(EXIT_SUCCESS);
}
Index: sys/net/if.c
===================================================================
RCS file: /cvsroot/src/sys/net/if.c,v
retrieving revision 1.310
diff -u -r1.310 if.c
--- sys/net/if.c 20 Apr 2015 10:19:54 -0000 1.310
+++ sys/net/if.c 21 Apr 2015 08:30:45 -0000
@@ -1446,20 +1446,26 @@
"UNKNOWN");
#endif
-#ifdef INET6
/*
* When going from UNKNOWN to UP, we need to mark existing
- * IPv6 addresses as tentative and restart DAD as we may have
+ * addresses as tentative and restart DAD as we may have
* erroneously not found a duplicate.
*
* This needs to happen before rt_ifmsg to avoid a race where
* listeners would have an address and expect it to work right
* away.
*/
- if (in6_present && link_state == LINK_STATE_UP &&
+ if (link_state == LINK_STATE_UP &&
old_link_state == LINK_STATE_UNKNOWN)
- in6_if_link_down(ifp);
+ {
+#ifdef INET
+ in_if_link_down(ifp);
+#endif
+#ifdef INET6
+ if (in6_present)
+ in6_if_link_down(ifp);
#endif
+ }
/* Notify that the link state has changed. */
rt_ifmsg(ifp);
@@ -1469,14 +1475,23 @@
carp_carpdev_state(ifp);
#endif
+ if (link_state == LINK_STATE_DOWN) {
+#ifdef INET
+ in_if_link_down(ifp);
+#endif
#ifdef INET6
- if (in6_present) {
- if (link_state == LINK_STATE_DOWN)
+ if (in6_present)
in6_if_link_down(ifp);
- else if (link_state == LINK_STATE_UP)
+#endif
+ } else if (link_state == LINK_STATE_UP) {
+#ifdef INET
+ in_if_link_up(ifp);
+#endif
+#ifdef INET6
+ if (in6_present)
in6_if_link_up(ifp);
- }
#endif
+ }
splx(s);
}
@@ -1553,6 +1568,9 @@
carp_carpdev_state(ifp);
#endif
rt_ifmsg(ifp);
+#ifdef INET
+ in_if_down(ifp);
+#endif
#ifdef INET6
if (in6_present)
in6_if_down(ifp);
@@ -1583,6 +1601,9 @@
carp_carpdev_state(ifp);
#endif
rt_ifmsg(ifp);
+#ifdef INET
+ in_if_up(ifp);
+#endif
#ifdef INET6
if (in6_present)
in6_if_up(ifp);
@@ -2066,13 +2087,16 @@
}
if (((oif_flags ^ ifp->if_flags) & IFF_UP) != 0) {
+ int s = splnet();
+#ifdef INET
+ in_if_up(ifp);
+#endif
#ifdef INET6
- if (in6_present && (ifp->if_flags & IFF_UP) != 0) {
- int s = splnet();
+ if (in6_present && (ifp->if_flags & IFF_UP) != 0)
in6_if_up(ifp);
- splx(s);
- }
#endif
+
+ splx(s);
}
#ifdef COMPAT_OIFREQ
if (cmd != ocmd)
Index: sys/net/if.h
===================================================================
RCS file: /cvsroot/src/sys/net/if.h,v
retrieving revision 1.188
diff -u -r1.188 if.h
--- sys/net/if.h 20 Apr 2015 10:19:54 -0000 1.188
+++ sys/net/if.h 21 Apr 2015 08:30:46 -0000
@@ -594,6 +594,7 @@
struct sockaddr ifru_broadaddr;
struct sockaddr_storage ifru_space;
short ifru_flags;
+ int ifru_flags4;
int ifru_metric;
int ifru_mtu;
int ifru_dlt;
@@ -609,6 +610,7 @@
#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_flags4 ifr_ifru.ifru_flags4 /* 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: sys/net/if_spppsubr.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_spppsubr.c,v
retrieving revision 1.132
diff -u -r1.132 if_spppsubr.c
--- sys/net/if_spppsubr.c 20 Apr 2015 10:19:54 -0000 1.132
+++ sys/net/if_spppsubr.c 21 Apr 2015 08:30:48 -0000
@@ -4875,7 +4875,7 @@
found:
{
- int error;
+ int error, hostIsNew;
struct sockaddr_in new_sin = *si;
struct sockaddr_in new_dst = *dest;
@@ -4886,8 +4886,13 @@
*/
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 @@
*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 @@
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: sys/netinet/if_arp.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/if_arp.c,v
retrieving revision 1.162
diff -u -r1.162 if_arp.c
--- sys/netinet/if_arp.c 23 Mar 2015 18:33:17 -0000 1.162
+++ sys/netinet/if_arp.c 21 Apr 2015 08:30:49 -0000
@@ -95,6 +95,7 @@
#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 @@
#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 @@
#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 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 @@
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 @@
}
/* 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 @@
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 @@
/*
* 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 @@
}
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 @@
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_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: sys/netinet/if_inarp.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/if_inarp.h,v
retrieving revision 1.44
diff -u -r1.44 if_inarp.h
--- sys/netinet/if_inarp.h 30 Sep 2012 05:13:12 -0000 1.44
+++ sys/netinet/if_inarp.h 21 Apr 2015 08:30:49 -0000
@@ -56,6 +56,22 @@
};
#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 @@
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: sys/netinet/in.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.c,v
retrieving revision 1.151
diff -u -r1.151 in.c
--- sys/netinet/in.c 26 Feb 2015 12:58:36 -0000 1.151
+++ sys/netinet/in.c 21 Apr 2015 08:30:49 -0000
@@ -100,6 +100,7 @@
#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>
@@ -391,6 +392,16 @@
}
/* 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);
@@ -439,6 +450,24 @@
}
break;
+ case SIOCGIFAFLAG_IN:
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+ struct sockaddr_in *sa;
+
+ sa = (struct sockaddr_in *)&ifr->ifr_addr;
+ LIST_FOREACH(ia,
+ &IN_IFADDR_HASH(sa->sin_addr.s_addr),
+ ia_hash) {
+ if (ia->ia_ifp == ifp &&
+ in_hosteq(ia->ia_addr.sin_addr,
+ ifra->ifra_addr.sin_addr))
+ break;
+ }
+ }
+ if (ia == NULL)
+ return (EADDRNOTAVAIL);
+ break;
+
case SIOCSIFBRDADDR:
if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_INTERFACE,
KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
@@ -509,7 +538,7 @@
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 +549,11 @@
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 +574,8 @@
}
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 +598,10 @@
sizeof(ifra->ifra_broadaddr));
break;
+ case SIOCGIFAFLAG_IN:
+ ifr->ifr_flags4 = ia->ia4_flags;
+ break;
+
case SIOCDIFADDR:
in_purgeaddr(&ia->ia_ifa);
(void)pfil_run_hooks(if_pfil, (struct mbuf **)SIOCDIFADDR,
@@ -652,6 +677,9 @@
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 +898,7 @@
*/
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 +916,14 @@
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 +992,12 @@
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 +1164,87 @@
}
/*
+ * 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);
+}
+
+/*
* 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 @@
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 @@
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: sys/netinet/in.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.h,v
retrieving revision 1.96
diff -u -r1.96 in.h
--- sys/netinet/in.h 10 Feb 2015 19:11:52 -0000 1.96
+++ sys/netinet/in.h 21 Apr 2015 08:30:50 -0000
@@ -467,7 +467,8 @@
#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 @@
{ "random_id", CTLTYPE_INT }, \
{ "do_loopback_cksum", CTLTYPE_INT }, \
{ "stats", CTLTYPE_STRUCT }, \
+ { "dad_count", CTLTYPE_INT }, \
}
#endif /* _NETBSD_SOURCE */
@@ -564,6 +566,11 @@
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 *);
+
struct route;
struct ip_moptions;
Index: sys/netinet/in_pcb.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_pcb.c,v
retrieving revision 1.156
diff -u -r1.156 in_pcb.c
--- sys/netinet/in_pcb.c 3 Apr 2015 20:01:07 -0000 1.156
+++ sys/netinet/in_pcb.c 21 Apr 2015 08:30:50 -0000
@@ -287,6 +287,8 @@
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: sys/netinet/in_selsrc.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_selsrc.c,v
retrieving revision 1.11
diff -u -r1.11 in_selsrc.c
--- sys/netinet/in_selsrc.c 25 Feb 2014 18:30:12 -0000 1.11
+++ sys/netinet/in_selsrc.c 21 Apr 2015 08:30:50 -0000
@@ -300,6 +300,7 @@
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 @@
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 @@
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: sys/netinet/in_var.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_var.h,v
retrieving revision 1.70
diff -u -r1.70 in_var.h
--- sys/netinet/in_var.h 1 Jul 2014 05:49:18 -0000 1.70
+++ sys/netinet/in_var.h 21 Apr 2015 08:30:51 -0000
@@ -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_multi *ia_allhosts; /* multicast address record for
the allhosts multicast group */
uint16_t ia_idsalt; /* ip_id salt for this ia */
+ int ia4_flags;
};
struct in_aliasreq {
@@ -217,6 +225,8 @@
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 +250,7 @@
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: sys/netinet/ip_icmp.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_icmp.c,v
retrieving revision 1.135
diff -u -r1.135 ip_icmp.c
--- sys/netinet/ip_icmp.c 2 Dec 2014 20:25:47 -0000 1.135
+++ sys/netinet/ip_icmp.c 21 Apr 2015 08:30:52 -0000
@@ -703,6 +703,8 @@
/* 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 @@
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: sys/netinet/ip_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_input.c,v
retrieving revision 1.320
diff -u -r1.320 ip_input.c
--- sys/netinet/ip_input.c 26 Mar 2015 04:05:58 -0000 1.320
+++ sys/netinet/ip_input.c 21 Apr 2015 08:30:52 -0000
@@ -593,11 +593,13 @@
*
* 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 @@
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_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: sys/netinet/raw_ip.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/raw_ip.c,v
retrieving revision 1.147
diff -u -r1.147 raw_ip.c
--- sys/netinet/raw_ip.c 3 Apr 2015 20:01:07 -0000 1.147
+++ sys/netinet/raw_ip.c 21 Apr 2015 08:30:53 -0000
@@ -563,6 +563,7 @@
struct sockaddr_in *addr = (struct sockaddr_in *)nam;
int error = 0;
int s;
+ struct ifaddr *ia;
KASSERT(solocked(so));
KASSERT(inp != NULL);
@@ -580,11 +581,19 @@
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: sys/sys/sockio.h
===================================================================
RCS file: /cvsroot/src/sys/sys/sockio.h,v
retrieving revision 1.32
diff -u -r1.32 sockio.h
--- sys/sys/sockio.h 5 Oct 2013 23:16:54 -0000 1.32
+++ sys/sys/sockio.h 21 Apr 2015 08:30:54 -0000
@@ -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 */
Home |
Main Index |
Thread Index |
Old Index