}
-static void
+static bool
dhcp_addr_duplicated(struct interface *ifp, struct in_addr *ia)
{
struct dhcp_state *state = D_STATE(ifp);
unsigned long long opts = ifp->options->options;
struct dhcpcd_ctx *ctx = ifp->ctx;
+ bool deleted = false;
#ifdef IN_IFF_DUPLICATED
struct ipv4_addr *iap;
#endif
if ((state->offer == NULL || state->offer->yiaddr != ia->s_addr) &&
!IN_ARE_ADDR_EQUAL(ia, &state->lease.addr))
- return;
+ return deleted;
/* RFC 2131 3.1.5, Client-server interaction */
logerrx("%s: DAD detected %s", ifp->name, inet_ntoa(*ia));
if (!(opts & DHCPCD_STATIC) && !state->lease.frominfo)
dhcp_decline(ifp);
#ifdef IN_IFF_DUPLICATED
- if ((iap = ipv4_iffindaddr(ifp, ia, NULL)) != NULL)
+ if ((iap = ipv4_iffindaddr(ifp, ia, NULL)) != NULL) {
ipv4_deladdr(iap, 0);
+ deleted = true;
+ }
#endif
eloop_timeout_delete(ctx->eloop, NULL, ifp);
if (opts & (DHCPCD_STATIC | DHCPCD_INFORM)) {
script_runreason(ifp, state->reason);
if (!(ctx->options & DHCPCD_MASTER))
eloop_exit(ifp->ctx->eloop, EXIT_FAILURE);
- return;
+ return deleted;
}
eloop_timeout_add_sec(ifp->ctx->eloop,
DHCP_RAND_MAX, dhcp_discover, ifp);
+ return deleted;
}
#endif
}
}
-void
+struct ipv4_addr *
dhcp_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid)
{
struct interface *ifp;
ifp = ia->iface;
state = D_STATE(ifp);
if (state == NULL || state->state == DHS_NONE)
- return;
+ return ia;
if (cmd == RTM_DELADDR) {
if (state->addr == ia) {
* to drop the lease. */
dhcp_drop(ifp, "EXPIRE");
dhcp_start1(ifp);
+ return NULL;
}
- return;
}
if (cmd != RTM_NEWADDR)
- return;
+ return ia;
#ifdef IN_IFF_NOTUSEABLE
if (!(ia->addr_flags & IN_IFF_NOTUSEABLE))
dhcp_finish_dad(ifp, &ia->addr);
else if (ia->addr_flags & IN_IFF_DUPLICATED)
- dhcp_addr_duplicated(ifp, &ia->addr);
+ return dhcp_addr_duplicated(ifp, &ia->addr) ? NULL : ia;
#endif
ifo = ifp->options;
if (ifo->options & DHCPCD_INFORM) {
if (state->state != DHS_INFORM)
dhcp_inform(ifp);
- return;
+ return ia;
}
if (!(ifo->options & DHCPCD_STATIC))
- return;
+ return ia;
if (ifo->req_addr.s_addr != INADDR_ANY)
- return;
+ return ia;
free(state->old);
state->old = state->new;
state->new_len = dhcp_message_new(&state->new, &ia->addr, &ia->mask);
if (state->new == NULL)
- return;
+ return ia;
if (ifp->flags & IFF_POINTOPOINT) {
for (i = 1; i < 255; i++)
if (i != DHO_ROUTER && has_option_mask(ifo->dstmask,i))
state->addr = ia;
dhcp_inform(ifp);
}
+
+ return ia;
}
ssize_t dhcp_env(FILE *, const char *, const struct interface *,
const struct bootp *, size_t);
-void dhcp_handleifa(int, struct ipv4_addr *, pid_t pid);
+struct ipv4_addr *dhcp_handleifa(int, struct ipv4_addr *, pid_t pid);
void dhcp_drop(struct interface *, const char *);
void dhcp_start(struct interface *);
void dhcp_abort(struct interface *);
}
if (addr->s_addr != INADDR_ANY && addr->s_addr != INADDR_BROADCAST) {
- /* If the handler deletes the address, the other might crash.
- * So only call one handler based on the address type. */
- if (IN_LINKLOCAL(ntohl(addr->s_addr)))
+ ia = dhcp_handleifa(cmd, ia, pid);
#ifdef IPV4LL
+ if (ia != NULL)
ipv4ll_handleifa(cmd, ia, pid);
-#else
- ;
#endif
- else
- dhcp_handleifa(cmd, ia, pid);
}
- if (cmd == RTM_DELADDR)
+ if (cmd == RTM_DELADDR && ia != NULL)
free(ia);
}
}
#endif
-void
+struct ipv4_addr *
ipv4ll_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid)
{
struct interface *ifp;
ifp = ia->iface;
state = IPV4LL_STATE(ifp);
if (state == NULL)
- return;
+ return ia;
if (cmd == RTM_DELADDR &&
state->addr != NULL &&
loginfox("%s: pid %d deleted IP address %s",
ifp->name, pid, ia->saddr);
ipv4ll_defend_failed(ifp);
- return;
+ return ia;
}
#ifdef IN_IFF_DUPLICATED
if (cmd != RTM_NEWADDR)
- return;
+ return ia;
if (!IN_ARE_ADDR_EQUAL(&state->pickedaddr, &ia->addr))
- return;
+ return ia;
if (!(ia->addr_flags & IN_IFF_NOTUSEABLE))
ipv4ll_not_found(ifp);
else if (ia->addr_flags & IN_IFF_DUPLICATED) {
logerrx("%s: DAD detected %s", ifp->name, ia->saddr);
ipv4_deladdr(ia, 1);
ipv4ll_found(ifp);
+ return NULL;
}
#endif
+
+ return ia;
}