changeset 2168:6133c1c25912 draft

Read the embedded config into global values rather than each time per interface. Add config toggles to build dhcpcd-embedded.conf into dhcpcd or to read it at runtime. The build process will now build .c and .h files based on dhcpcd-embedded.conf and provide defines to reduce the number or re-allocs if it grows (ie has the full DHCP option list).
author Roy Marples <roy@marples.name>
date Fri, 29 Nov 2013 11:15:03 +0000
parents 1a0a80db36d6
children 97267d7f1321
files .gitignore Makefile README configure defs.h dhcp.c dhcp.h dhcp6.c dhcp6.h dhcpcd-embedded.conf dhcpcd-embedded.h.in dhcpcd.c dhcpcd.conf.5.in genembedc genembedh if-options.c if-options.h
diffstat 17 files changed, 435 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/.gitignore	Wed Nov 27 21:35:45 2013 +0000
+++ b/.gitignore	Fri Nov 29 11:15:03 2013 +0000
@@ -9,5 +9,7 @@
 dhcpcd.conf.5
 dhcpcd.core
 dhcpcd.8
+dhcpcd-embedded.c
+dhcpcd-embedded.h
 dhcpcd-run-hooks
 dhcpcd-run-hooks.8
--- a/Makefile	Wed Nov 27 21:35:45 2013 +0000
+++ b/Makefile	Fri Nov 29 11:15:03 2013 +0000
@@ -52,6 +52,8 @@
 DISTPREFIX?=	${PROG}-${VERSION}
 DISTFILE?=	${DISTPREFIX}.tar.bz2
 
+HOST_SH?=	/bin/sh
+
 CLEANFILES+=	*.tar.bz2
 
 .PHONY:		import import-bsd dev
@@ -73,6 +75,16 @@
 .c.o:
 	${CC} ${CFLAGS} ${CPPFLAGS} -c $< -o $@
 
+CLEANFILES+=	dhcpcd-embedded.h dhcpcd-embedded.c
+
+dhcpcd-embedded.h: genembedh dhcpcd-embedded.conf dhcpcd-embedded.h.in
+	${HOST_SH} ${.ALLSRC} $^ > $@
+
+dhcpcd-embedded.c: genembedc dhcpcd-embedded.conf
+	${HOST_SH} ${.ALLSRC} $^ > $@
+
+if-options.c: dhcpcd-embedded.h
+
 .depend: ${SRCS} ${COMPAT_SRCS}
 	${CC} ${CPPFLAGS} -MM ${SRCS} ${COMPAT_SRCS} > .depend
 
@@ -81,6 +93,10 @@
 ${PROG}: ${DEPEND} ${OBJS}
 	${CC} ${LDFLAGS} -o $@ ${OBJS} ${LDADD}
 
+_embeddedinstall: dhcpcd-embedded.conf
+	${INSTALL} -d ${DESTDIR}${SCRIPTSDIR}
+	${INSTALL} -m ${CONFMODE} dhcpcd-embedded.conf ${DESTDIR}${SCRIPTSDIR}
+
 _proginstall: ${PROG}
 	${INSTALL} -d ${DESTDIR}${SBINDIR}
 	${INSTALL} -m ${BINMODE} ${PROG} ${DESTDIR}${SBINDIR}
@@ -89,9 +105,8 @@
 _scriptsinstall: ${SCRIPTS}
 	${INSTALL} -d ${DESTDIR}${SCRIPTSDIR}
 	${INSTALL} -m ${BINMODE} ${SCRIPTS} ${DESTDIR}${SCRIPTSDIR}
-	${INSTALL} -m ${CONFMODE} dhcpcd-embedded.conf ${DESTDIR}${SCRIPTSDIR}
 
-proginstall: _proginstall _scriptsinstall
+proginstall: _proginstall _scriptsinstall ${EMBEDDEDINSTALL}
 	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
 
 _maninstall: ${MAN5} ${MAN8}
@@ -105,8 +120,7 @@
 	test -e ${DESTDIR}${SYSCONFDIR}/dhcpcd.conf || \
 		${INSTALL} -m ${CONFMODE} dhcpcd.conf ${DESTDIR}${SYSCONFDIR}
 
-install: _proginstall _scriptsinstall _maninstall _confinstall
-	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+install: proginstall _maninstall _confinstall
 
 clean:
 	rm -f ${OBJS} ${PROG} ${PROG}.core ${CLEANFILES}
