to handle the IA_PD.
ia_pd_mix config option disables this and mixes IA_PD in the single session as
per draft-ietf-dhc-dhcpv6-stateful-issues-06.
}
TAILQ_FOREACH(ifd, ifp->ctx->ifaces, next) {
+ if (ifp->options->options & DHCPCD_NOPFXDLG)
+ continue;
k = 0;
carrier_warned = abrt = 0;
TAILQ_FOREACH(ap, &state->addrs, next) {
return k;
}
+static struct interface *
+dhcp6_findpfxdlgif(struct interface *ifp)
+{
+ struct interface *ifn;
+
+ if (ifp->options && ifp->options->options & DHCPCD_PFXDLGONLY)
+ return NULL;
+
+ if (ifp->ctx && ifp->ctx->ifaces) {
+ TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
+ if (strcmp(ifn->name, ifp->name) == 0 &&
+ ifn->options->options & DHCPCD_PFXDLGONLY)
+ return ifn;
+ }
+ }
+ return NULL;
+}
+
/* ARGSUSED */
static void
dhcp6_handledata(void *arg)
ssize_t bytes;
struct cmsghdr *cm;
struct in6_pktinfo pkt;
- struct interface *ifp;
+ struct interface *ifp, *ifpx;
const char *op;
struct dhcp6_message *r;
struct dhcp6_state *state;
ctx->sfrom);
return;
}
+
+ r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base;
+
+ /* Which interface state is the IAID for? */
+ ifpx = dhcp6_findpfxdlgif(ifp);
+ if (ifpx && D6_STATE(ifpx)) {
+ state = D6_STATE(ifpx);
+ if (r->xid[0] == state->send->xid[0] &&
+ r->xid[1] == state->send->xid[1] &&
+ r->xid[2] == state->send->xid[2])
+ ifp = ifpx;
+ }
+
state = D6_STATE(ifp);
if (state == NULL || state->send == NULL) {
syslog(LOG_DEBUG, "%s: DHCPv6 reply received but not running",
ifp->name);
return;
}
-
- r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base;
-
/* We're already bound and this message is for another machine */
/* XXX DELEGATED? */
if (r->type != DHCP6_RECONFIGURE &&
(state->state == DH6S_BOUND || state->state == DH6S_INFORMED))
return;
- r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base;
if (r->type != DHCP6_RECONFIGURE &&
(r->xid[0] != state->send->xid[0] ||
r->xid[1] != state->send->xid[1] ||
if (dhcp6_findselfsla(ifp, NULL))
del_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT);
+ /* Create a 2nd interface to handle the PD state */
+ if (!(ifo->options & (DHCPCD_PFXDLGONLY | DHCPCD_PFXDLGMIX)) &&
+ dhcp6_hasprefixdelegation(ifp))
+ {
+ const char * const argv[] = { ifp->name };
+ struct if_head *ifs;
+ struct interface *ifn;
+
+ ifn = dhcp6_findpfxdlgif(ifp);
+ if (ifn == NULL) {
+ ifs = if_discover(ifp->ctx, -1, UNCONST(argv));
+ if (ifs) {
+ ifn = TAILQ_FIRST(ifs);
+ if (ifn) {
+ syslog(LOG_INFO,
+ "%s: creating psuedo interface"
+ " to handle Prefix Delegation",
+ ifp->name);
+ ifp->options->options |=
+ DHCPCD_NOPFXDLG;
+ TAILQ_REMOVE(ifs, ifn, next);
+ TAILQ_INSERT_AFTER(ifp->ctx->ifaces,
+ ifp, ifn, next);
+ dhcpcd_initstate(ifn);
+ ifn->options->options |=
+ DHCPCD_PFXDLGONLY;
+ ifn->options->options &=
+ ~(DHCPCD_IPV4 | DHCPCD_IPV6RS |
+ DHCPCD_NOPFXDLG);
+ eloop_timeout_add_sec(ifp->ctx->eloop,
+ 0, dhcpcd_startinterface, ifn);
+ }
+ while ((ifn = TAILQ_FIRST(ifs))) {
+ TAILQ_REMOVE(ifs, ifn, next);
+ if_free(ifn);
+ }
+ free(ifs);
+ }
+ }
+ }
+
if (state->state == DH6S_INFORM) {
add_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
dhcp6_startinform(ifp);
static void
dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
{
+ struct interface *ifpx;
struct dhcp6_state *state;
struct dhcpcd_ctx *ctx;
unsigned long long options;
+ ifpx = dhcp6_findpfxdlgif(ifp);
+ if (ifpx) {
+ dhcp6_freedrop(ifpx, drop, reason);
+ TAILQ_REMOVE(ifp->ctx->ifaces, ifpx, next);
+ if_free(ifpx);
+ }
+
if (ifp->ctx->eloop)
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 4, 2014
+.Dd July 7, 2014
.Dt DHCPCD 8
.Os
.Sh NAME
.Fl U, Fl Fl dumplease
.Ar interface
.Nm
-.Fl Fl pfxdlgonly
-.Nm
-.Fl Fl nopfxdlg
-.Nm
.Fl Fl version
.Nm
.Fl x , Fl Fl exit
to stdout.
.Ar interface
could also be a path to a DHCP wire formatted file.
+Use the
+.Fl 4
+or
+.Fl 6
+flags to specify an address family.
+Pass a 2nd
+.Fl U, Fl Fl dumplease option to dump a secondary lease, such as
+DHCPv6 Prefix Delegation when not being mixed with another IA type.
.It Fl V, Fl Fl variables
Display a list of option codes and the associated variable for use in
.Xr dhcpcd-run-hooks 8 .
so that
.Nm
knows which process to signal.
-.Pp
-.Li RFC3633
-DHCPv6 Prefix Delegation does not work in the same state or session as
-Normal or Temporary Addresses.
-.Nm
-is designed for a single state per protocol and as such
-.Li draft-ietf-dhc-dhcpv6-stateful-issues-06
-is supported by default, but that is not a published RFC yet.
-To allow RFC conformance,
-.Nm
-supports the
-.Fl Fl pfxdlgonly
-and
-.Fl Fl nopfxdlg
-options which allow the spawning of two
-.Nm
-instances to separate the Prefix Delegation state from the others.
-You may wish to disable
-.Xr dhcpcd-run-hooks 8
-on the
-.Fl Fl pfxdlgonly
-instance using the
-.Fl Fl script \"\"
-option.
.Sh FILES
.Bl -ohang
.It Pa @SYSCONFDIR@/dhcpcd.conf
}
/* This is only a problem if the interfaces are on the same network. */
- if (ifn)
+ if (ifn && strcmp(ifp->name, ifn->name))
syslog(LOG_ERR,
"%s: IAID conflicts with one assigned to %s",
ifp->name, ifn->name);
}
static void
-init_state(struct interface *ifp, int argc, char **argv)
+dhcpcd_initstate1(struct interface *ifp, int argc, char **argv)
{
struct if_options *ifo;
}
}
+void
+dhcpcd_initstate(struct interface *ifp)
+{
+
+ dhcpcd_initstate1(ifp, ifp->ctx->argc, ifp->ctx->argv);
+}
+
static void
run_preinit(struct interface *ifp)
{
syslog(LOG_DEBUG, "%s: interface added", ifp->name);
TAILQ_REMOVE(ifs, ifp, next);
TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next);
- init_state(ifp, ctx->argc, ctx->argv);
+ dhcpcd_initstate(ifp);
run_preinit(ifp);
iff = ifp;
}
if_free(ifp);
} else {
TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next);
- init_state(ifp, argc, argv);
+ dhcpcd_initstate1(ifp, argc, argv);
run_preinit(ifp);
dhcpcd_startinterface(ifp);
}
static void
stop_all_interfaces(struct dhcpcd_ctx *ctx, int do_release)
{
- struct interface *ifp;
+ struct interface *ifp, *ifpm;
/* drop_dhcp could change the order, so we do it like this. */
for (;;) {
ifp = TAILQ_LAST(ctx->ifaces, if_head);
if (ifp == NULL)
break;
+ /* Stop the master interface only */
+ ifpm = if_find(ifp->ctx, ifp->name);
+ if (ifpm)
+ ifp = ifpm;
if (do_release) {
ifp->options->options |= DHCPCD_RELEASE;
ifp->options->options &= ~DHCPCD_PERSISTENT;
i = 1;
break;
case 'U':
- i = 2;
+ if (i == 3)
+ i = 4;
+ else if (i != 4)
+ i = 3;
break;
case 'V':
- i = 3;
+ i = 2;
break;
case '?':
usage();
usage();
goto exit_failure;
}
- if (i == 3) {
+ if (i == 2) {
printf("Interface options:\n");
if (optind == argc - 1) {
free_options(ifo);
ctx.options |= DHCPCD_TEST;
else
ctx.options |= DHCPCD_DUMPLEASE;
+ if (i == 4)
+ ctx.options |= DHCPCD_PFXDLGONLY;
ctx.options |= DHCPCD_PERSISTENT;
ctx.options &= ~DHCPCD_DAEMONISE;
}
snprintf(pidfile, sizeof(pidfile),
PIDFILE, "-", argv[optind], per);
} else {
- snprintf(pidfile, sizeof(pidfile), PIDFILE,
- ctx.options & DHCPCD_PFXDLGONLY ? ".pd" : "",
- "", "");
+ snprintf(pidfile, sizeof(pidfile), PIDFILE, "", "", "");
ctx.options |= DHCPCD_MASTER;
}
}
TAILQ_INSERT_HEAD(ctx.ifaces, ifp, next);
}
configure_interface(ifp, ctx.argc, ctx.argv);
+ if (ctx.options & DHCPCD_PFXDLGONLY)
+ ifp->options->options |= DHCPCD_PFXDLGONLY;
if (family == 0 || family == AF_INET) {
if (dhcp_dump(ifp) == -1)
i = 1;
}
#ifdef USE_SIGNALS
- if (!(ctx.options & (DHCPCD_TEST | DHCPCD_PFXDLGONLY)) &&
+ if (!(ctx.options & DHCPCD_TEST) &&
(sig == 0 || ctx.ifc != 0))
{
#endif
}
- if (ctx.options & DHCPCD_MASTER && !(ctx.options & DHCPCD_PFXDLGONLY)) {
+ if (ctx.options & DHCPCD_MASTER) {
if (control_start(&ctx, NULL) == -1)
syslog(LOG_ERR, "control_start: %m");
}
}
TAILQ_FOREACH(ifp, ctx.ifaces, next) {
- init_state(ifp, argc, argv);
+ dhcpcd_initstate1(ifp, argc, argv);
}
if (ctx.options & DHCPCD_BACKGROUND && dhcpcd_daemonise(&ctx))
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 4, 2014
+.Dd July 7, 2014
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
.D1 interface eth1
.D1 ipv4
.D1 ipv6rs
-.Pp
-Using this option with other IA options in the same interface block is not
-currently RFC conformant.
-Please see the
-.Li BUGS
-section below.
+.It Ic ia_pd_mix
+To be RFC compliant,
+.Nm dhcpcd
+cannot mix Prefix Delegation with other DHCPv6 address types in the same
+session.
+This has a number of issues: additional DHCP traffic and potential collisions
+between options.
+.Ic ia_pd_mix
+enables
+.Li draft-ietf-dhc-dhcpv6-stateful-issues-06
+support so that Prefix Delegation can be mixed with other address types in
+the same session.
.It Ic ipv4only
Only configure IPv4.
.It Ic ipv6only
.Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name
.Sh BUGS
-Combining different DHCPv6 IA options in the same interface block is not
-currently RFC conformant.
-See
-.Lk http://datatracker.ietf.org/doc/draft-ietf-dhc-dhcpv6-stateful-issues
-for details.
-.Nm dhcpcd
-strives to comply with this document and will be updated when finally published.
-To enable RFC conformance, spawn separate
-.Nm dhcpcd
-instances using the
-.Fl Fl pfxdlgonly
-and
-.Fl Fl nopfxdlg
-options as described in
-.Xr dhcpcd 8 .
-.Pp
Please report them to
.Lk http://roy.marples.name/projects/dhcpcd
int dhcpcd_selectprofile(struct interface *, const char *);
void dhcpcd_startinterface(void *);
+void dhcpcd_initstate(struct interface *);
#endif
#define O_CONTROLGRP O_BASE + 34
#define O_SLAAC O_BASE + 35
#define O_GATEWAY O_BASE + 36
-#define O_NOPFXDLG O_BASE + 37
-#define O_PFXDLGONLY O_BASE + 38
+#define O_PFXDLGMIX O_BASE + 37
const struct option cf_options[] = {
{"background", no_argument, NULL, 'b'},
{"controlgroup", required_argument, NULL, O_CONTROLGRP},
{"slaac", required_argument, NULL, O_SLAAC},
{"gateway", no_argument, NULL, O_GATEWAY},
- {"nopfxdlg", no_argument, NULL, O_NOPFXDLG},
- {"pfxdlgonly", no_argument, NULL, O_PFXDLGONLY},
+ {"ia_pd_mix", no_argument, NULL, O_PFXDLGMIX},
{NULL, 0, NULL, '\0'}
};
else
ifo->options &= ~DHCPCD_SLAACPRIVATE;
break;
- case O_NOPFXDLG:
- ifo->options |= DHCPCD_NOPFXDLG;
- break;
- case O_PFXDLGONLY:
- ifo->options |= DHCPCD_PFXDLGONLY;
+ case O_PFXDLGMIX:
+ ifo->options |= DHCPCD_PFXDLGMIX;
break;
default:
return 0;
#define DHCPCD_DHCP6 (1ULL << 50)
#define DHCPCD_NOPFXDLG (1ULL << 51)
#define DHCPCD_PFXDLGONLY (1ULL << 52)
+#define DHCPCD_PFXDLGMIX (1ULL << 53)
extern const struct option cf_options[];
}
if (ifp)
continue;
+
if (argc > 0) {
for (i = 0; i < argc; i++) {
#ifdef __linux__
if (ctx != NULL && ctx->ifaces != NULL) {
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
- if (strcmp(ifp->name, ifname) == 0)
+ if ((ifp->options ||
+ !(ifp->options->options & DHCPCD_PFXDLGONLY)) &&
+ strcmp(ifp->name, ifname) == 0)
return ifp;
}
}