Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Add IPv4 address flags IN_IFF_TENTATIVE, IN_IFF_DUPLICAT...



details:   https://anonhg.NetBSD.org/src/rev/f40cac8e8ae3
branches:  trunk
changeset: 337878:f40cac8e8ae3
user:      roy <roy%NetBSD.org@localhost>
date:      Sat May 02 14:41:32 2015 +0000

description:
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@

diffstat:

 sys/net/if.h            |    4 +-
 sys/net/if_spppsubr.c   |   19 +-
 sys/netinet/if_arp.c    |  395 +++++++++++++++++++++++++++++++++++++++++++++--
 sys/netinet/if_inarp.h  |   21 ++-
 sys/netinet/in.c        |  163 +++++++++++++++++--
 sys/netinet/in.h        |   12 +-
 sys/netinet/in_pcb.c    |    6 +-
 sys/netinet/in_proto.c  |    7 +-
 sys/netinet/in_selsrc.c |   15 +-
 sys/netinet/in_var.h    |   15 +-
 sys/netinet/ip_icmp.c   |   10 +-
 sys/netinet/ip_input.c  |   18 +-
 sys/netinet/raw_ip.c    |   17 +-
 sys/sys/sockio.h        |    3 +-
 14 files changed, 637 insertions(+), 68 deletions(-)

diffs (truncated from 1292 to 300 lines):

diff -r 651070b5cda0 -r f40cac8e8ae3 sys/net/if.h
--- a/sys/net/if.h      Sat May 02 14:30:27 2015 +0000
+++ b/sys/net/if.h      Sat May 02 14:41:32 2015 +0000
@@ -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  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_*) */
diff -r 651070b5cda0 -r f40cac8e8ae3 sys/net/if_spppsubr.c
--- a/sys/net/if_spppsubr.c     Sat May 02 14:30:27 2015 +0000
+++ b/sys/net/if_spppsubr.c     Sat May 02 14:41:32 2015 +0000
@@ -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 @@
 
 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);
        }
diff -r 651070b5cda0 -r f40cac8e8ae3 sys/netinet/if_arp.c
--- a/sys/netinet/if_arp.c      Sat May 02 14:30:27 2015 +0000
+++ b/sys/netinet/if_arp.c      Sat May 02 14:41:32 2015 +0000
@@ -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 @@
 #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;
+}
+



Home | Main Index | Thread Index | Old Index