@@ -118,10 +132,10 @@
 dist:
 	git archive --prefix=${DISTPREFIX}/ ${GITREF} | bzip2 > ${DISTFILE}
 
-import:
+import: ${SRCS}
 	rm -rf /tmp/${DISTPREFIX}
 	${INSTALL} -d /tmp/${DISTPREFIX}
-	cp ${SRCS} dhcpcd.conf *.in /tmp/${DISTPREFIX}
+	cp ${SRCS} dhcpcd.conf dhcpcd-embedded.conf *.in /tmp/${DISTPREFIX}
 	cp $$(${CC} ${CPPFLAGS} -MM ${SRCS} | \
 		sed -e 's/^.*\.c //g' -e 's/.*\.c$$//g' -e 's/\\//g' | \
 		tr ' ' '\n' | \
@@ -176,6 +190,7 @@
 		for x in \
 		    /tmp/${DISTPREFIX}/dhcpcd-run-hooks.in \
 		    /tmp/${DISTPREFIX}/dhcpcd.conf \
+		    /tmp/${DISTPREFIX}/dhcpcd-embedded.conf \
 		; do \
 			if test -e "$$x"; then \
 				if test "$$(sed -ne 1p $$x)" = "#!/bin/sh" \
--- a/README	Wed Nov 27 21:35:45 2013 +0000
+++ b/README	Fri Nov 29 11:15:03 2013 +0000
@@ -52,6 +52,16 @@
 can use an interface. As of the time of writing only udev support is included.
 You can disable this with --without-dev, or without-udev
 
+To shrink dhcpcd you can disable IPv4 or IPv6:
+	--disable-inet
+	--disable-inet6
+
+You can also move the embedded extended configuration from the dhcpcd binary
+to an external file (LIBEXECDIR/dhcpcd-embedded.conf)
+	--disable-embedded
+If dhcpcd cannot load this file at runtime, dhcpcd will work but will not be
+able to decode any DHCP/DHCPv6 options present within the file.
+
 To prepare dhcpcd for import into a platform source tree (like NetBSD)
 you can use the make import target to create /tmp/dhcpcd-$version and
 populate it with all the source files and hooks needed.
--- a/configure	Wed Nov 27 21:35:45 2013 +0000
+++ b/configure	Fri Nov 29 11:15:03 2013 +0000
@@ -19,6 +19,7 @@
 STATIC=
 INCLUDEDIR=
 DEVS=
+EMBEDDED=
 
 for x do
 	opt=${x%%=*}
@@ -38,6 +39,8 @@
 	--enable-ipv4) INET=yes;;
 	--disable-ipv6) INET6=no;;
 	--enable-ipv6) INET6=yes;;
+	--disable-embedded) EMBEDDED=no;;
+	--enable-embedded) EMBEDDED=no;;
 	--prefix) PREFIX=$var;;
 	--sysconfdir) SYSCONFDIR=$var;;
 	--bindir|--sbindir) SBINDIR=$var;;
@@ -137,6 +140,8 @@
 done
 
 : ${SED:=sed}
+: ${GREP:=grep}
+: ${WC:=wc}
 
 : ${FORK:=yes}
 : ${SYSCONFDIR:=$PREFIX/etc}
@@ -312,6 +317,23 @@
 EOF
 fi
 
+if [ -z "$EMBEDDED" -o "$EMBEDDED" = yes ]; then
+	echo "dhcpcd-embedded.conf will be embedded in dhcpcd itself"
+	echo "SRCS+=		dhcpcd-embedded.c" >>$CONFIG_MK
+else
+	echo "dhcpcd-embedded.conf will be installed to $LIBEXECDIR"
+	echo "CFLAGS+= -DEMBEDDED_CONFIG=\\\"$LIBEXECDIR/dhcpcd-embedded.conf\\\"" >>$CONFIG_MK
+	echo "EMBEDDEDINSTALL=	_embeddedinstall" >>$CONFIG_MK
+fi
+printf %s "Estimating initial embedded defines ... "
+INITDEFINES=$($GREP "^define " dhcpcd-embedded.conf | $WC -l)
+echo $INITDEFINES
+echo "#define INITDEFINES $INITDEFINES" >>$CONFIG_H
+printf %s "Estimating initial embedded define6s ... "
+INITDEFINE6S=$($GREP "^define6 " dhcpcd-embedded.conf | $WC -l)
+echo $INITDEFINE6S
+echo "#define INITDEFINE6S $INITDEFINE6S" >>$CONFIG_H
+
 if [ -n "$FORK" -a "$FORK" != yes -a "$FORK" != true ]; then
 	echo "There is no fork"
 	echo "CPPFLAGS+=	-DTHERE_IS_NO_FORK" >>$CONFIG_MK
