]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
It seems that FreeBSD will send RTM_DELADDR + RTM_NEWADDR when
authorRoy Marples <roy@marples.name>
Fri, 6 Sep 2013 09:38:24 +0000 (09:38 +0000)
committerRoy Marples <roy@marples.name>
Fri, 6 Sep 2013 09:38:24 +0000 (09:38 +0000)
replacing an existing IPv4 address with the same values.
As such, we need to maintain a list of configured IPv4 addresses
for each interface so we know when to add it and when to skip it
to avoid receiving bogus RTM_DELADDR messages from ourself.

dhcp.c
dhcp.h
dhcpcd.h
if-bsd.c
if-options.h
ipv4.c
ipv4.h
net.c

diff --git a/dhcp.c b/dhcp.c
index 30c1ecd638bb72379c3776a3f41c36b03b57d31b..b13778c218cee59a38a8b2908789f03f85cc7b10 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -1699,7 +1699,6 @@ dhcp_rebind(void *arg)
        send_rebind(ifp);
 }
 
-
 void
 dhcp_bind(void *arg)
 {
@@ -1721,10 +1720,10 @@ dhcp_bind(void *arg)
        state->offer = NULL;
        get_lease(lease, state->new);
        if (ifo->options & DHCPCD_STATIC) {
-               syslog(LOG_INFO, "%s: using static address %s",
-                   iface->name, inet_ntoa(lease->addr));
+               syslog(LOG_INFO, "%s: using static address %s/%d",
+                   iface->name, inet_ntoa(lease->addr),
+                   inet_ntocidr(lease->net));
                lease->leasetime = ~0U;
-               lease->net.s_addr = ifo->req_mask.s_addr;
                state->reason = "STATIC";
        } else if (state->new->cookie != htonl(MAGIC_COOKIE)) {
                syslog(LOG_INFO, "%s: using IPv4LL address %s",
@@ -1831,7 +1830,7 @@ dhcp_timeout(void *arg)
 }
 
 struct dhcp_message *
-dhcp_message_new(struct in_addr *addr, struct in_addr *mask)
+dhcp_message_new(const struct in_addr *addr, const struct in_addr *mask)
 {
        struct dhcp_message *dhcp;
        uint8_t *p;
@@ -1851,60 +1850,65 @@ dhcp_message_new(struct in_addr *addr, struct in_addr *mask)
        return dhcp;
 }
 
-static int
-handle_3rdparty(struct interface *ifp)
+static void
+dhcp_static(struct interface *ifp)
 {
        struct if_options *ifo;
        struct dhcp_state *state;
-       struct in_addr addr, net, dst;
 
+       state = D_STATE(ifp);
        ifo = ifp->options;
-       if (ifo->req_addr.s_addr != INADDR_ANY)
-               return 0;
-
-       if (ipv4_getaddress(ifp->name, &addr, &net, &dst) == 1)
-               ipv4_handleifa(RTM_NEWADDR, ifp->name, &addr, &net, &dst);
-       else {
+       if (ifo->req_addr.s_addr == INADDR_ANY) {
                syslog(LOG_INFO,
-                   "%s: waiting for 3rd party to configure IP address",
+                   "%s: waiting for 3rd party to "
+                   "configure IP address",
                    ifp->name);
-               state = D_STATE(ifp);
                state->reason = "3RDPARTY";
                script_runreason(ifp, state->reason);
-       }
-       return 1;
-}
-
-static void
-dhcp_static(struct interface *ifp)
-{
-       struct if_options *ifo;
-       struct dhcp_state *state;
-
-       if (handle_3rdparty(ifp))
                return;
-       ifo = ifp->options;
-       state = D_STATE(ifp);
+       }
        state->offer = dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
-       eloop_timeout_delete(NULL, ifp);
-       dhcp_bind(ifp);
+       if (state->offer) {
+               eloop_timeout_delete(NULL, ifp);
+               dhcp_bind(ifp);
+       }
 }
 
 void
 dhcp_inform(struct interface *ifp)
 {
        struct dhcp_state *state;
-
-       if (handle_3rdparty(ifp))
-               return;
+       struct if_options *ifo;
+       struct ipv4_addr *ap;
 
        state = D_STATE(ifp);
+       ifo = ifp->options;
        if (options & DHCPCD_TEST) {
-               state->addr.s_addr = ifp->options->req_addr.s_addr;
-               state->net.s_addr = ifp->options->req_mask.s_addr;
+               state->addr.s_addr = ifo->req_addr.s_addr;
+               state->net.s_addr = ifo->req_mask.s_addr;
        } else {
-               ifp->options->options |= DHCPCD_STATIC;
-               dhcp_static(ifp);
+               if (ifo->req_addr.s_addr == INADDR_ANY) {
+                       state = D_STATE(ifp);
+                       ap = ipv4_findaddr(ifp, NULL, NULL);
+                       if (ap == NULL) {
+                               syslog(LOG_INFO,
+                                       "%s: waiting for 3rd party to "
+                                       "configure IP address",
+                                       ifp->name);
+                               state->reason = "3RDPARTY";
+                               script_runreason(ifp, state->reason);
+                               return;
+                       }
+                       state->offer =
+                           dhcp_message_new(&ap->addr, &ap->net);
+               } else 
+                       state->offer =
+                           dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
+               if (state->offer) {
+                       ifo->options |= DHCPCD_STATIC;
+                       dhcp_bind(ifp);
+                       ifo->options &= ~DHCPCD_STATIC;
+               }
        }
 
        state->state = DHS_INFORM;
@@ -2217,6 +2221,8 @@ dhcp_handle(struct interface *iface, struct dhcp_message **dhcpp,
 
                if (!(ifo->options & DHCPCD_INFORM))
                        log_dhcp(LOG_DEBUG, "acknowledged", iface, dhcp, from);
+               else
+                   ifo->options &= ~DHCPCD_STATIC;
        }
 
        /* BOOTP could have already assigned this above, so check we still
@@ -2241,7 +2247,7 @@ dhcp_handle(struct interface *iface, struct dhcp_message **dhcpp,
                /* If the interface already has the address configured
                 * then we can't ARP for duplicate detection. */
                addr.s_addr = state->offer->yiaddr;
-               if (ipv4_hasaddress(iface->name, &addr, NULL) != 1) {
+               if (!ipv4_findaddr(iface, &addr, NULL)) {
                        state->claims = 0;
                        state->probes = 0;
                        state->conflicts = 0;
@@ -2684,3 +2690,65 @@ dhcp_start(struct interface *ifp)
        else
                dhcp_reboot(ifp);
 }
+
+void
+dhcp_handleifa(int type, struct interface *ifp,
+       const struct in_addr *addr,
+       const struct in_addr *net,
+       const struct in_addr *dst)
+{
+       struct dhcp_state *state;
+       struct if_options *ifo;
+       int i;
+
+       state = D_STATE(ifp);
+       if (state == NULL)
+               return;
+
+       if (type == RTM_DELADDR) {
+               if (state->new &&
+                   state->new->yiaddr == addr->s_addr)
+                       syslog(LOG_INFO, "%s: removing IP address %s/%d",
+                           ifp->name, inet_ntoa(state->lease.addr),
+                           inet_ntocidr(state->lease.net));
+               return;
+       }
+
+       if (type != RTM_NEWADDR)
+               return;
+
+       ifo = ifp->options;
+       if (ifo->options & DHCPCD_INFORM) {
+               if (state->state != DHS_INFORM)
+                       dhcp_inform(ifp);
+               return;
+       }
+
+       if (!(ifo->options & DHCPCD_STATIC))
+               return;
+       if (ifo->req_addr.s_addr != INADDR_ANY)
+               return;
+
+       free(state->old);
+       state->old = state->new;
+       state->new = dhcp_message_new(addr, net);
+       if (state->new == NULL)
+               return;
+       state->dst.s_addr = dst ? dst->s_addr : INADDR_ANY;
+       if (dst) {
+               for (i = 1; i < 255; i++)
+                       if (i != DHO_ROUTER && has_option_mask(ifo->dstmask,i))
+                               dhcp_message_add_addr(state->new, i, *dst);
+       }
+       state->reason = "STATIC";
+       ipv4_buildroutes();
+       script_runreason(ifp, state->reason);
+       if (ifo->options & DHCPCD_INFORM) {
+               state->state = DHS_INFORM;
+               state->xid = dhcp_xid(ifp);
+               state->lease.server.s_addr = dst ? dst->s_addr : INADDR_ANY;
+               state->addr = *addr;
+               state->net = *net;
+               dhcp_inform(ifp);
+       }
+}
diff --git a/dhcp.h b/dhcp.h
index 60586988a735a9dea84369e80caf4ed5d3b259fe..986fd98a027db8cfeaec9585c70844431ffcfa6b 100644 (file)
--- a/dhcp.h
+++ b/dhcp.h
@@ -259,8 +259,8 @@ ssize_t dhcp_env(char **, const char *, const struct dhcp_message *,
     const struct interface *);
 
 uint32_t dhcp_xid(const struct interface *);
-struct dhcp_message *dhcp_message_new(struct in_addr *addr,
-    struct in_addr *mask);
+struct dhcp_message *dhcp_message_new(const struct in_addr *addr,
+    const struct in_addr *mask);
 int dhcp_message_add_addr(struct dhcp_message *, uint8_t, struct in_addr);
 ssize_t make_message(struct dhcp_message **, const struct interface *,
     uint8_t);
@@ -270,6 +270,9 @@ ssize_t write_lease(const struct interface *, const struct dhcp_message *);
 struct dhcp_message *read_lease(const struct interface *);
 void get_lease(struct dhcp_lease *, const struct dhcp_message *);
 
+void dhcp_handleifa(int, struct interface *,
+    const struct in_addr *, const struct in_addr *, const struct in_addr *);
+
 void dhcp_drop(struct interface *, const char *);
 void dhcp_start(struct interface *);
 void dhcp_stop(struct interface *);
index a55cef7ce8172fc22003e695073410cdb9b35551..4f0f56f5e802a66f0bd20c7aeffa4087abeeb235 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
 #define LINK_UNKNOWN   0
 #define LINK_DOWN      -1
 
-#define IF_DATA_DHCP   0
-#define IF_DATA_IPV6   1
-#define IF_DATA_IPV6ND 2
-#define IF_DATA_DHCP6  3
-#define IF_DATA_MAX    4
+#define IF_DATA_IPV4   0
+#define IF_DATA_DHCP   1       
+#define IF_DATA_IPV6   2
+#define IF_DATA_IPV6ND 3
+#define IF_DATA_DHCP6  4
+#define IF_DATA_MAX    5
 
 struct interface {
        TAILQ_ENTRY(interface) next;
index ba607e3b52546d6ee007322e6513a03f6f8ee0a2..d7e466f8b21784fba3db42817566141543d8c0bc 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -659,7 +659,8 @@ manage_link(int fd)
                                        COPYOUT(rt.dest, rti_info[RTAX_IFA]);
                                        COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
                                        COPYOUT(rt.gate, rti_info[RTAX_BRD]);
-                                       ipv4_handleifa(rtm->rtm_type, ifname,
+                                       ipv4_handleifa(rtm->rtm_type,
+                                           NULL, ifname,
                                            &rt.dest, &rt.net, &rt.gate);
                                        break;
 #endif
index a3ef051423624537c154f5504e923492598bd78b..69c7200a35df62dd977a30a768ba590c13e31bb5 100644 (file)
@@ -36,8 +36,6 @@
 #include <limits.h>
 #include <stdint.h>
 
-#include "ipv4.h"
-
 /* Don't set any optional arguments here so we retain POSIX
  * compatibility with getopt */
 #define IF_OPTS "46bc:de:f:gh:i:kl:m:no:pqr:s:t:u:v:wxy:z:ABC:DEF:GHI:JKLO:Q:S:TUVW:X:Z:"
diff --git a/ipv4.c b/ipv4.c
index bd33ad6b82cb10507ab2607834e376892fdc576f..06dc761af4be7efbe64c453d0bc8131a29f2e233 100644 (file)
--- a/ipv4.c
+++ b/ipv4.c
@@ -25,6 +25,7 @@
  * SUCH DAMAGE.
  */
 
+#include <sys/queue.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 
@@ -47,6 +48,7 @@
 
 #include "config.h"
 #include "common.h"
+#include "dhcpcd.h"
 #include "dhcp.h"
 #include "if-options.h"
 #include "if-pref.h"
@@ -109,74 +111,45 @@ ipv4_getnetmask(uint32_t addr)
        return 0;
 }
 
+struct ipv4_addr *
+ipv4_findaddr(struct interface *ifp,
+    const struct in_addr *addr, const struct in_addr *net)
+{
+       struct ipv4_state *state;
+       struct ipv4_addr *ap;
+
+       state = IPV4_STATE(ifp);
+       if (state) {
+               TAILQ_FOREACH(ap, &state->addrs, next) {
+                       if ((addr == NULL || ap->addr.s_addr == addr->s_addr) &&
+                           (net == NULL || ap->net.s_addr == net->s_addr))
+                               return ap;
+               }
+       }
+       return NULL;
+}
+
 int
 ipv4_addrexists(const struct in_addr *addr)
 {
-       const struct interface *ifp;
-       const struct dhcp_state *state;
+       struct interface *ifp;
+       struct dhcp_state *state;
 
        TAILQ_FOREACH(ifp, ifaces, next) {
-               state = D_CSTATE(ifp);
+               state = D_STATE(ifp);
                if (state) {
                        if (addr == NULL) {
-                               if (state->addr.s_addr)
+                               if (state->addr.s_addr != INADDR_ANY)
                                        return 1;
-                       } else if (memcmp(&addr->s_addr,
-                           &state->addr.s_addr,
-                           sizeof(state->addr.s_addr)) == 0)
+                       } else if (addr->s_addr == state->addr.s_addr)
                                return 1;
                }
+               if (addr != NULL && ipv4_findaddr(ifp, addr, NULL))
+                       return 1;
        }
        return 0;
 }
 
-int
-ipv4_doaddress(const char *ifname,
-    struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
-{
-       struct ifaddrs *ifaddrs, *ifa;
-       const struct sockaddr_in *a, *n, *d;
-       int retval;
-
-       if (getifaddrs(&ifaddrs) == -1)
-               return -1;
-
-       retval = 0;
-       for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
-               if (ifa->ifa_addr == NULL ||
-                   ifa->ifa_addr->sa_family != AF_INET ||
-                   strcmp(ifa->ifa_name, ifname) != 0)
-                       continue;
-               a = (const struct sockaddr_in *)(void *)ifa->ifa_addr;
-               n = (const struct sockaddr_in *)(void *)ifa->ifa_netmask;
-               if (ifa->ifa_flags & IFF_POINTOPOINT)
-                       d = (const struct sockaddr_in *)(void *)
-                           ifa->ifa_dstaddr;
-               else
-                       d = NULL;
-               if (act == 1) {
-                       addr->s_addr = a->sin_addr.s_addr;
-                       net->s_addr = n->sin_addr.s_addr;
-                       if (dst) {
-                               if (ifa->ifa_flags & IFF_POINTOPOINT)
-                                       dst->s_addr = d->sin_addr.s_addr;
-                               else
-                                       dst->s_addr = INADDR_ANY;
-                       }
-                       retval = 1;
-                       break;
-               }
-               if (addr->s_addr == a->sin_addr.s_addr &&
-                   (net == NULL || net->s_addr == n->sin_addr.s_addr))
-               {
-                       retval = 1;
-                       break;
-               }
-       }
-       freeifaddrs(ifaddrs);
-       return retval;
-}
-
 void
 ipv4_freeroutes(struct rt_head *rts)
 {
@@ -586,26 +559,49 @@ ipv4_buildroutes(void)
 }
 
 static int
-delete_address(struct interface *iface)
+delete_address1(struct interface *ifp,
+    const struct in_addr *addr, const struct in_addr *net)
 {
-       int retval;
+       int r;
+       struct ipv4_state *state;
+       struct ipv4_addr *ap;
+
+       syslog(LOG_DEBUG, "%s: deleting IP address %s/%d",
+           ifp->name, inet_ntoa(*addr), inet_ntocidr(*net));
+       r = ipv4_deleteaddress(ifp, addr, net);
+       if (r == -1 && errno != EADDRNOTAVAIL && errno != ENXIO &&
+           errno != ENODEV)
+               syslog(LOG_ERR, "%s: %s: %m", ifp->name, __func__);
+
+       state = IPV4_STATE(ifp);
+       TAILQ_FOREACH(ap, &state->addrs, next) {
+               if (ap->addr.s_addr == addr->s_addr &&
+                   ap->net.s_addr == net->s_addr)
+               {
+                       TAILQ_REMOVE(&state->addrs, ap, next);
+                       free(ap);
+                       break;
+               }
+       }
+       return r;
+}
+    
+static int
+delete_address(struct interface *ifp)
+{
+       int r;
        struct if_options *ifo;
        struct dhcp_state *state;
 
-       state = D_STATE(iface);
-       ifo = iface->options;
+       state = D_STATE(ifp);
+       ifo = ifp->options;
        if (ifo->options & DHCPCD_INFORM ||
            (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
                return 0;
-       syslog(LOG_DEBUG, "%s: deleting IP address %s/%d",
-           iface->name, inet_ntoa(state->addr), inet_ntocidr(state->net));
-       retval = ipv4_deleteaddress(iface, &state->addr, &state->net);
-       if (retval == -1 && errno != EADDRNOTAVAIL && errno != ENXIO &&
-           errno != ENODEV)
-               syslog(LOG_ERR, "del_address: %m");
+       r = delete_address1(ifp, &state->addr, &state->net);
        state->addr.s_addr = 0;
        state->net.s_addr = 0;
-       return retval;
+       return r;
 }
 
 void
@@ -616,6 +612,7 @@ ipv4_applyaddr(void *arg)
        struct dhcp_message *dhcp;
        struct dhcp_lease *lease;
        struct if_options *ifo = ifp->options;
+       struct ipv4_addr *ap;
        struct rt *rt;
        int r;
 
@@ -640,10 +637,16 @@ ipv4_applyaddr(void *arg)
                return;
        }
 
-       /* This also changes netmask */
-       if (!(ifo->options & DHCPCD_INFORM) ||
-           !ipv4_hasaddress(ifp->name, &lease->addr, &lease->net))
-       {
+       /* If the netmask is different, delete the addresss */
+       ap = ipv4_findaddr(ifp, &lease->addr, NULL);
+       if (ap && ap->net.s_addr != lease->net.s_addr)
+               delete_address1(ifp, &ap->addr, &ap->net);
+
+       if (ipv4_findaddr(ifp, &lease->addr, &lease->net))
+               syslog(LOG_DEBUG, "%s: IP address %s/%d already exists",
+                   ifp->name, inet_ntoa(lease->addr),
+                   inet_ntocidr(lease->net));
+       else {
                syslog(LOG_DEBUG, "%s: adding IP address %s/%d",
                    ifp->name, inet_ntoa(lease->addr),
                    inet_ntocidr(lease->net));
@@ -687,62 +690,74 @@ ipv4_applyaddr(void *arg)
 }
 
 void
-ipv4_handleifa(int type, const char *ifname,
-    struct in_addr *addr, struct in_addr *net, struct in_addr *dst)
+ipv4_handleifa(int type, struct if_head *ifs, const char *ifname,
+    const struct in_addr *addr, const struct in_addr *net,
+    const struct in_addr *dst)
 {
        struct interface *ifp;
-       struct if_options *ifo;
-       struct dhcp_state *state;
-       int i;
+       struct ipv4_state *state;
+       struct ipv4_addr *ap;
 
+       if (ifs == NULL)
+               ifs = ifaces;
+       if (ifs == NULL)
+               return;
        if (addr->s_addr == INADDR_ANY)
                return;
-       TAILQ_FOREACH(ifp, ifaces, next) {
+
+       TAILQ_FOREACH(ifp, ifs, next) {
                if (strcmp(ifp->name, ifname) == 0)
                        break;
        }
        if (ifp == NULL)
                return;
 
-       state = D_STATE(ifp);
-       if (state == NULL)
-               return;
-
-       if (type == RTM_DELADDR) {
-               if (state->new &&
-                   state->new->yiaddr == addr->s_addr)
-                       syslog(LOG_INFO, "%s: removing IP address %s/%d",
-                           ifp->name, inet_ntoa(state->lease.addr),
-                           inet_ntocidr(state->lease.net));
-               return;
+       state = IPV4_STATE(ifp);
+       if (state == NULL) {
+               ifp->if_data[IF_DATA_IPV4] = malloc(sizeof(*state));
+               state = IPV4_STATE(ifp);
+               if (state == NULL) {
+                       syslog(LOG_ERR, "%s: %m", __func__);
+                       return;
+               }
+               TAILQ_INIT(&state->addrs);
+               ap = NULL;
+       } else
+               ap = ipv4_findaddr(ifp, addr, net);
+       if (type == RTM_NEWADDR && ap == NULL) {
+               ap = malloc(sizeof(*ap));
+               if (ap == NULL) {
+                       syslog(LOG_ERR, "%s: %m", __func__);
+                       return;
+               }
+               ap->addr.s_addr = addr->s_addr;
+               ap->net.s_addr = net->s_addr;
+               if (dst)
+                       ap->dst.s_addr = dst->s_addr;
+               else
+                       ap->dst.s_addr = INADDR_ANY;
+               TAILQ_INSERT_TAIL(&state->addrs, ap, next);
+       } else if (type == RTM_DELADDR) {
+               if (ap == NULL)
+                       return;
+               TAILQ_REMOVE(&state->addrs, ap, next);
+               free(ap);
        }
 
-       if (type != RTM_NEWADDR)
-               return;
-
-       ifo = ifp->options;
-       if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)) == 0 ||
-           ifo->req_addr.s_addr != INADDR_ANY)
-               return;
+       dhcp_handleifa(type, ifp, addr, net, dst);
+}
 
-       free(state->old);
-       state->old = state->new;
-       state->new = dhcp_message_new(addr, net);
-       state->dst.s_addr = dst ? dst->s_addr : INADDR_ANY;
-       if (dst) {
-               for (i = 1; i < 255; i++)
-                       if (i != DHO_ROUTER && has_option_mask(ifo->dstmask,i))
-                               dhcp_message_add_addr(state->new, i, *dst);
-       }
-       state->reason = "STATIC";
-       ipv4_buildroutes();
-       script_runreason(ifp, state->reason);
-       if (ifo->options & DHCPCD_INFORM) {
-               state->state = DHS_INFORM;
-               state->xid = dhcp_xid(ifp);
-               state->lease.server.s_addr = dst ? dst->s_addr : INADDR_ANY;
-               state->addr = *addr;
-               state->net = *net;
-               dhcp_inform(ifp);
+void
+ipv4_free(struct interface *ifp)
+{
+       struct ipv4_state *state;
+       struct ipv4_addr *addr;
+
+       state = IPV4_STATE(ifp);
+       if (state) {
+               while ((addr = TAILQ_FIRST(&state->addrs))) {
+                       TAILQ_REMOVE(&state->addrs, addr, next);
+                       free(addr);
+               }
        }
 }
diff --git a/ipv4.h b/ipv4.h
index eec0000ac21b434671609d1fc315eebbbfd3cb0a..ebab2cd35b8f7228887b3b2c772645a10194ff1e 100644 (file)
--- a/ipv4.h
+++ b/ipv4.h
@@ -41,6 +41,23 @@ struct rt {
 };
 TAILQ_HEAD(rt_head, rt);
 
+struct ipv4_addr {
+       TAILQ_ENTRY(ipv4_addr) next;
+       struct in_addr addr;
+       struct in_addr net;
+       struct in_addr dst;
+};
+TAILQ_HEAD(ipv4_addrhead, ipv4_addr);
+
+struct ipv4_state {
+       struct ipv4_addrhead addrs;
+};
+
+#define IPV4_STATE(ifp)                                                               \
+       ((struct ipv4_state *)(ifp)->if_data[IF_DATA_IPV4])
+#define IPV4_CSTATE(ifp)                                                      \
+       ((const struct ipv4_state *)(ifp)->if_data[IF_DATA_IPV4])
+
 #ifdef INET
 int ipv4_init(void);
 int inet_ntocidr(struct in_addr);
@@ -52,11 +69,11 @@ void ipv4_buildroutes(void);
 void ipv4_applyaddr(void *);
 int ipv4_routedeleted(const struct rt *);
 
-void ipv4_handleifa(int, const char *,
-    struct in_addr *, struct in_addr *, struct in_addr *);
+struct ipv4_addr *ipv4_findaddr(struct interface *,
+    const struct in_addr *, const struct in_addr *);
+void ipv4_handleifa(int, struct if_head *, const char *,
+    const struct in_addr *, const struct in_addr *, const struct in_addr *);
 
-int ipv4_doaddress(const char *,
-    struct in_addr *, struct in_addr *, struct in_addr *, int);
 int if_address(const struct interface *,
     const struct in_addr *, const struct in_addr *,
     const struct in_addr *, int);
@@ -66,10 +83,6 @@ int if_address(const struct interface *,
        if_address(iface, addr, net, brd, 2)
 #define ipv4_deleteaddress(iface, addr, net)                                 \
        if_address(iface, addr, net, NULL, -1)
-#define ipv4_hasaddress(iface, addr, net)                                    \
-       ipv4_doaddress(iface, addr, net, NULL, 0)
-#define ipv4_getaddress(iface, addr, net, dst)                               \
-       ipv4_doaddress(iface, addr, net, dst, 1)
 
 int if_route(const struct rt *rt, int);
 #define ipv4_addroute(rt) if_route(rt, 1)
@@ -82,6 +95,7 @@ int ipv4_opensocket(struct interface *, int);
 ssize_t ipv4_sendrawpacket(const struct interface *,
     int, const void *, ssize_t);
 ssize_t ipv4_getrawpacket(struct interface *, int, void *, ssize_t, int *);
+void ipv4_free(struct interface *);
 #else
 #define ipv4_init() -1
 #define ipv4_applyaddr(a) {}
diff --git a/net.c b/net.c
index 898b222157ea68602b21116f29b39b9fa8301c07..0720a0f46b01d3e70e7843292d6e531945007165 100644 (file)
--- a/net.c
+++ b/net.c
@@ -70,6 +70,7 @@
 #include "dhcp.h"
 #include "dhcp6.h"
 #include "if-options.h"
+#include "ipv4.h"
 #include "ipv6nd.h"
 #include "net.h"
 
@@ -138,6 +139,7 @@ free_interface(struct interface *ifp)
 
        if (ifp == NULL)
                return;
+       ipv4_free(ifp);
        dhcp_free(ifp);
        ipv6_free(ifp);
        dhcp6_free(ifp);
@@ -223,6 +225,10 @@ discover_interfaces(int argc, char * const *argv)
 #ifdef __linux__
        char ifn[IF_NAMESIZE];
 #endif
+#ifdef INET
+       const struct sockaddr_in *addr;
+       const struct sockaddr_in *net;
+       const struct sockaddr_in *dst;
 #ifdef INET6
        const struct sockaddr_in6 *sin6;
        int ifa_flags;
@@ -441,11 +447,29 @@ discover_interfaces(int argc, char * const *argv)
                TAILQ_INSERT_TAIL(ifs, ifp, next);
        }
 
-#ifdef INET6
        for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
-               if (ifa->ifa_addr != NULL &&
-                   ifa->ifa_addr->sa_family == AF_INET6)
-               {
+               if (ifa->ifa_addr == NULL)
+                       continue;
+               switch(ifa->ifa_addr->sa_family) {
+#ifdef INET
+               case AF_INET:
+                       addr = (const struct sockaddr_in *)
+                           (void *)ifa->ifa_addr;
+                       net = (const struct sockaddr_in *)
+                           (void *)ifa->ifa_netmask;
+                       if (ifa->ifa_flags & IFF_POINTOPOINT)
+                               dst = (const struct sockaddr_in *)
+                                   (void *)ifa->ifa_dstaddr;
+                       else
+                               dst = NULL;
+                       ipv4_handleifa(RTM_NEWADDR, ifs, ifa->ifa_name,
+                               &addr->sin_addr,
+                               &net->sin_addr,
+                               dst ? &dst->sin_addr : NULL);
+                       break;
+#endif
+#ifdef INET6
+               case AF_INET6:
                        sin6 = (const struct sockaddr_in6 *)
                            (void *)ifa->ifa_addr;
                        ifa_flags = in6_addr_flags(ifa->ifa_name,
@@ -454,6 +478,8 @@ discover_interfaces(int argc, char * const *argv)
                                ipv6_handleifa(RTM_NEWADDR, ifs,
                                    ifa->ifa_name,
                                    &sin6->sin6_addr, ifa_flags);
+                       break;
+#endif
                }
        }
 #endif