From: Roy Marples Date: Fri, 1 May 2015 09:41:54 +0000 (+0000) Subject: Support IN_IFF_TENTATIVE and IN_IFF_DUPLICATED on NetBSD. X-Git-Tag: v6.8.2~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d686aa4f7d4a3cbdc58a27633a65e66abbbde9c0;p=thirdparty%2Fdhcpcd.git Support IN_IFF_TENTATIVE and IN_IFF_DUPLICATED on NetBSD. --- diff --git a/arp.c b/arp.c index 122752b6..4877a65f 100644 --- a/arp.c +++ b/arp.c @@ -96,12 +96,20 @@ eexit: void arp_report_conflicted(const struct arp_state *astate, const struct arp_msg *amsg) { - char buf[HWADDR_LEN * 3]; - logger(astate->iface->ctx, LOG_ERR, "%s: hardware address %s claims %s", - astate->iface->name, - hwaddr_ntoa(amsg->sha, astate->iface->hwlen, buf, sizeof(buf)), - inet_ntoa(astate->failed)); + if (amsg) { + char buf[HWADDR_LEN * 3]; + + logger(astate->iface->ctx, LOG_ERR, + "%s: hardware address %s claims %s", + astate->iface->name, + hwaddr_ntoa(amsg->sha, astate->iface->hwlen, + buf, sizeof(buf)), + inet_ntoa(astate->failed)); + } else + logger(astate->iface->ctx, LOG_ERR, + "%s: DAD detected %s", + astate->iface->name, inet_ntoa(astate->failed)); } static void @@ -315,7 +323,8 @@ arp_new(struct interface *ifp, const struct in_addr *addr) } state = D_STATE(ifp); astate->iface = ifp; - astate->addr = *addr; + if (addr) + astate->addr = *addr; TAILQ_INSERT_TAIL(&state->arp_states, astate, next); return astate; } @@ -380,3 +389,28 @@ arp_close(struct interface *ifp) #endif } } + +void +arp_handleifa(int cmd, struct interface *ifp, const struct in_addr *addr, + int flags) +{ +#ifdef IN_IFF_DUPLICATED + struct dhcp_state *state = D_STATE(ifp); + struct arp_state *astate, *asn; + + if (cmd != RTM_NEWADDR || (state = D_STATE(ifp)) == NULL) + return; + + TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, asn) { + if (astate->addr.s_addr == addr->s_addr) { + if (flags & IN_IFF_DUPLICATED) { + if (astate->conflicted_cb) + astate->conflicted_cb(astate, NULL); + } else if (!(flags & IN_IFF_TENTATIVE)) { + if (astate->probed_cb) + astate->probed_cb(astate); + } + } + } +#endif +} diff --git a/arp.h b/arp.h index d0d4ed7d..83422fe1 100644 --- a/arp.h +++ b/arp.h @@ -74,6 +74,8 @@ void arp_cancel(struct arp_state *); void arp_free(struct arp_state *); void arp_free_but(struct arp_state *); void arp_close(struct interface *); + +void arp_handleifa(int, struct interface *, const struct in_addr *, int); #else #define arp_close(a) {} #endif diff --git a/dhcp.c b/dhcp.c index 88824f3f..2c962a2d 100644 --- a/dhcp.c +++ b/dhcp.c @@ -1799,7 +1799,7 @@ dhcp_expire(void *arg) dhcp_discover(ifp); } -void +static void dhcp_decline(struct interface *ifp) { @@ -1824,12 +1824,14 @@ dhcp_renew(void *arg) send_renew(ifp); } +#ifndef IN_IFF_TENTATIVE static void dhcp_arp_announced(struct arp_state *astate) { arp_close(astate->iface); } +#endif static void dhcp_rebind(void *arg) @@ -1978,9 +1980,13 @@ dhcp_bind(struct interface *ifp, struct arp_state *astate) applyaddr: ipv4_applyaddr(ifp); - if (dhcpcd_daemonise(ifp->ctx)) - return; - if (ifo->options & DHCPCD_ARP) { + if (ifo->options & DHCPCD_ARP && + !(ifp->ctx->options & DHCPCD_FORKED)) + { +#ifdef IN_IFF_TENTATIVE + if (astate) + arp_free_but(astate); +#else if (state->added) { if (astate == NULL) { astate = arp_new(ifp, &state->addr); @@ -1994,6 +2000,7 @@ applyaddr: } } else if (!ipv4ll) arp_close(ifp); +#endif } } @@ -2347,7 +2354,12 @@ dhcp_arp_probed(struct arp_state *astate) } dhcp_close(astate->iface); eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate->iface); +#ifdef IN_IFF_TENTATIVE + ipv4_finaliseaddr(astate->iface); + arp_close(astate->iface); +#else dhcp_bind(astate->iface, astate); +#endif } static void @@ -2360,6 +2372,7 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg) ifo = astate->iface->options; if (state->arping_index && state->arping_index <= ifo->arping_len && + amsg && (amsg->sip.s_addr == ifo->arping[state->arping_index - 1] || (amsg->sip.s_addr == 0 && amsg->tip.s_addr == ifo->arping[state->arping_index - 1]))) @@ -2386,14 +2399,17 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg) dhcpcd_startinterface(astate->iface); } - if (state->offer == NULL) - return; - - /* RFC 2131 3.1.5, Client-server interaction */ - if (amsg->sip.s_addr == state->offer->yiaddr || - (amsg->sip.s_addr == 0 && amsg->tip.s_addr == state->offer->yiaddr)) + /* RFC 2131 3.1.5, Client-server interaction + * NULL amsg means IN_IFF_DUPLICATED */ + if (amsg == NULL || (state->offer && + (amsg->sip.s_addr == state->offer->yiaddr || + (amsg->sip.s_addr == 0 && + amsg->tip.s_addr == state->offer->yiaddr)))) { - astate->failed.s_addr = state->offer->yiaddr; + if (amsg) + astate->failed.s_addr = state->offer->yiaddr; + else + astate->failed = astate->addr; arp_report_conflicted(astate, amsg); unlink(state->leasefile); if (!state->lease.frominfo) @@ -2419,6 +2435,7 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp, unsigned int i; size_t auth_len; char *msg; + struct arp_state *astate; /* We may have found a BOOTP server */ if (get_option_uint8(ifp->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1) @@ -2632,6 +2649,10 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp, if ((type == 0 || type == DHCP_OFFER) && (state->state == DHS_DISCOVER || state->state == DHS_IPV4LL_BOUND)) { +#ifdef IN_IFF_DUPLICATED + struct ipv4_addr *ia; +#endif + lease->frominfo = 0; lease->addr.s_addr = dhcp->yiaddr; lease->cookie = dhcp->cookie; @@ -2640,6 +2661,18 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp, &lease->server, dhcp, DHO_SERVERID) != 0) lease->server.s_addr = INADDR_ANY; log_dhcp(LOG_INFO, "offered", ifp, dhcp, from); +#ifdef IN_IFF_DUPLICATED + ia = ipv4_iffindaddr(ifp, &lease->addr, NULL); + if (ia && ia->addr_flags & IN_IFF_DUPLICATED) { + log_dhcp(LOG_WARNING, "declined duplicate address", + ifp, dhcp, from); + dhcp_decline(ifp); + eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); + eloop_timeout_add_sec(ifp->ctx->eloop, + DHCP_RAND_MAX, dhcp_discover, ifp); + return; + } +#endif free(state->offer); state->offer = dhcp; *dhcpp = NULL; @@ -2703,7 +2736,7 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp, lease->frominfo = 0; eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); - + astate = NULL; if (ifo->options & DHCPCD_ARP && state->addr.s_addr != state->offer->yiaddr) { @@ -2711,19 +2744,21 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp, * then we can't ARP for duplicate detection. */ addr.s_addr = state->offer->yiaddr; if (!ipv4_iffindaddr(ifp, &addr, NULL)) { - struct arp_state *astate; - astate = arp_new(ifp, &addr); if (astate) { astate->probed_cb = dhcp_arp_probed; astate->conflicted_cb = dhcp_arp_conflicted; +#ifndef IN_IFF_TENTATIVE arp_probe(astate); +#endif } +#ifndef IN_IFF_TENTATIVE return; +#endif } } - dhcp_bind(ifp, NULL); + dhcp_bind(ifp, astate); } static size_t @@ -3158,8 +3193,16 @@ dhcp_start1(void *arg) state->offer = read_lease(ifp); /* Check the saved lease matches the type we want */ if (state->offer) { + struct ipv4_addr *ia; + struct in_addr addr; + + addr.s_addr = state->offer->yiaddr; + ia = ipv4_iffindaddr(ifp, &addr, NULL); if ((IS_BOOTP(ifp, state->offer) && !(ifo->options & DHCPCD_BOOTP)) || +#ifdef IN_IFF_DUPLICATED + (ia && ia->addr_flags & IN_IFF_DUPLICATED) || +#endif (!IS_BOOTP(ifp, state->offer) && ifo->options & DHCPCD_BOOTP)) { @@ -3271,10 +3314,11 @@ dhcp_start(struct interface *ifp) } void -dhcp_handleifa(int type, struct interface *ifp, +dhcp_handleifa(int cmd, struct interface *ifp, const struct in_addr *addr, const struct in_addr *net, - const struct in_addr *dst) + const struct in_addr *dst, + __unused int flags) { struct dhcp_state *state; struct if_options *ifo; @@ -3284,7 +3328,7 @@ dhcp_handleifa(int type, struct interface *ifp, if (state == NULL) return; - if (type == RTM_DELADDR) { + if (cmd == RTM_DELADDR) { if (state->new && (state->new->yiaddr == addr->s_addr || (state->new->yiaddr == INADDR_ANY && @@ -3299,7 +3343,7 @@ dhcp_handleifa(int type, struct interface *ifp, return; } - if (type != RTM_NEWADDR) + if (cmd != RTM_NEWADDR) return; ifo = ifp->options; diff --git a/dhcp.h b/dhcp.h index 008870d9..85ce06fd 100644 --- a/dhcp.h +++ b/dhcp.h @@ -274,12 +274,12 @@ ssize_t make_message(struct dhcp_message **, const struct interface *, int valid_dhcp_packet(unsigned char *); void dhcp_handleifa(int, struct interface *, - const struct in_addr *, const struct in_addr *, const struct in_addr *); + const struct in_addr *, const struct in_addr *, const struct in_addr *, + int); void dhcp_drop(struct interface *, const char *); void dhcp_start(struct interface *); void dhcp_stop(struct interface *); -void dhcp_decline(struct interface *); void dhcp_discover(void *); void dhcp_inform(struct interface *); void dhcp_bind(struct interface *, struct arp_state *); diff --git a/if-bsd.c b/if-bsd.c index 775c857d..ac9b6ec9 100644 --- a/if-bsd.c +++ b/if-bsd.c @@ -713,6 +713,33 @@ if_initrt(struct interface *ifp) free(buf); return 0; } + +int +if_addrflags(const struct in_addr *addr, const struct interface *ifp) +{ +#ifdef SIOCGIFAFLAG_IN + int s, flags; + struct ifreq ifr; + struct sockaddr_in *sin; + + s = socket(PF_INET, SOCK_DGRAM, 0); + flags = -1; + if (s != -1) { + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); + sin = (struct sockaddr_in *)(void *)&ifr.ifr_addr; + sin->sin_family = AF_INET; + sin->sin_addr = *addr; + if (ioctl(s, SIOCGIFAFLAG_IN, &ifr) != -1) + flags = ifr.ifr_addrflags; + close(s); + } + return flags; +#else + errno = ENOTSUP; + return 0; +#endif +} #endif #ifdef INET6 @@ -1127,6 +1154,8 @@ if_managelink(struct dhcpcd_ctx *ctx) struct rt6 rt6; struct in6_addr ia6, net6; struct sockaddr_in6 *sin6; +#endif +#if (defined(INET) && defined(IN_IFF_TENTATIVE)) || defined(INET6) int ifa_flags; #endif @@ -1261,9 +1290,15 @@ if_managelink(struct dhcpcd_ctx *ctx) COPYOUT(rt.dest, rti_info[RTAX_IFA]); COPYOUT(rt.net, rti_info[RTAX_NETMASK]); COPYOUT(rt.gate, rti_info[RTAX_BRD]); + if (rtm->rtm_type == RTM_NEWADDR) { + ifa_flags = if_addrflags(&rt.dest, ifp); + if (ifa_flags == -1) + break; + } else + ifa_flags = 0; ipv4_handleifa(ctx, rtm->rtm_type, NULL, ifp->name, - &rt.dest, &rt.net, &rt.gate); + &rt.dest, &rt.net, &rt.gate, ifa_flags); break; #endif #ifdef INET6 diff --git a/if-linux.c b/if-linux.c index ca89bae1..f99de8d9 100644 --- a/if-linux.c +++ b/if-linux.c @@ -1412,6 +1412,15 @@ if_initrt(struct interface *ifp) return send_netlink(ifp->ctx, ifp, NETLINK_ROUTE, &nlm.hdr, &_if_initrt); } + +int +if_addrflags(__unused const struct in_addr *addr, + __unused const struct interface *ifp) +{ + + /* Linux has no support for IPv4 address flags */ + return 0; +} #endif #ifdef INET6 diff --git a/if.c b/if.c index e297c305..c2cc4ae2 100644 --- a/if.c +++ b/if.c @@ -490,10 +490,11 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv) (void *)ifa->ifa_dstaddr; else dst = NULL; + ifa_flags = if_addrflags(&addr->sin_addr, ifp); ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name, &addr->sin_addr, &net->sin_addr, - dst ? &dst->sin_addr : NULL); + dst ? &dst->sin_addr : NULL, ifa_flags); break; #endif #ifdef INET6 diff --git a/if.h b/if.h index 4efc6364..8330ad75 100644 --- a/if.h +++ b/if.h @@ -31,6 +31,9 @@ #include #include /* for RTM_ADD et all */ #include +#ifdef BSD +#include /* for IN_IFF_TENTATIVE et all */ +#endif /* Some systems have route metrics. * OpenBSD route priority is not this. */ @@ -125,6 +128,8 @@ int if_address(const struct interface *, #define if_deladdress(ifp, addr, net) \ if_address(ifp, addr, net, NULL, -1) +int if_addrflags(const struct in_addr *, const struct interface *); + int if_route(unsigned char, const struct rt *rt); int if_initrt(struct interface *); #endif diff --git a/ipv4.c b/ipv4.c index 9c5162c9..d49984a0 100644 --- a/ipv4.c +++ b/ipv4.c @@ -800,26 +800,82 @@ ipv4_getstate(struct interface *ifp) static int ipv4_addaddr(struct interface *ifp, const struct dhcp_lease *lease) { - int r; + struct ipv4_state *state; + struct ipv4_addr *ia; + if ((state = ipv4_getstate(ifp)) == NULL) { + logger(ifp->ctx, LOG_ERR, "%s: ipv4_getstate: %m", __func__); + return -1; + } if (ifp->options->options & DHCPCD_NOALIAS) { - struct ipv4_state *state; - struct ipv4_addr *ap, *apn; + struct ipv4_addr *ian; - state = IPV4_STATE(ifp); - TAILQ_FOREACH_SAFE(ap, &state->addrs, next, apn) { - if (ap->addr.s_addr != lease->addr.s_addr) - delete_address1(ifp, &ap->addr, &ap->net); + TAILQ_FOREACH_SAFE(ia, &state->addrs, next, ian) { + if (ia->addr.s_addr != lease->addr.s_addr) + delete_address1(ifp, &ia->addr, &ia->net); } } + if ((ia = malloc(sizeof(*ia))) == NULL) { + logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); + return -1; + } + logger(ifp->ctx, LOG_DEBUG, "%s: adding IP address %s/%d", ifp->name, inet_ntoa(lease->addr), inet_ntocidr(lease->net)); - r = if_addaddress(ifp, &lease->addr, &lease->net, &lease->brd); - if (r == -1 && errno != EEXIST) - logger(ifp->ctx, LOG_ERR, "%s: if_addaddress: %m", __func__); - return r; + if (if_addaddress(ifp, &lease->addr, &lease->net, &lease->brd) == -1) { + if (errno != EEXIST) + logger(ifp->ctx, LOG_ERR, "%s: if_addaddress: %m", + __func__); + free(ia); + return -1; + } + + ia->iface = ifp; + ia->addr = lease->addr; + ia->net = lease->net; +#ifdef IN_IFF_TENTATIVE + ia->addr_flags = IN_IFF_TENTATIVE; +#endif + TAILQ_INSERT_TAIL(&state->addrs, ia, next); + return 0; +} + +static void +ipv4_finalisert(struct interface *ifp) +{ + const struct dhcp_state *state = D_CSTATE(ifp); + + /* Find any freshly added routes, such as the subnet route. + * We do this because we cannot rely on recieving the kernel + * notification right now via our link socket. */ + if_initrt(ifp); + ipv4_buildroutes(ifp->ctx); + script_runreason(ifp, state->reason); + + dhcpcd_daemonise(ifp->ctx); +} + +void +ipv4_finaliseaddr(struct interface *ifp) +{ + struct dhcp_state *state = D_STATE(ifp); + struct dhcp_lease *lease; + + lease = &state->lease; + + /* Delete the old address if different */ + if (state->addr.s_addr != lease->addr.s_addr && + state->addr.s_addr != 0 && + ipv4_iffindaddr(ifp, &lease->addr, NULL)) + delete_address(ifp); + + state->added = STATE_ADDED; + state->defend = 0; + state->addr.s_addr = lease->addr.s_addr; + state->net.s_addr = lease->net.s_addr; + ipv4_finalisert(ifp); } void @@ -831,7 +887,6 @@ ipv4_applyaddr(void *arg) struct dhcp_lease *lease; struct if_options *ifo = ifp->options; struct ipv4_addr *ap; - struct ipv4_state *istate = NULL; int r; if (state == NULL) @@ -893,7 +948,7 @@ ipv4_applyaddr(void *arg) ifn->name); state->addr.s_addr = lease->addr.s_addr; state->net.s_addr = lease->net.s_addr; - goto routes; + ipv4_finalisert(ifp); } logger(ifp->ctx, LOG_INFO, "%s: preferring %s on %s", ifn->name, @@ -930,40 +985,26 @@ ipv4_applyaddr(void *arg) r = ipv4_addaddr(ifp, lease); if (r == -1 && errno != EEXIST) return; - istate = ipv4_getstate(ifp); - ap = malloc(sizeof(*ap)); - ap->iface = ifp; - ap->addr = lease->addr; - ap->net = lease->net; - ap->dst.s_addr = INADDR_ANY; - TAILQ_INSERT_TAIL(&istate->addrs, ap, next); } - /* Now delete the old address if different */ - if (state->addr.s_addr != lease->addr.s_addr && - state->addr.s_addr != 0 && - ipv4_iffindaddr(ifp, &lease->addr, NULL)) - delete_address(ifp); - - state->added = STATE_ADDED; - state->defend = 0; - state->addr.s_addr = lease->addr.s_addr; - state->net.s_addr = lease->net.s_addr; +#ifdef IN_IFF_TENTATIVE + ap = ipv4_iffindaddr(ifp, &lease->addr, NULL); + if (ap == NULL) { + logger(ifp->ctx, LOG_ERR, "%s: added address vanished", + ifp->name); + return; + } else if (ap->addr_flags & IN_IFF_TENTATIVE) + return; +#endif -routes: - /* Find any freshly added routes, such as the subnet route. - * We do this because we cannot rely on recieving the kernel - * notification right now via our link socket. */ - if_initrt(ifp); - ipv4_buildroutes(ifp->ctx); - script_runreason(ifp, state->reason); + ipv4_finaliseaddr(ifp); } void ipv4_handleifa(struct dhcpcd_ctx *ctx, - int type, struct if_head *ifs, const char *ifname, + int cmd, struct if_head *ifs, const char *ifname, const struct in_addr *addr, const struct in_addr *net, - const struct in_addr *dst) + const struct in_addr *dst, int flags) { struct interface *ifp; struct ipv4_state *state; @@ -979,44 +1020,39 @@ ipv4_handleifa(struct dhcpcd_ctx *ctx, errno = EINVAL; return; } - - TAILQ_FOREACH(ifp, ifs, next) { - if (strcmp(ifp->name, ifname) == 0) - break; - } - if (ifp == NULL) { - errno = ESRCH; + if ((ifp = if_find(ifs, ifname)) == NULL) return; - } - state = ipv4_getstate(ifp); - if (state == NULL) { + if ((state = ipv4_getstate(ifp)) == NULL) { errno = ENOENT; return; } ap = ipv4_iffindaddr(ifp, addr, net); - if (type == RTM_NEWADDR && ap == NULL) { - ap = malloc(sizeof(*ap)); + if (cmd == RTM_NEWADDR) { if (ap == NULL) { - logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); - return; + if ((ap = malloc(sizeof(*ap))) == NULL) { + logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); + return; + } + ap->iface = ifp; + ap->addr = *addr; + ap->net = *net; + if (dst) + ap->dst.s_addr = dst->s_addr; + else + ap->dst.s_addr = INADDR_ANY; + TAILQ_INSERT_TAIL(&state->addrs, ap, next); + } + ap->addr_flags = flags; + } else if (cmd == RTM_DELADDR) { + if (ap) { + TAILQ_REMOVE(&state->addrs, ap, next); + free(ap); } - ap->iface = ifp; - 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); } - dhcp_handleifa(type, ifp, addr, net, dst); + dhcp_handleifa(cmd, ifp, addr, net, dst, flags); + arp_handleifa(cmd, ifp, addr, flags); } void diff --git a/ipv4.h b/ipv4.h index 2b7f64da..a33e6737 100644 --- a/ipv4.h +++ b/ipv4.h @@ -50,6 +50,7 @@ struct ipv4_addr { struct in_addr net; struct in_addr dst; struct interface *iface; + int addr_flags; }; TAILQ_HEAD(ipv4_addrhead, ipv4_addr); @@ -75,6 +76,7 @@ int ipv4_addrexists(struct dhcpcd_ctx *, const struct in_addr *); #define STATE_FAKE 0x02 void ipv4_buildroutes(struct dhcpcd_ctx *); +void ipv4_finaliseaddr(struct interface *); void ipv4_applyaddr(void *); int ipv4_handlert(struct dhcpcd_ctx *, int, struct rt *); void ipv4_freerts(struct rt_head *); @@ -84,7 +86,8 @@ struct ipv4_addr *ipv4_iffindaddr(struct interface *, struct ipv4_addr *ipv4_iffindlladdr(struct interface *); struct ipv4_addr *ipv4_findaddr(struct dhcpcd_ctx *, const struct in_addr *); void ipv4_handleifa(struct dhcpcd_ctx *, int, struct if_head *, const char *, - const struct in_addr *, const struct in_addr *, const struct in_addr *); + const struct in_addr *, const struct in_addr *, const struct in_addr *, + int); void ipv4_freeroutes(struct rt_head *); diff --git a/ipv4ll.c b/ipv4ll.c index e6569faa..5f08980e 100644 --- a/ipv4ll.c +++ b/ipv4ll.c @@ -105,11 +105,17 @@ static void ipv4ll_probed(struct arp_state *astate) { struct dhcp_state *state = D_STATE(astate->iface); - struct dhcp_message *offer; + + if (state->state == DHS_IPV4LL_BOUND) { + ipv4_finaliseaddr(astate->iface); + return; + } if (state->state != DHS_BOUND) { + struct dhcp_message *offer; + /* A DHCP lease could have already been offered. - * Backup and replace once the IPv4LL addres is bound */ + * Backup and replace once the IPv4LL address is bound */ offer = state->offer; state->offer = ipv4ll_make_lease(astate->addr.s_addr); if (state->offer == NULL) @@ -133,7 +139,11 @@ static void ipv4ll_probe(void *arg) { +#ifdef IN_IFF_TENTATIVE + ipv4ll_probed(arg); +#else arp_probe(arg); +#endif } static void @@ -144,13 +154,14 @@ ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg) fail = 0; /* RFC 3927 2.2.1, Probe Conflict Detection */ - if (amsg->sip.s_addr == astate->addr.s_addr || - (amsg->sip.s_addr == 0 && amsg->tip.s_addr == astate->addr.s_addr)) + if (amsg == NULL || + (amsg->sip.s_addr == astate->addr.s_addr || + (amsg->sip.s_addr == 0 && amsg->tip.s_addr == astate->addr.s_addr))) fail = astate->addr.s_addr; /* RFC 3927 2.5, Conflict Defense */ if (IN_LINKLOCAL(htonl(state->addr.s_addr)) && - amsg->sip.s_addr == state->addr.s_addr) + amsg && amsg->sip.s_addr == state->addr.s_addr) fail = state->addr.s_addr; if (fail == 0) @@ -254,7 +265,11 @@ ipv4ll_start(void *arg) } if (astate->addr.s_addr == INADDR_ANY) astate->addr.s_addr = ipv4ll_pick_addr(astate); +#ifdef IN_IFF_TENTATIVE + ipv4ll_probed(astate); +#else arp_probe(astate); +#endif } void