@@ -770,7 +792,7 @@
 	printf "Checking for ypind ... "
 	YPBIND=$(_which ypbind)
 	if [ -n "$YPBIND" ]; then
-		if strings "$YPBIND" | grep -q yp.conf; then
+		if strings "$YPBIND" | $GREP -q yp.conf; then
 			YPHOOK="50-yp.conf"
 		else
 			YPHOOK="50-ypbind"
--- a/defs.h	Wed Nov 27 21:35:45 2013 +0000
+++ b/defs.h	Fri Nov 29 11:15:03 2013 +0000
@@ -33,9 +33,6 @@
 #ifndef CONFIG
 # define CONFIG			SYSCONFDIR "/" PACKAGE ".conf"
 #endif
-#ifndef EMBEDDED_CONFIG
-# define EMBEDDED_CONFIG	LIBEXECDIR "/" PACKAGE "-embedded.conf"
-#endif
 #ifndef SCRIPT
 # define SCRIPT			LIBEXECDIR "/" PACKAGE "-run-hooks"
 #endif
--- a/dhcp.c	Wed Nov 27 21:35:45 2013 +0000
+++ b/dhcp.c	Fri Nov 29 11:15:03 2013 +0000
@@ -222,6 +222,10 @@
 	struct udphdr udp;
 	struct dhcp_message dhcp;
 };
+
+struct dhcp_opt *dhcp_eopts = NULL;
+size_t dhcp_eopts_len = 0;
+
 static const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
 
 static int dhcp_open(struct interface *);
@@ -1126,7 +1130,7 @@
 }
 
 static const struct dhcp_opt *
-dhcp_getoverride(const struct if_options *ifo, uint16_t o)
+dhcp_getoverride(const struct if_options *ifo, uint16_t o, int e)
 {
 	size_t i;
 	const struct dhcp_opt *opt;
@@ -1138,10 +1142,18 @@
 		if (opt->option == o)
 			return opt;
 	}
+	if (e) {
+		for (i = 0, opt = dhcp_eopts;
+		    i < dhcp_eopts_len;
+		    i++, opt++)
+		{
+			if (opt->option == o)
+				return opt;
+		}
+	}
 	return NULL;
 }
 
-
 static const uint8_t *
 dhcp_getoption(int *len, int option, const uint8_t *od, int ol)
 {
@@ -1188,7 +1200,7 @@
 				continue;
 			if (has_option_mask(ifo->nomask, opt->option))
 				continue;
-			if (dhcp_getoverride(ifo, opt->option))
+			if (dhcp_getoverride(ifo, opt->option, 1))
 				continue;
 			p = get_option(dhcp, opt->option, &pl, NULL);
 			if (!p)
@@ -1202,10 +1214,26 @@
 			e++;
 		if (*dhcp->servername && !(overl & 2))
 			e++;
+		for (oi = 0, opt = dhcp_eopts;
+		    oi < dhcp_eopts_len;
+		    oi++, opt++)
+		{
+			if (has_option_mask(ifo->nomask, opt->option))
+				continue;
+			if (dhcp_getoverride(ifo, opt->option, 0))
+				continue;
+			p = get_option(dhcp, opt->option, &pl, NULL);
+			if (!p)
+				continue;
+			e += dhcp_envoption(NULL, prefix, "", ifp->name,
+			    opt, dhcp_getoption, p, pl);
+		}
 		for (oi = 0, opt = ifo->dhcp_override;
 		    oi < ifo->dhcp_override_len;
 		    oi++, opt++)
 		{
+			if (has_option_mask(ifo->nomask, opt->option))
+				continue;
 			p = get_option(dhcp, opt->option, &pl, NULL);
 			if (!p)
 				continue;
@@ -1245,7 +1273,7 @@
 			continue;
 		if (has_option_mask(ifo->nomask, opt->option))
 			continue;
-		if (dhcp_getoverride(ifo, opt->option))
+		if (dhcp_getoverride(ifo, opt->option, 1))
 			continue;
 		p = get_option(dhcp, opt->option, &pl, NULL);
 		if (!p)
@@ -1260,6 +1288,19 @@
 		    opt, dhcp_getoption, p, pl);
 	}
 
