changeset 2542:28b1ed6d98ad draft

Allow the request of a DHCPv6 address or prefix, a prefix length must be specified.
author Roy Marples <roy@marples.name>
date Sat, 21 Jun 2014 11:42:36 +0000
parents 98b581c3152b
children 8255dad7230c
files dhcp6.c dhcpcd.conf.5.in if-options.c if-options.h ipv6.h
diffstat 5 files changed, 110 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/dhcp6.c	Fri Jun 20 22:32:44 2014 +0000
+++ b/dhcp6.c	Sat Jun 21 11:42:36 2014 +0000
@@ -405,12 +405,15 @@
 	case DH6S_REBIND:
 		/* FALLTHROUGH */
 	case DH6S_CONFIRM:
+		/* FALLTHROUGH */
+	case DH6S_DISCOVER:
 		if (m == NULL) {
 			m = state->new;
 			ml = state->new_len;
 		}
 		TAILQ_FOREACH(ap, &state->addrs, next) {
-			if (ap->prefix_vltime == 0)
+			if (ap->prefix_vltime == 0 &&
+			    !(ap->flags & IPV6_AF_REQUEST))
 				continue;
 			if (ifo->ia_type == D6_OPTION_IA_PD)
 				len += sizeof(*o) + sizeof(u8) +
@@ -421,8 +424,7 @@
 				    sizeof(u32) + sizeof(u32);
 		}
 		/* FALLTHROUGH */
-	case DH6S_INIT: /* FALLTHROUGH */
-	case DH6S_DISCOVER:
+	case DH6S_INIT:
 		len += ifo->ia_len * (sizeof(*o) + (sizeof(u32) * 3));
 		IA = 1;
 		break;
@@ -536,7 +538,8 @@
 		p += sizeof(u32);
 		memset(p, 0, sizeof(u32) + sizeof(u32));
 		TAILQ_FOREACH(ap, &state->addrs, next) {
-			if (ap->prefix_vltime == 0)
+			if (ap->prefix_vltime == 0 &&
+			    !(ap->flags & IPV6_AF_REQUEST))
 				continue;
 			if (memcmp(ifo->ia[l].iaid, ap->iaid, sizeof(u32)))
 				continue;
@@ -949,10 +952,51 @@
 }
 
 static void
+dhcp6_dadcallback(void *arg)
+{
+	struct ipv6_addr *ap = arg;
+	struct interface *ifp;
+	struct dhcp6_state *state;
+	int wascompleted;
+
+	wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
+	ap->flags |= IPV6_AF_DADCOMPLETED;
+	if (ap->flags & IPV6_AF_DUPLICATED)
+		/* XXX FIXME
+		 * We should decline the address */
+		syslog(LOG_WARNING, "%s: DAD detected %s",
+		    ap->iface->name, ap->saddr);
+
+	if (!wascompleted) {
+		ifp = ap->iface;
+		state = D6_STATE(ifp);
+		if (state->state == DH6S_BOUND ||
+		    state->state == DH6S_DELEGATED)
+		{
+			TAILQ_FOREACH(ap, &state->addrs, next) {
+				if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
+					wascompleted = 1;
+					break;
+				}
+			}
+			if (!wascompleted) {
+				syslog(LOG_DEBUG, "%s: DHCPv6 DAD completed",
+				    ifp->name);
+				script_runreason(ifp, state->reason);
+				dhcpcd_daemonise(ifp->ctx);
+			}
+		}
+	}
+}
+
+static void
 dhcp6_startdiscover(void *arg)
 {
 	struct interface *ifp;
 	struct dhcp6_state *state;
+	size_t i;
+	struct if_ia *ia;
+	struct ipv6_addr *a;
 
 	ifp = arg;
 	dhcp6_delete_delegates(ifp);
@@ -974,6 +1018,30 @@
 	dhcp6_freedrop_addrs(ifp, 0, NULL);
 	unlink(state->leasefile);
 
+	/* Add any requested prefixes / addresses */
+	for (i = 0; i < ifp->options->ia_len; i++) {
+		ia = &ifp->options->ia[i];
+		if (ia->prefix_len) {
+			a = calloc(1, sizeof(*a));
+			if (a == NULL) {
+				syslog(LOG_ERR, "%s: %m", __func__);
+				return NULL;
+			}
+			a->flags = IPV6_AF_REQUEST;
+			a->iface = ifp;
+			a->dadcallback = dhcp6_dadcallback;
+			memcpy(&a->iaid, &ia->iaid, sizeof(a->iaid));
+			//a->prefix_pltime = 0;
+			//a->prefix_vltime = 0;
+			if (ifp->options->ia_type == D6_OPTION_IA_PD)
+				memcpy(&a->prefix, &ia->addr, sizeof(a->addr));
+			else
+				memcpy(&a->addr, &ia->addr, sizeof(a->addr));
+			a->prefix_len = ia->prefix_len;
+			TAILQ_INSERT_TAIL(&state->addrs, a, next);
+		}
+	}
+
 	if (dhcp6_makemessage(ifp) == -1)
 		syslog(LOG_ERR, "%s: dhcp6_makemessage: %m", ifp->name);
 	else
@@ -1264,44 +1332,6 @@
 	return 0;
 }
 
