changeset 2180:3e28ffe1d00b draft

Allow string and binhex types to have lengths. This is useful when you embed two strings in the same option.
author Roy Marples <roy@marples.name>
date Sun, 01 Dec 2013 17:43:49 +0000
parents 498d3807e8ac
children 3517466bff67
files dhcp-common.c dhcp-common.h dhcpcd.conf.5.in if-options.c
diffstat 4 files changed, 43 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/dhcp-common.c	Sat Nov 30 09:43:39 2013 +0000
+++ b/dhcp-common.c	Sun Dec 01 17:43:49 2013 +0000
@@ -288,28 +288,36 @@
 }
 
 static size_t
-dhcp_optlen(int type, size_t dl)
+dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
 {
 	size_t sz;
 
 	if (dl == 0)
 		return 0;
 
-	if (type == 0 || type & (STRING | RFC3442 | RFC5969))
+	if (opt->type == 0 ||
+	    opt->type & (STRING | BINHEX | RFC3442 | RFC5969))
+	{
+		if (opt->len) {
+			if ((size_t)opt->len > dl)
+				return 0;
+			return opt->len;
+		}
 		return dl;
+	}
 
-	if ((type & (ADDRIPV4 | ARRAY)) == (ADDRIPV4 | ARRAY)) {
+	if ((opt->type & (ADDRIPV4 | ARRAY)) == (ADDRIPV4 | ARRAY)) {
 		if (dl < sizeof(uint32_t))
 			return 0;
 		return dl - (dl % sizeof(uint32_t));
 	}
 
 	sz = 0;
-	if (type & (UINT32 | ADDRIPV4))
+	if (opt->type & (UINT32 | ADDRIPV4))
 		sz = sizeof(uint32_t);
-	else if (type & UINT16)
+	else if (opt->type & UINT16)
 		sz = sizeof(uint16_t);
-	else if (type & UINT8)
+	else if (opt->type & UINT8)
 		sz = sizeof(uint8_t);
 	else
 		/* If we don't know the size, assume it's valid */
@@ -503,6 +511,8 @@
 	size_t e;
 	char *v, *val;
 
+	if (opt->len && opt->len < ol)
+		ol = opt->len;
 	len = print_option(NULL, 0, opt->type, ol, od, ifname);
 	if (len < 0)
 		return 0;
@@ -543,7 +553,7 @@
 	n = 0;
 	for (i = 0; i < opt->embopts_len; i++) {
 		eopt = &opt->embopts[i];
-		e = dhcp_optlen(eopt->type, ol);
+		e = dhcp_optlen(eopt, ol);
 		if (e == 0)
 			/* Report error? */
 			return 0;
--- a/dhcp-common.h	Sat Nov 30 09:43:39 2013 +0000
+++ b/dhcp-common.h	Sun Dec 01 17:43:49 2013 +0000
@@ -64,6 +64,7 @@
 struct dhcp_opt {
 	uint16_t option;
 	int type;
+	int len;
 
 	/* This union allows us to define a global static list of
 	 * variable names which we don't free and a list of user defined
--- a/dhcpcd.conf.5.in	Sat Nov 30 09:43:39 2013 +0000
+++ b/dhcpcd.conf.5.in	Sun Dec 01 17:43:49 2013 +0000
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd November 27, 2013
+.Dd December 1, 2013
 .Dt DHCPCD.CONF 5
 .Os
 .Sh NAME
@@ -515,14 +515,16 @@
 .Ar type .
 .El
 .Ss Types to define
-If a length is unspecified by the type, it consumes the rest of the option
-data.
+The type directly affects the length of data consumed inside the option.
+Any remaining data is normally discarded.
+Lengths can be specified for string and binhex types, but this is generally
+with other data embedded afterwards in the same option.
 .Bl -tag -width indent
 .It Ic ipaddress
 An IPv4 address, 4 bytes
 .It Ic ip6address
 An IPv6 address, 16 bytes
-.It Ic string
+.It Ic string Op : Ic length
 A shell escaped string (binary data escaped as octal)
 .It Ic byte
 A byte
@@ -538,7 +540,7 @@
 A fixed value (1) to indicate that the option is present, 0 bytes
 .It Ic domain
 A RFC 3397 encoded string
-.It Ic binhex
+.It Ic binhex Op : Ic length
 Binary data expressed as hexadecimal
 .It Ic embed
 Contains embedded options (implies encap as well)
--- a/if-options.c	Sat Nov 30 09:43:39 2013 +0000
+++ b/if-options.c	Sun Dec 01 17:43:49 2013 +0000
@@ -527,7 +527,7 @@
 static int
 parse_option(struct if_options *ifo, int opt, const char *arg)
 {
-	int i, t;
+	int i, l, t;
 	char *p = NULL, *fp, *np, **nconf;
 	ssize_t s;
 	struct in_addr addr, addr2;
@@ -1246,6 +1246,14 @@
 		fp = strwhite(arg);
 		if (fp)
 			*fp++ = '\0';
+		np = strchr(arg, ':');
+		/* length */
+		if (np) {
+			*np++ = '\0';
+			if ((l = atoint(np)) == -1)
+				return -1;
+		} else
+			l = 0;
 		t = 0;
 		if (strcasecmp(arg, "request") == 0) {
 			t |= REQUEST;
@@ -1312,6 +1320,11 @@
 			syslog(LOG_ERR, "unknown type: %s", arg);
 			return -1;
 		}
+		if (l && !(t & (STRING | BINHEX))) {
+			syslog(LOG_WARNING,
+			    "ignoring length for type `%s'", arg);
+			l = 0;
+		}
 		/* variable */
 		if (fp) {
 			arg = strskipwhite(fp);
@@ -1359,6 +1372,10 @@
 			free_dhcp_opt_embenc(ndop);
 		ndop->option = i; /* could have been 0 */
 		ndop->type = t;
+		if (t & (STRING | BINHEX))
+			ndop->len = l;
+		else
+			ndop->len = 0;
 		ndop->v.dvar = np;
 		/* Save the define for embed and encap options */
 		if (opt == O_DEFINE || opt == O_DEFINE6)