+	for (oi = 0, opt = dhcp_eopts;
+	    oi < dhcp_eopts_len;
+	    oi++, opt++)
+	{
+		if (has_option_mask(ifo->nomask, opt->option))
+			continue;
+		if (dhcp_getoverride(ifo, opt->option, 0))
+			continue;
+		if ((p = get_option(dhcp, opt->option, &pl, NULL)))
+			ep += dhcp_envoption(ep, prefix, "", ifp->name,
+			    opt, dhcp_getoption, p, pl);
+	}
+
 	for (oi = 0, opt = ifo->dhcp_override;
 	    oi < ifo->dhcp_override_len;
 	    oi++, opt++)
--- a/dhcp.h	Wed Nov 27 21:35:45 2013 +0000
+++ b/dhcp.h	Fri Nov 29 11:15:03 2013 +0000
@@ -240,6 +240,9 @@
 #ifdef INET
 extern const struct dhcp_opt dhcp_opts[];
 
+extern struct dhcp_opt *dhcp_eopts;
+extern size_t dhcp_eopts_len;
+
 char *decode_rfc3361(int dl, const uint8_t *data);
 ssize_t decode_rfc3442(char *out, ssize_t len, int pl, const uint8_t *p);
 ssize_t decode_rfc5969(char *out, ssize_t len, int pl, const uint8_t *p);
--- a/dhcp6.c	Wed Nov 27 21:35:45 2013 +0000
+++ b/dhcp6.c	Fri Nov 29 11:15:03 2013 +0000
@@ -129,6 +129,9 @@
 };
 #undef O
 
+struct dhcp_opt *dhcp6_eopts = NULL;
+size_t dhcp6_eopts_len = 0;
+
 struct dhcp_compat {
 	uint8_t dhcp_opt;
 	uint16_t dhcp6_opt;
@@ -2571,7 +2574,7 @@
 }
 
 static const struct dhcp_opt *
-dhcp6_getoverride(const struct if_options *ifo, uint16_t o)
+dhcp6_getoverride(const struct if_options *ifo, uint16_t o, int e)
 {
 	size_t i;
 	const struct dhcp_opt *opt;
@@ -2583,6 +2586,15 @@
 		if (opt->option == o)
 			return opt;
 	}
+	if (e != 0) {
+		for (i = 0, opt = dhcp6_eopts;
+		    i < dhcp6_eopts_len;
+		    i++, opt++)
+		{
+			if (opt->option == o)
+				return opt;
+		}
+	}
 	return NULL;
 }
 
@@ -2609,7 +2621,7 @@
 			continue;
 		if (has_option_mask(ifo->nomask6, opt->option))
 			continue;
-		if (dhcp6_getoverride(ifo, opt->option))
+		if (dhcp6_getoverride(ifo, opt->option, 1))
 			continue;
 		o = dhcp6_getmoption(opt->option, m, mlen);
 		if (o == NULL)
@@ -2672,6 +2684,24 @@
 		}
 	}
 
+	for (oi = 0, opt = dhcp6_eopts;
+	    oi < dhcp6_eopts_len;
+	    oi++, opt++)
+	{
+		if (has_option_mask(ifo->nomask, opt->option))
+			continue;
+		if (dhcp6_getoverride(ifo, opt->option, 0))
+			continue;
+
+		o = dhcp6_getmoption(opt->option, m, mlen);
+		if (o == NULL)
+			continue;
+		ol = ntohs(o->len);
+		od = D6_COPTION_DATA(o);
+		n += dhcp_envoption(env == NULL ? NULL : &env[n],
+		    prefix, "_dhcp6", ifp->name, opt, dhcp6_getoption, od, ol);
+	}
+
 	for (oi = 0, opt = ifo->dhcp6_override;
 	    oi < ifo->dhcp6_override_len;
 	    oi++, opt++)
--- a/dhcp6.h	Wed Nov 27 21:35:45 2013 +0000
+++ b/dhcp6.h	Fri Nov 29 11:15:03 2013 +0000
@@ -222,6 +222,9 @@
     ((const uint8_t *)(o) + sizeof(struct dhcp6_option))
 
 #ifdef INET6
+extern struct dhcp_opt *dhcp6_eopts;
+extern size_t dhcp6_eopts_len;
+
 void dhcp6_printoptions(void);
 int dhcp6_addrexists(const struct ipv6_addr *);
 int dhcp6_find_delegates(struct interface *);
