DHCP lease.
This allows us to manage IPv4LL and DHCP at the same time a lot easier.
eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate);
state = D_STATE(astate->iface);
TAILQ_REMOVE(&state->arp_states, astate, next);
- if (state->arp_ipv4ll == astate) {
- ipv4ll_stop(astate->iface);
- state->arp_ipv4ll = NULL;
- }
free(astate);
}
}
if (ifo->fallback)
eloop_timeout_add_sec(ifp->ctx->eloop,
ifo->reboot, dhcp_fallback, ifp);
- else if (ifo->options & DHCPCD_IPV4LL &&
- !IN_LINKLOCAL(htonl(state->addr.s_addr)))
+ else if (ifo->options & DHCPCD_IPV4LL)
eloop_timeout_add_sec(ifp->ctx->eloop,
ifo->reboot, ipv4ll_start, ifp);
if (ifo->options & DHCPCD_REQUEST)
return;
}
dhcp_close(astate->iface);
+
+ /* Stop IPv4LL now we have a working DHCP address */
+ ipv4ll_drop(astate->iface);
+
eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate->iface);
#ifdef IN_IFF_TENTATIVE
logger(astate->iface->ctx, LOG_DEBUG, "%s: DAD completed for %s",
struct dhcp_state *state = D_STATE(ifp);
struct if_options *ifo = ifp->options;
struct dhcp_lease *lease = &state->lease;
- uint8_t ipv4ll = 0;
if (state->state == DHS_BOUND)
goto applyaddr;
inet_ntocidr(lease->net));
lease->leasetime = ~0U;
state->reason = "STATIC";
- } else if (state->new->cookie != htonl(MAGIC_COOKIE)) {
- logger(ifp->ctx, LOG_INFO, "%s: using IPv4LL address %s",
- ifp->name, inet_ntoa(lease->addr));
- lease->leasetime = ~0U;
- state->reason = "IPV4LL";
- ipv4ll = 1;
} else if (ifo->options & DHCPCD_INFORM) {
if (ifo->req_addr.s_addr != 0)
lease->addr.s_addr = ifo->req_addr.s_addr;
#ifdef IN_IFF_TENTATIVE
if (astate)
arp_free_but(astate);
- else if (!ipv4ll)
+ else
arp_close(ifp);
#else
if (state->added) {
}
if (astate) {
arp_announce(astate);
- if (!ipv4ll)
- arp_free_but(astate);
+ arp_free_but(astate);
}
- } else if (!ipv4ll)
+ } else
arp_close(ifp);
#endif
}
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
/* Need to add this before dhcp_expire and friends. */
- if (!ifo->fallback && ifo->options & DHCPCD_IPV4LL &&
- !IN_LINKLOCAL(htonl(state->addr.s_addr)))
+ if (!ifo->fallback && ifo->options & DHCPCD_IPV4LL)
eloop_timeout_add_sec(ifp->ctx->eloop,
ifo->reboot, ipv4ll_start, ifp);
case 0:
log_dhcp(LOG_WARNING, "IPv4LL disabled from",
ifp, dhcp, from);
- dhcp_drop(ifp, "EXPIRE");
+ ipv4ll_drop(ifp);
arp_close(ifp);
- eloop_timeout_delete(ifp->ctx->eloop,
- NULL, ifp);
- eloop_timeout_add_sec(ifp->ctx->eloop,
- DHCP_MAX, dhcp_discover,
- ifp);
break;
case 1:
log_dhcp(LOG_WARNING, "IPv4LL enabled from",
ifp, dhcp, from);
- eloop_timeout_delete(ifp->ctx->eloop,
- NULL, ifp);
- if (IN_LINKLOCAL(htonl(state->addr.s_addr)))
- eloop_timeout_add_sec(ifp->ctx->eloop,
- DHCP_MAX, dhcp_discover, ifp);
- else
- ipv4ll_start(ifp);
+ ipv4ll_start(ifp);
break;
default:
logger(ifp->ctx, LOG_ERR,
ifp->name, tmp);
break;
}
+ eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+ eloop_timeout_add_sec(ifp->ctx->eloop,
+ DHCP_MAX, dhcp_discover, ifp);
}
return;
}
struct arp_statehead arp_states;
size_t arping_index;
-
- struct arp_state *arp_ipv4ll;
- unsigned int conflicts;
- time_t defend;
- char randomstate[128];
};
#define D_STATE(ifp) \
int get_option_addr(struct dhcpcd_ctx *,struct in_addr *,
const struct dhcp_message *, uint8_t);
#define IS_BOOTP(i, m) ((m) && \
- !IN_LINKLOCAL(htonl((m)->yiaddr)) && \
get_option_uint8((i)->ctx, NULL, (m), DHO_MESSAGETYPE) == -1)
struct rt_head *get_option_routes(struct interface *,
const struct dhcp_message *);
#include "if.h"
#include "if-options.h"
#include "ipv4.h"
+#include "ipv4ll.h"
#include "ipv6.h"
#include "ipv6nd.h"
#include "script.h"
dhcp6_drop(ifp, stop ? NULL : "EXPIRE6");
ipv6nd_drop(ifp);
ipv6_drop(ifp);
+ ipv4ll_drop(ifp);
dhcp_drop(ifp, stop ? "STOP" : "EXPIRE");
arp_close(ifp);
}
#define LINK_DOWN -1
#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
+#define IF_DATA_IPV4LL 1
+#define IF_DATA_DHCP 2
+#define IF_DATA_IPV6 3
+#define IF_DATA_IPV6ND 4
+#define IF_DATA_DHCP6 5
+#define IF_DATA_MAX 6
/* If the interface does not support carrier status (ie PPP),
* dhcpcd can poll it for the relevant flags periodically */
#include "if.h"
#include "if-options.h"
#include "ipv4.h"
+#include "ipv4ll.h"
#include "ipv6nd.h"
#ifdef __QNX__
if (ifp == NULL)
return;
- ipv4_free(ifp);
+ ipv4ll_free(ifp);
dhcp_free(ifp);
+ ipv4_free(ifp);
dhcp6_free(ifp);
ipv6nd_free(ifp);
ipv6_free(ifp);
((addr & IN_CLASSB_NET) == 0xc0a80000))
#endif
-#define LINKLOCAL_ADDR 0xa9fe0000
-#define LINKLOCAL_MASK IN_CLASSB_NET
-#define LINKLOCAL_BRDC (LINKLOCAL_ADDR | ~LINKLOCAL_MASK)
-
-#ifndef IN_LINKLOCAL
-# define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR)
-#endif
-
#define RAW_EOF 1 << 0
#define RAW_PARTIALCSUM 2 << 0
#include "if.h"
#include "if-options.h"
#include "ipv4.h"
+#include "ipv4ll.h"
#include "script.h"
#define IPV4_LOOPBACK_ROUTE
continue;
dnr = get_routes(ifp);
dnr = add_subnet_route(dnr, ifp);
+ if ((rt = ipv4ll_subnet_route(ifp)) != NULL)
+ TAILQ_INSERT_HEAD(dnr, rt, next);
#ifdef IPV4_LOOPBACK_ROUTE
dnr = add_loopback_route(dnr, ifp);
#endif
return state;
}
-static int
-ipv4_addaddr(struct interface *ifp, const struct dhcp_lease *lease)
+struct ipv4_addr *
+ipv4_addaddr(struct interface *ifp, const struct in_addr *addr,
+ const struct in_addr *mask, const struct in_addr *bcast)
{
struct ipv4_state *state;
struct ipv4_addr *ia;
- struct dhcp_state *dstate;
if ((state = ipv4_getstate(ifp)) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: ipv4_getstate: %m", __func__);
- return -1;
+ return NULL;
}
if (ifp->options->options & DHCPCD_NOALIAS) {
struct ipv4_addr *ian;
TAILQ_FOREACH_SAFE(ia, &state->addrs, next, ian) {
- if (ia->addr.s_addr != lease->addr.s_addr)
+ if (ia->addr.s_addr != addr->s_addr)
ipv4_deladdr(ifp, &ia->addr, &ia->net);
}
}
if ((ia = malloc(sizeof(*ia))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
- return -1;
+ return NULL;
}
logger(ifp->ctx, LOG_DEBUG, "%s: adding IP address %s/%d",
- ifp->name, inet_ntoa(lease->addr),
- inet_ntocidr(lease->net));
- if (if_addaddress(ifp, &lease->addr, &lease->net, &lease->brd) == -1) {
+ ifp->name, inet_ntoa(*addr), inet_ntocidr(*mask));
+ if (if_addaddress(ifp, addr, mask, bcast) == -1) {
if (errno != EEXIST)
logger(ifp->ctx, LOG_ERR, "%s: if_addaddress: %m",
__func__);
free(ia);
- return -1;
+ return NULL;
}
ia->iface = ifp;
- ia->addr = lease->addr;
- ia->net = lease->net;
+ ia->addr = *addr;
+ ia->net = *mask;
#ifdef IN_IFF_TENTATIVE
ia->addr_flags = IN_IFF_TENTATIVE;
#endif
TAILQ_INSERT_TAIL(&state->addrs, ia, next);
+ return ia;
+}
- dstate = D_STATE(ifp);
+static int
+ipv4_daddaddr(struct interface *ifp, const struct dhcp_lease *lease)
+{
+ struct dhcp_state *state;
+
+ if (ipv4_addaddr(ifp, &lease->addr, &lease->net, &lease->brd) == NULL)
+ return -1;
+
+ state = D_STATE(ifp);
#ifdef IN_IFF_TENTATIVE
- dstate->added |= STATE_ADDED;
+ state->added |= STATE_ADDED;
#else
- dstate->added = STATE_ADDED;
+ state->added = STATE_ADDED;
#endif
- dstate->defend = 0;
- dstate->addr.s_addr = lease->addr.s_addr;
- dstate->net.s_addr = lease->net.s_addr;
+ state->addr.s_addr = lease->addr.s_addr;
+ state->net.s_addr = lease->net.s_addr;
return 0;
}
if (ifn->options->options & DHCPCD_ARP)
dhcp_bind(ifn, NULL);
else {
- ipv4_addaddr(ifn, &nstate->lease);
+ ipv4_daddaddr(ifn, &nstate->lease);
nstate->added = STATE_ADDED;
}
break;
ifp->name, inet_ntoa(lease->addr),
inet_ntocidr(lease->net));
else {
- r = ipv4_addaddr(ifp, lease);
+ r = ipv4_daddaddr(ifp, lease);
if (r == -1 && errno != EEXIST)
return;
}
void ipv4_buildroutes(struct dhcpcd_ctx *);
void ipv4_finaliseaddr(struct interface *);
-int ipv4_deladdr(struct interface *ifp, const struct in_addr *,
+int ipv4_deladdr(struct interface *, const struct in_addr *,
const struct in_addr *);
-int ipv4_preferanother(struct interface *ifp);
+int ipv4_preferanother(struct interface *);
+struct ipv4_addr *ipv4_addaddr(struct interface *,
+ const struct in_addr *, const struct in_addr *, const struct in_addr *);
void ipv4_applyaddr(void *);
int ipv4_handlert(struct dhcpcd_ctx *, int, struct rt *);
void ipv4_freerts(struct rt_head *);
* SUCH DAMAGE.
*/
+#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include "if.h"
#include "if-options.h"
#include "ipv4ll.h"
+#include "script.h"
-static struct dhcp_message *
-ipv4ll_make_lease(uint32_t addr)
-{
- uint32_t u32;
- struct dhcp_message *dhcp;
- uint8_t *p;
-
- dhcp = calloc(1, sizeof(*dhcp));
- if (dhcp == NULL)
- return NULL;
- /* Put some LL options in */
- dhcp->yiaddr = addr;
- p = dhcp->options;
- *p++ = DHO_SUBNETMASK;
- *p++ = sizeof(u32);
- u32 = htonl(LINKLOCAL_MASK);
- memcpy(p, &u32, sizeof(u32));
- p += sizeof(u32);
- *p++ = DHO_BROADCAST;
- *p++ = sizeof(u32);
- u32 = htonl(LINKLOCAL_BRDC);
- memcpy(p, &u32, sizeof(u32));
- p += sizeof(u32);
- *p++ = DHO_END;
-
- return dhcp;
-}
+static const struct in_addr inaddr_llmask = { htonl(LINKLOCAL_MASK) };
+static const struct in_addr inaddr_llbcast = { htonl(LINKLOCAL_BRDC) };
static in_addr_t
ipv4ll_pick_addr(const struct arp_state *astate)
{
- in_addr_t addr;
- struct interface *ifp;
- const struct dhcp_state *state;
+ struct in_addr addr;
- for (;;) {
+ do {
/* RFC 3927 Section 2.1 states that the first 256 and
* last 256 addresses are reserved for future use.
* See ipv4ll_start for why we don't use arc4_random. */
- addr = ntohl(LINKLOCAL_ADDR |
+ addr.s_addr = ntohl(LINKLOCAL_ADDR |
((uint32_t)(random() % 0xFD00) + 0x0100));
/* No point using a failed address */
- if (addr == astate->failed.s_addr)
+ if (addr.s_addr == astate->failed.s_addr)
continue;
-
/* Ensure we don't have the address on another interface */
- TAILQ_FOREACH(ifp, astate->iface->ctx->ifaces, next) {
- state = D_CSTATE(ifp);
- if (state && state->addr.s_addr == addr)
- break;
- }
+ } while (ipv4_findaddr(astate->iface->ctx, &addr) != NULL);
+
+ return addr.s_addr;
+}
- /* Yay, this should be a unique and workable IPv4LL address */
- if (ifp == NULL)
- break;
+struct rt *
+ipv4ll_subnet_route(const struct interface *ifp)
+{
+ const struct ipv4ll_state *state;
+ struct rt *rt;
+
+ assert(ifp != NULL);
+ if ((state = IPV4LL_CSTATE(ifp)) == NULL ||
+ state->addr.s_addr == INADDR_ANY)
+ return NULL;
+
+ if ((rt = malloc(sizeof(*rt))) == NULL) {
+ logger(ifp->ctx, LOG_ERR, "%s: malloc: %m", __func__);
+ return NULL;
}
- return addr;
+ rt->iface = ifp;
+ rt->dest.s_addr = state->addr.s_addr & inaddr_llmask.s_addr;
+ rt->net = inaddr_llmask;
+ rt->gate.s_addr = INADDR_ANY;
+ return rt;
+}
+
+ssize_t
+ipv4ll_env(char **env, const char *prefix, const struct interface *ifp)
+{
+ const struct ipv4ll_state *state;
+ const char *pf = prefix == NULL ? "" : "_";
+ struct in_addr netnum;
+
+ assert(ifp != NULL);
+ if ((state = IPV4LL_CSTATE(ifp)) == NULL)
+ return 0;
+
+ if (env == NULL)
+ return 5;
+
+ /* Emulate a DHCP environment */
+ if (asprintf(&env[0], "%s%sip_address=%s",
+ prefix, pf, inet_ntoa(state->addr)) == -1)
+ return -1;
+ if (asprintf(&env[1], "%s%ssubnet_mask=%s",
+ prefix, pf, inet_ntoa(inaddr_llmask)) == -1)
+ return -1;
+ if (asprintf(&env[2], "%s%ssubnet_cidr=%d",
+ prefix, pf, inet_ntocidr(inaddr_llmask)) == -1)
+ return -1;
+ if (asprintf(&env[3], "%s%sbroadcast_address=%s",
+ prefix, pf, inet_ntoa(inaddr_llbcast)) == -1)
+ return -1;
+ netnum.s_addr = state->addr.s_addr & inaddr_llmask.s_addr;
+ if (asprintf(&env[4], "%s%snetwork_number=%s",
+ prefix, pf, inet_ntoa(inaddr_llbcast)) == -1)
+ return -1;
+ return 5;
}
static void
ipv4ll_probed(struct arp_state *astate)
{
- struct dhcp_state *state = D_STATE(astate->iface);
-
- if (state->state == DHS_IPV4LL_BOUND) {
- ipv4_finaliseaddr(astate->iface);
+ struct interface *ifp;
+ struct ipv4ll_state *state;
+ struct ipv4_addr *ia;
+
+ assert(astate != NULL);
+ assert(astate->iface != NULL);
+
+ ifp = astate->iface;
+ state = IPV4LL_STATE(ifp);
+ assert(state != NULL);
+
+ logger(ifp->ctx, LOG_INFO, "%s: using IPv4LL address %s",
+ ifp->name, inet_ntoa(astate->addr));
+ ia = ipv4_iffindaddr(ifp, &astate->addr, &inaddr_llmask);
+ if (ia == NULL)
+ ia = ipv4_addaddr(ifp, &astate->addr,
+ &inaddr_llmask, &inaddr_llbcast);
+ if (ia == NULL)
return;
- }
-
- if (state->state != DHS_BOUND) {
- struct dhcp_message *offer;
-
- /* A DHCP lease could have already been offered.
- * 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)
- logger(astate->iface->ctx, LOG_ERR, "%s: %m", __func__);
- else
- dhcp_bind(astate->iface, astate);
- state->offer = offer;
- }
+#ifdef IN_IFF_NOTREADY
+ if (ia->addr_flags & IN_IFF_NOTREADY)
+ return;
+ logger(ifp->ctx, LOG_DEBUG, "%s: DAD completed for %s",
+ ifp->name, inet_ntoa(astate->addr));
+#endif
+ state->addr = astate->addr;
+ state->defend = 0;
+ script_runreason(ifp, "IPV4LL");
}
static void
ipv4ll_announced(struct arp_state *astate)
{
- struct dhcp_state *state = D_STATE(astate->iface);
+ struct ipv4ll_state *state = IPV4LL_STATE(astate->iface);
state->conflicts = 0;
/* Need to keep the arp state so we can defend our IP. */
static void
ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
{
- struct dhcp_state *state = D_STATE(astate->iface);
+ struct ipv4ll_state *state;
in_addr_t fail;
+ assert(astate != NULL);
+ assert(astate->iface != NULL);
+ state = IPV4LL_STATE(astate->iface);
+ assert(state != NULL);
+
fail = 0;
/* RFC 3927 2.2.1, Probe Conflict Detection */
if (amsg == NULL ||
void
ipv4ll_start(void *arg)
{
- struct interface *ifp = arg;
- struct dhcp_state *state = D_STATE(ifp);
+ struct interface *ifp;
+ struct ipv4ll_state *state;
struct arp_state *astate;
- struct ipv4_addr *ap;
+ struct ipv4_addr *ia;
+
+ assert(arg != NULL);
+ ifp = arg;
+ if ((state = IPV4LL_STATE(ifp)) == NULL) {
+ ifp->if_data[IF_DATA_IPV4LL] = calloc(1, sizeof(*state));
+ if ((state = IPV4LL_STATE(ifp)) == NULL) {
+ syslog(LOG_ERR, "%s: calloc %m", __func__);
+ return;
+ }
+
+ state->addr.s_addr = INADDR_ANY;
+ }
- if (state->arp_ipv4ll)
+ if (state->arp != NULL)
return;
/* RFC 3927 Section 2.1 states that the random number generator
if ((astate = arp_new(ifp, NULL)) == NULL)
return;
- state->arp_ipv4ll = astate;
+ state->arp = astate;
astate->probed_cb = ipv4ll_probed;
astate->announced_cb = ipv4ll_announced;
astate->conflicted_cb = ipv4ll_conflicted;
- if (IN_LINKLOCAL(htonl(state->addr.s_addr))) {
- astate->addr = state->addr;
- arp_announce(astate);
- return;
+ /* Find an existing IPv4LL address and ensure we can work with it. */
+ ia = ipv4_iffindlladdr(ifp);
+#ifdef IN_IFF_TENTATIVE
+ if (ia != NULL && ia->addr_flags & IN_IFF_DUPLICATED) {
+ ipv4_deladdr(ifp, &ia->addr, &ia->net);
+ ia = NULL;
}
-
- if (state->offer && IN_LINKLOCAL(ntohl(state->offer->yiaddr))) {
- astate->addr.s_addr = state->offer->yiaddr;
- free(state->offer);
- state->offer = NULL;
- ap = ipv4_iffindaddr(ifp, &astate->addr, NULL);
- } else
- ap = ipv4_iffindlladdr(ifp);
- if (ap) {
- astate->addr = ap->addr;
+#endif
+ if (ia != NULL) {
+ astate->addr = ia->addr;
+#ifdef IN_IFF_TENTATIVE
+ if (ia->addr_flags & (IN_IFF_TENTATIVE | IN_IFF_DETACHED)) {
+ logger(ifp->ctx, LOG_INFO,
+ "%s: waiting for DAD to complete on %s",
+ ifp->name, inet_ntoa(ia->addr));
+ return;
+ }
+#endif
ipv4ll_probed(astate);
return;
}
setstate(state->randomstate);
- /* We maybe rebooting an IPv4LL address. */
- if (!IN_LINKLOCAL(htonl(astate->addr.s_addr))) {
- logger(ifp->ctx, LOG_INFO, "%s: probing for an IPv4LL address",
- ifp->name);
- astate->addr.s_addr = INADDR_ANY;
- }
- if (astate->addr.s_addr == INADDR_ANY)
- astate->addr.s_addr = ipv4ll_pick_addr(astate);
+ logger(ifp->ctx, LOG_INFO, "%s: probing for an IPv4LL address",
+ ifp->name);
+ astate->addr.s_addr = ipv4ll_pick_addr(astate);
#ifdef IN_IFF_TENTATIVE
ipv4ll_probed(astate);
#else
}
void
-ipv4ll_stop(struct interface *ifp)
+ipv4ll_freedrop(struct interface *ifp, int drop)
{
- struct dhcp_state *state = D_STATE(ifp);
+ struct ipv4ll_state *state;
- eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp_ipv4ll);
+ assert(ifp != NULL);
+ if ((state = IPV4LL_STATE(ifp)) == NULL)
+ return;
+
+ /* Free ARP state first because ipv4_deladdr might also ... */
+ if (state->arp) {
+ eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp);
+ arp_free(state->arp);
+ state->arp = NULL;
+ }
+
+ /* Unlike other protocols, we don't run a script on stopping IPv4LL
+ * because we piggy back on the state of DHCP. */
+ if (drop) {
+ if (state->addr.s_addr != INADDR_ANY) {
+ ipv4_deladdr(ifp, &state->addr, &inaddr_llmask);
+ state->addr.s_addr = INADDR_ANY;
+ }
+ }
+ free(state);
+ ifp->if_data[IF_DATA_IPV4LL] = NULL;
}
#ifndef IPV4LL_H
#define IPV4LL_H
+#include "arp.h"
+
+#define LINKLOCAL_ADDR 0xa9fe0000
+#define LINKLOCAL_MASK IN_CLASSB_NET
+#define LINKLOCAL_BRDC (LINKLOCAL_ADDR | ~LINKLOCAL_MASK)
+
+#ifndef IN_LINKLOCAL
+# define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR)
+#endif
+
+struct ipv4ll_state {
+ struct in_addr addr;
+ struct arp_state *arp;
+ unsigned int conflicts;
+ time_t defend;
+ char randomstate[128];
+};
+
+#define IPV4LL_STATE(ifp) \
+ ((struct ipv4ll_state *)(ifp)->if_data[IF_DATA_IPV4LL])
+#define IPV4LL_CSTATE(ifp) \
+ ((const struct ipv4ll_state *)(ifp)->if_data[IF_DATA_IPV4LL])
+
+struct rt* ipv4ll_subnet_route(const struct interface *);
+ssize_t ipv4ll_env(char **, const char *, const struct interface *);
void ipv4ll_start(void *);
void ipv4ll_claimed(void *);
void ipv4ll_handle_failure(void *);
-void ipv4ll_stop(struct interface *);
+
+#define ipv4ll_free(ifp) ipv4ll_freedrop((ifp), 0);
+#define ipv4ll_drop(ifp) ipv4ll_freedrop((ifp), 1);
+void ipv4ll_freedrop(struct interface *, int);
#endif
#include "dhcp6.h"
#include "if.h"
#include "if-options.h"
+#include "ipv4ll.h"
#include "ipv6nd.h"
#include "script.h"
const struct interface *ifp2;
int af;
#ifdef INET
- int dhcp;
+ int dhcp, ipv4ll;
const struct dhcp_state *state;
#endif
#ifdef INET6
#endif
#ifdef INET
- dhcp = 0;
+ dhcp = ipv4ll = 0;
state = D_STATE(ifp);
#endif
#ifdef INET6
ra = 1;
#endif
#ifdef INET
+ else if (strcmp(reason, "IPV4LL") == 0)
+ ipv4ll = 1;
else
dhcp = 1;
#endif
dumplease:
#ifdef INET
+ if (ipv4ll) {
+ n = ipv4ll_env(NULL, NULL, ifp);
+ if (n > 0) {
+ nenv = realloc(env, sizeof(char *) *
+ (elen + (size_t)n + 1));
+ if (nenv == NULL)
+ goto eexit;
+ env = nenv;
+ if ((n = ipv4ll_env(env + elen, "new", ifp)) == -1)
+ goto eexit;
+ elen += (size_t)n;
+ }
+ }
if (dhcp && state && state->new) {
n = dhcp_env(NULL, NULL, state->new, ifp);
if (n > 0) {