-static void
-dhcp6_dadcallback(void *arg)
-{
-	struct ipv6_addr *ap = arg;
-	struct interface *ifp;
-	struct dhcp6_state *state;
-	int wascompleted;
-
-	wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
-	ap->flags |= IPV6_AF_DADCOMPLETED;
-	if (ap->flags & IPV6_AF_DUPLICATED)
-		/* XXX FIXME
-		 * We should decline the address */
-		syslog(LOG_WARNING, "%s: DAD detected %s",
-		    ap->iface->name, ap->saddr);
-
-	if (!wascompleted) {
-		ifp = ap->iface;
-		state = D6_STATE(ifp);
-		if (state->state == DH6S_BOUND ||
-		    state->state == DH6S_DELEGATED)
-		{
-			TAILQ_FOREACH(ap, &state->addrs, next) {
-				if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
-					wascompleted = 1;
-					break;
-				}
-			}
-			if (!wascompleted) {
-				syslog(LOG_DEBUG, "%s: DHCPv6 DAD completed",
-				    ifp->name);
-				script_runreason(ifp, state->reason);
-				dhcpcd_daemonise(ifp->ctx);
-			}
-		}
-	}
-}
-
 static int
 dhcp6_findna(struct interface *ifp, const uint8_t *iaid,
     const uint8_t *d, size_t l)
@@ -1370,7 +1400,7 @@
 			    "%s/%d", ia, a->prefix_len);
 			TAILQ_INSERT_TAIL(&state->addrs, a, next);
 		} else
-			a->flags &= ~IPV6_AF_STALE;
+			a->flags &= ~(IPV6_AF_STALE | IPV6_AF_REQUEST);
 		memcpy(&u32, p, sizeof(u32));
 		a->prefix_pltime = ntohl(u32);
 		p += sizeof(u32);
@@ -1455,7 +1485,7 @@
 			    "%s/%d", ia, a->prefix_len);
 			TAILQ_INSERT_TAIL(&state->addrs, a, next);
 		} else {
-			a->flags &= ~IPV6_AF_STALE;
+			a->flags &= ~(IPV6_AF_STALE | IPV6_AF_REQUEST);
 			if (a->prefix_vltime != vltime)
 				a->flags |= IPV6_AF_NEW;
 		}
--- a/dhcpcd.conf.5.in	Fri Jun 20 22:32:44 2014 +0000
+++ b/dhcpcd.conf.5.in	Sat Jun 21 11:42:36 2014 +0000
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd June 6, 2014
+.Dd June 20, 2014
 .Dt DHCPCD.CONF 5
 .Os
 .Sh NAME
@@ -214,7 +214,7 @@
 Also, see the
 .Ic env
 option above to control how the hostname is set on the host.
-.It Ic ia_na Op Ar iaid
+.It Ic ia_na Op Ar iaid Op / address Op / prefix_len
 Request a DHCPv6 Normal Address for
 .Ar iaid .
 .Ar iaid
@@ -230,7 +230,7 @@
 You can request more than one ia_ta by specifying a unique
 .Ar iaid
 for each one.
-.It Ic ia_pd Op Ar iaid Op Ar interface Op / Ar sla_id Op / Ar prefix_len
+.It Ic ia_pd Op Ar iaid Oo / Ar prefix / Ar prefix_len Oc Op Ar interface Op / Ar sla_id Op / Ar prefix_len
 Request a DHCPv6 Delegated Prefix for
 .Ar iaid .
 This option must be used in an
--- a/if-options.c	Fri Jun 20 22:32:44 2014 +0000
+++ b/if-options.c	Sat Jun 21 11:42:36 2014 +0000
@@ -1236,6 +1236,9 @@
 		fp = strwhite(arg);
 		if (fp)
 			*fp++ = '\0';
+		p = strchr(arg, '/');
+		if (p)
+			*p++ = '\0';
 		if (parse_iaid(iaid, arg, sizeof(iaid)) == -1)
 			return -1;
 		ia = NULL;
@@ -1262,8 +1265,33 @@
 			ia->iaid[1] = iaid[1];
 			ia->iaid[2] = iaid[2];
 			ia->iaid[3] = iaid[3];
+			if (p == NULL) {
+				memset(&ia->addr, 0, sizeof(ia->addr));
+				ia->prefix_len = 0;
+			} else {
+				arg = p;
+				p = strchr(arg, '/');
+				if (p)
+					*p++ = '\0';
+				if (inet_pton(AF_INET6, arg, &ia->addr) == -1) {
+					syslog(LOG_ERR, "%s: %m", arg);
+					memset(&ia->addr, 0, sizeof(ia->addr));
+				}
+				if (p) {
+					i = atoint(p);
+					if (i != -1 && (i < 8 || i > 120)) {
+						errno = EINVAL;
+						i = -1;
+					}
+					if (i == -1) {
+						syslog(LOG_ERR, "%s: %m", p);
+						ia->prefix_len = 0;
+					} else
+						ia->prefix_len = (uint8_t)i;
+				}
+			}
+			ia->sla_len = 0;
 			ia->sla = NULL;
-			ia->sla_len = 0;
 		}
 		if (ifo->ia_type != D6_OPTION_IA_PD)
 			break;
--- a/if-options.h	Fri Jun 20 22:32:44 2014 +0000
+++ b/if-options.h	Sat Jun 21 11:42:36 2014 +0000
@@ -115,6 +115,8 @@
 struct if_ia {
 	uint8_t iaid[4];
 #ifdef INET6
+	struct in6_addr addr;
+	uint8_t prefix_len;
 	size_t sla_len;
 	struct if_sla *sla;
 #endif
--- a/ipv6.h	Fri Jun 20 22:32:44 2014 +0000
+++ b/ipv6.h	Sat Jun 21 11:42:36 2014 +0000
@@ -109,7 +109,8 @@
 #define IPV6_AF_DADCOMPLETED	0x0040
 #define IPV6_AF_DELEGATED	0x0080
 #define IPV6_AF_DELEGATEDPFX	0x0100
-#define IPV6_AF_DELEGATEDZERO	0X0200
+#define IPV6_AF_DELEGATEDZERO	0x0200
+#define IPV6_AF_REQUEST		0x0400
 
 struct rt6 {
 	TAILQ_ENTRY(rt6) next;