--- a/dhcpcd-embedded.conf	Wed Nov 27 21:35:45 2013 +0000
+++ b/dhcpcd-embedded.conf	Fri Nov 29 11:15:03 2013 +0000
@@ -16,4 +16,4 @@
 define6 56 encap
 encap 1 ip6address ntp_server_addr
 encap 2 ip6address ntp_mcast_addr
-encap 3 ip6address ntp_fqdn
+encap 3 ip6address ntp_server_fqdn
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dhcpcd-embedded.h.in	Fri Nov 29 11:15:03 2013 +0000
@@ -0,0 +1,31 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define INITDEFINES	@INITDEFINES@
+#define INITDEFINE6S	@INITDEFINE6S@
+
+extern const char *dhcpcd_embedded_conf[];
--- a/dhcpcd.c	Wed Nov 27 21:35:45 2013 +0000
+++ b/dhcpcd.c	Fri Nov 29 11:15:03 2013 +0000
@@ -136,11 +136,35 @@
 }
 
 static void
+free_globals(void)
+{
+	int i;
+	size_t n;
+
+	for (i = 0; i < ifac; i++)
+		free(ifav[i]);
+	free(ifav);
+	for (i = 0; i < ifdc; i++)
+		free(ifdv[i]);
+	free(ifdv);
+
+#ifdef INET
+	for (n = 0; n < dhcp_eopts_len; n++)
+		free_dhcp_opt_embenc(&dhcp_eopts[n]);
+	free(dhcp_eopts);
+#endif
+#ifdef INET6
+	for (n = 0; n < dhcp6_eopts_len; n++)
+		free_dhcp_opt_embenc(&dhcp6_eopts[n]);
+	free(dhcp6_eopts);
+#endif
+}
+
+static void
 cleanup(void)
 {
 #ifdef DEBUG_MEMORY
 	struct interface *ifp;
-	int i;
 
 	free(duid);
 	free_options(if_options);
@@ -153,12 +177,7 @@
 		free(ifaces);
 	}
 
-	for (i = 0; i < ifac; i++)
-		free(ifav[i]);
-	free(ifav);
-	for (i = 0; i < ifdc; i++)
-		free(ifdv[i]);
-	free(ifdv);
+	free_globals();
 #endif
 
 	if (!(options & DHCPCD_FORKED))
