tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: IPv4 Address Flags
On 21/04/2015 09:46, Roy Marples wrote:
> 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)
New patch attached after making already committed adjustments to make a
few things more protocol agnostic.
Suggested by dyoung@
Roy
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 22 Apr 2015 21:02:41 -0000
@@ -62,12 +62,14 @@
static void in_constructor(void) __attribute__((constructor));
static void in_status(prop_dictionary_t, prop_dictionary_t, bool);
static void in_commit_address(prop_dictionary_t, prop_dictionary_t);
+static bool in_addr_tentative(struct ifaddrs *ifa);
static void in_alias(const char *, prop_dictionary_t, prop_dictionary_t,
struct in_aliasreq *);
static struct afswtch af = {
.af_name = "inet", .af_af = AF_INET, .af_status = in_status,
- .af_addr_commit = in_commit_address
+ .af_addr_commit = in_commit_address,
+ .af_addr_tentative = in_addr_tentative
};
static void
@@ -137,6 +139,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_addrflags & IN_IFF_TENTATIVE)
+ printf(" tentative");
+ if (ifr.ifr_addrflags & IN_IFF_DUPLICATED)
+ printf(" duplicated");
+ if (ifr.ifr_addrflags & IN_IFF_DETACHED)
+ printf(" detached");
+ }
+#endif
}
static void
@@ -203,6 +220,26 @@
commit_address(env, oenv, &inparam);
}
+static bool
+in_addr_tentative(struct ifaddrs *ifa)
+{
+#ifdef IN_IFF_TENTATIVE
+ int s;
+ struct ifreq ifr;
+
+ 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");
+ return ifr.ifr_addrflags & IN_IFF_TENTATIVE ? true : false;
+#else
+ return false;
+#endif
+}
+
static void
in_constructor(void)
{
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 22 Apr 2015 21:03:01 -0000
@@ -594,6 +594,7 @@
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 @@
#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: 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 22 Apr 2015 21:03:04 -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 22 Apr 2015 21:03:05 -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 22 Apr 2015 21:03:05 -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 22 Apr 2015 21:03:06 -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>
@@ -373,6 +374,7 @@
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 @@
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 @@
}
/* 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 @@
if (ifp == NULL)
panic("in_control");
- if (cmd == SIOCGIFALIAS)
+ if (cmd == SIOCGIFALIAS || cmd == SIOCGIFAFLAG_IN)
break;
if (ia == NULL &&
@@ -509,7 +524,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 +535,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 +560,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 +584,10 @@
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 @@
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 @@
*/
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 @@
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 @@
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 @@
}
/*
+ * 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 @@
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 22 Apr 2015 21:03:07 -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,12 @@
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: 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 22 Apr 2015 21:03:07 -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_proto.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_proto.c,v
retrieving revision 1.111
diff -u -r1.111 in_proto.c
--- sys/netinet/in_proto.c 10 Feb 2015 19:11:52 -0000 1.111
+++ sys/netinet/in_proto.c 22 Apr 2015 21:03:07 -0000
@@ -384,6 +384,8 @@
.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 @@
.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: 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 22 Apr 2015 21:03:07 -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 22 Apr 2015 21:03:08 -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; /* address flags */
};
struct in_aliasreq {
@@ -101,6 +109,7 @@
#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 @@
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 @@
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 22 Apr 2015 21:03:08 -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 22 Apr 2015 21:03:09 -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 22 Apr 2015 21:03:09 -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/netinet6/nd6_rtr.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/nd6_rtr.c,v
retrieving revision 1.98
diff -u -r1.98 nd6_rtr.c
--- sys/netinet6/nd6_rtr.c 25 Feb 2015 12:45:34 -0000 1.98
+++ sys/netinet6/nd6_rtr.c 22 Apr 2015 21:03:12 -0000
@@ -272,8 +272,15 @@
}
if (nd_ra->nd_ra_retransmit)
ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
- if (nd_ra->nd_ra_curhoplimit)
- ndi->chlim = nd_ra->nd_ra_curhoplimit;
+ if (nd_ra->nd_ra_curhoplimit) {
+ if (ndi->chlim < nd_ra->nd_ra_curhoplimit)
+ ndi->chlim = nd_ra->nd_ra_curhoplimit;
+ else if (ndi->chlim != nd_ra->nd_ra_curhoplimit)
+ log(LOG_ERR, "nd_ra_input: lower CurHopLimit sent from "
+ "%s on %s (current=%d, received=%d), ignored\n",
+ ip6_sprintf(&ip6->ip6_src),
+ if_name(ifp), ndi->chlim, nd_ra->nd_ra_curhoplimit);
+ }
dr = defrtrlist_update(&drtr);
}
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 22 Apr 2015 21:03:13 -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