@@ -807,21 +826,16 @@
 {
 	siginfo_t *siginfo = arg;
 	struct if_options *ifo;
-	int i;
 
 	syslog(LOG_INFO, "received SIGALRM from PID %d, rebinding",
 	    (int)siginfo->si_pid);
 
-	for (i = 0; i < ifac; i++)
-		free(ifav[i]);
-	free(ifav);
+	free_globals();
 	ifav = NULL;
 	ifac = 0;
-	for (i = 0; i < ifdc; i++)
-		free(ifdv[i]);
-	free(ifdv);
 	ifdc = 0;
 	ifdv = NULL;
+
 	ifo = read_config(cffile, NULL, NULL, NULL);
 	add_options(ifo, margc, margv);
 	/* We need to preserve these two options. */
--- a/dhcpcd.conf.5.in	Wed Nov 27 21:35:45 2013 +0000
+++ b/dhcpcd.conf.5.in	Fri Nov 29 11:15:03 2013 +0000
@@ -534,6 +534,8 @@
 A signed 32bit integer, 4 bytes
 .It Ic uint32
 An unsigned 32bit integer, 4 bytes
+.It Ic flag 
+A fixed value (1) to indicate that the option is present, 0 bytes
 .It Ic domain
 A RFC 3397 encoded string
 .It Ic binhex
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/genembedc	Fri Nov 29 11:15:03 2013 +0000
@@ -0,0 +1,47 @@
+#!/bin/sh
+set -e
+
+: ${TOOL_SED:=sed}
+CONF=${1:-dhcpcd-embedded.conf}
+
+cat <<EOF
+/*
+ * DO NOT EDIT
+ * Automatically generated from dhcpcd-embedded.conf
+ * Ths allows us to simply generate DHCP structure without any C programming
+ */
+
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+
+const char *dhcpcd_embedded_conf[] = {
+EOF
+
+$TOOL_SED -e 's/#.*$//' -e '/^$/d' -e 's/^/"/g' -e 's/$/\",/g' $CONF
+printf "%s\n%s\n" "NULL" "};"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/genembedh	Fri Nov 29 11:15:03 2013 +0000
@@ -0,0 +1,15 @@
+#!/bin/sh
+set -e
+
+: ${TOOL_SED:=sed}
+: ${TOOL_GREP:=grep}
+: ${TOOL_WC:=wc}
+CONF=${1:-dhcpcd-embedded.conf}
+H=${2:-dhcpcd-embedded.h.in}
+
+INITDEFINES=$($TOOL_GREP "^define " $CONF | $TOOL_WC -l)
+INITDEFINE6S=$($TOOL_GREP "^define6 " $CONF | $TOOL_WC -l)
+$TOOL_SED \
+	-e "s/@INITDEFINES@/$INITDEFINES/" \
+	-e "s/@INITDEFINE6S@/$INITDEFINE6S/" \
+	$H
--- a/if-options.c	Wed Nov 27 21:35:45 2013 +0000
+++ b/if-options.c	Fri Nov 29 11:15:03 2013 +0000
@@ -46,6 +46,7 @@
 #include "common.h"
 #include "dhcp.h"
 #include "dhcp6.h"
+#include "dhcpcd-embedded.h"
 #include "if-options.h"
 #include "ipv4.h"
 #include "platform.h"
@@ -479,7 +480,7 @@
 /* Pointer to last defined option */
 static struct dhcp_opt *ldop;
 
-static void
+void
 free_dhcp_opt_embenc(struct dhcp_opt *opt)
 {
 	size_t i;
@@ -499,6 +500,30 @@
 	opt->encopts = NULL;
 }
 
+static char *
+strwhite(const char *s)
+{
+
+	while (*s != ' ' && *s != '\t') {
+		if (*s == '\0')
+			return NULL;
+		s++;
+	}
+	return UNCONST(s);
+}
+
+static char *
+strskipwhite(const char *s)
+{
+
+	while (*s == ' ' || *s == '\t') {
+		if (*s == '\0')
+			return NULL;
+		s++;
+	}
+	return UNCONST(s);
+}
+
 static int
 parse_option(struct if_options *ifo, int opt, const char *arg)
 {
@@ -852,14 +877,13 @@
 		    strncmp(arg, "classless_static_routes=", strlen("classless_static_routes=")) == 0 ||
 		    strncmp(arg, "ms_classless_static_routes=", strlen("ms_classless_static_routes=")) == 0)
 		{
-			fp = np = strchr(p, ' ');
+			fp = np = strwhite(p);
 			if (np == NULL) {
 				syslog(LOG_ERR, "all routes need a gateway");
 				return -1;
 			}
 			*np++ = '\0';
-			while (*np == ' ')
-				np++;
+			np = strskipwhite(np);
 			if (ifo->routes == NULL) {
 				ifo->routes = malloc(sizeof(*ifo->routes));
 				if (ifo->routes == NULL) {
@@ -1059,7 +1083,7 @@
 		ifo->ia_type = i;
 		if (arg == NULL)
 			break;
-		fp = strchr(arg, ' ');
+		fp = strwhite(arg);
 		if (fp)
 			*fp++ = '\0';
 		if (parse_iaid(iaid, arg, sizeof(iaid)) == -1)
@@ -1094,9 +1118,11 @@
 		if (ifo->ia_type != D6_OPTION_IA_PD)
 			break;
 		for (p = fp; p; p = fp) {
-			fp = strchr(p, ' ');
-			if (fp)
+			fp = strwhite(p);
+			if (fp) {
 				*fp++ = '\0';
+				fp = strskipwhite(fp);
+			}
 			sla = realloc(ia->sla,
 			    sizeof(*ia->sla) * (ia->sla_len + 1));
 			if (sla == NULL) {
@@ -1206,7 +1232,7 @@
 		if (opt == O_EMBED) /* Embedded options don't have codes */
 			i = 0;
 		else {
-			fp = strchr(arg, ' ');
+			fp = strwhite(arg);
 			if (!fp) {
 				syslog(LOG_ERR, "invalid syntax: %s", arg);
 				return -1;
@@ -1214,44 +1240,80 @@
 			*fp++ = '\0';
 			if ((i = atoint(arg)) == -1)
 				return -1;
-			arg = fp;
+			arg = strskipwhite(fp);
 		}
 		/* type */
-		fp = strchr(arg, ' ');
-		if (fp)
+		fp = strwhite(arg);
+		if (fp) 
+			*fp++ = '\0';
+		t = 0;
+		if (strcasecmp(arg, "request") == 0) {
+			t |= REQUEST;
+			arg = strskipwhite(fp);
+			fp = strwhite(arg);
+			if (fp == NULL) {
+				syslog(LOG_ERR, "incomplete request type");
+				return -1;
+			}
 			*fp++ = '\0';
+		} else if (strcasecmp(arg, "norequest") == 0) {
+			t |= NOREQ;
+			arg = strskipwhite(fp);
+			fp = strwhite(arg);
+			if (fp == NULL) {
+				syslog(LOG_ERR, "incomplete request type");
+				return -1;
+			}
+			*fp++ = '\0';
+		}
+		if (strcasecmp(arg, "array") == 0) {
+			t |= ARRAY;
+			arg = strskipwhite(fp);
+			fp = strwhite(arg);
+			if (fp == NULL) {
+				syslog(LOG_ERR, "incomplete array type");
+				return -1;
+			}
+			*fp++ = '\0';
+		}
 		if (strcasecmp(arg, "ipaddress") == 0)
-			t = ADDRIPV4;
+			t |= ADDRIPV4;
 		else if (strcasecmp(arg, "ip6address") == 0)
-			t = ADDRIPV6;
+			t |= ADDRIPV6;
 		else if (strcasecmp(arg, "string") == 0)
-			t = STRING;
+			t |= STRING;
 		else if (strcasecmp(arg, "byte") == 0)
-			t = UINT8;
+			t |= UINT8;
 		else if (strcasecmp(arg, "uint16") == 0)
-			t = UINT16;
+			t |= UINT16;
 		else if (strcasecmp(arg, "int16") == 0)
-			t = SINT16;
+			t |= SINT16;
 		else if (strcasecmp(arg, "uint32") == 0)
-			t = UINT32;
+			t |= UINT32;
 		else if (strcasecmp(arg, "int32") == 0)
-			t = SINT32;
+			t |= SINT32;
+		else if (strcasecmp(arg, "flag") == 0)
+			t |= FLAG;
 		else if (strcasecmp(arg, "domain") == 0)
-			t = STRING | RFC3397;
+			t |= STRING | RFC3397;
 		else if (strcasecmp(arg, "binhex") == 0)
-			t = BINHEX;
+			t |= BINHEX;
 		else if (strcasecmp(arg, "embed") == 0)
 			t = EMBED;
 		else if (strcasecmp(arg, "encap") == 0)
 			t = ENCAP;
+		else if (strcasecmp(arg, "rfc3361") ==0)
+			t = STRING | RFC3361;
+		else if (strcasecmp(arg, "rfc5969") == 0)
+			t = RFC5969;
 		else {
 			syslog(LOG_ERR, "unknown type: %s", arg);
 			return -1;
 		}
 		/* variable */
 		if (fp) {
-			arg = fp;
-			fp = strchr(arg, ' ');
+			arg = strskipwhite(fp);
+			fp = strwhite(arg);
 			if (fp)
 				*fp++ = '\0';
 			np = strdup(arg);
@@ -1269,15 +1331,17 @@
 			np = NULL;
 		}
 		if (opt == O_EMBED)
-			dl = 0;
+			dl = *dop_len;
 		else {
 			for (dl = 0; dl < *dop_len; dl++) {
 				ndop = &(*dop)[dl];
-				if (ndop->option == i)
+				/* type 0 seems freshly malloced struct
+				 * for us to use */
+				if (ndop->option == i || ndop->type == 0)
 					break;
 			}
 		}
-		if (dl <= *dop_len) {
+		if (dl >= *dop_len) {
 			if ((ndop = realloc(*dop,
 			    sizeof(**dop) * ((*dop_len) + 1))) == NULL) {
 				syslog(LOG_ERR, "%s: %m", __func__);
@@ -1285,13 +1349,13 @@
 			}
 			*dop = ndop;
 			ndop = &(*dop)[(*dop_len)++];
-			ndop->option = i;
 			ndop->embopts = NULL;
 			ndop->embopts_len = 0;
 			ndop->encopts = NULL;
 			ndop->encopts_len = 0;
 		} else
 			free_dhcp_opt_embenc(ndop);
+		ndop->option = i; /* could have been 0 */
 		ndop->type = t;
 		ndop->v.dvar = np;
 		/* Save the define for embed and encap options */
@@ -1352,6 +1416,10 @@
 	FILE *f;
 	char *line, *option, *p;
 	int skip = 0, have_profile = 0;
+#ifndef EMBEDDED_CONFIG
+	const char **e;
+	size_t linel, ol;
+#endif
 
 	/* Seed our default options */
 	ifo = calloc(1, sizeof(*ifo));
@@ -1380,12 +1448,53 @@
 	memcpy(ifo->vendorclassid + 1, vendor, ifo->vendorclassid[0]);
 
 	/* Parse our embedded options file */
-	f = fopen(EMBEDDED_CONFIG, "r");
-	if (f == NULL) {
-		if (errno != ENOENT)
-			syslog(LOG_ERR, "fopen `%s': %m", file);
-	} else {
-		while ((line = get_line(f))) {
+	if (ifname == NULL) {
+		/* Space for initial estimates */
+#if defined(INET) && defined(INITDEFINES)
+		ifo->dhcp_override =
+		    calloc(INITDEFINES, sizeof(*ifo->dhcp_override));
+		if (ifo->dhcp_override == NULL)
+			syslog(LOG_ERR, "%s: %m", __func__);
+		else
+			ifo->dhcp_override_len = INITDEFINES;
+#endif
+
+#if defined(INET6) && defined(INITDEFINE6S)
+		ifo->dhcp6_override =
+		    calloc(INITDEFINE6S, sizeof(*ifo->dhcp6_override));
+		if (ifo->dhcp6_override == NULL)
+			syslog(LOG_ERR, "%s: %m", __func__);
+		else
+			ifo->dhcp6_override_len = INITDEFINES;
+#endif
+
+		/* Now load our embedded config */
+#ifdef EMBEDDED_CONFIG
+		f = fopen(EMBEDDED_CONFIG, "r");
+		if (f == NULL)
+			syslog(LOG_ERR, "fopen `%s': %m", EMBEDDED_CONFIG);
+
+		while (f && (line = get_line(f))) {
+#else
+		linel = 80;
+		line = malloc(linel);
+		if (line == NULL) {
+			syslog(LOG_ERR, "%s: %m", __func__);
+			return NULL;
+		}
+		for (e = dhcpcd_embedded_conf; *e; e++) {
+			ol = strlen(*e) + 1;
+			if (ol > linel) {
+				free(line);
+				linel = ol;
+				line = malloc(linel);
+				if (line == NULL) {
+					syslog(LOG_ERR, "%s: %m", __func__);
+					return NULL;
+				}
+			}
+			memcpy(line, *e, ol);
+#endif
 			option = strsep(&line, " \t");
 			/* Trim trailing whitespace */
 			if (line && *line) {
@@ -1396,8 +1505,36 @@
 					*p-- = '\0';
 			}
 			parse_config_line(ifo, option, line);
+
 		}
-		fclose(f);
+
+#ifdef EMBEDDED_CONFIG
+		if (f)
+			fclose(f);
+#else
+		free(line);
+#endif
+#ifdef INET
+		dhcp_eopts = ifo->dhcp_override;
+		dhcp_eopts_len = ifo->dhcp_override_len;
+#else
+		for (i = 0; i < ifo->dhcp_override_len; i++)
+			free_dhcp_opt_embenc(&ifo->dhcp_override[i]);
+		free(ifo->dhcp_override);
+#endif
+		ifo->dhcp_override = NULL;
+		ifo->dhcp_override_len = 0;
+
+#ifdef INET6
+		dhcp6_eopts = ifo->dhcp6_override;
+		dhcp6_eopts_len = ifo->dhcp6_override_len;
+#else
+		for (i = 0; i < ifo->dhcp6_override_len; i++)
+			free_dhcp_opt_embenc(&ifo->dhcp6_override[i]);
+		free(ifo->dhcp6_override);
+#endif
+		ifo->dhcp6_override = NULL;
+		ifo->dhcp6_override_len = 0;
 	}
 
 	/* Parse our options file */
--- a/if-options.h	Wed Nov 27 21:35:45 2013 +0000
+++ b/if-options.h	Fri Nov 29 11:15:03 2013 +0000
@@ -173,6 +173,7 @@
 struct if_options *read_config(const char *,
     const char *, const char *, const char *);
 int add_options(struct if_options *, int, char **);
+void free_dhcp_opt_embenc(struct dhcp_opt *);
 void free_options(struct if_options *);
 
 #endif