1d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/*
2d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * dhcpcd - DHCP client daemon
3d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
4d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * All rights reserved
5d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
6d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Redistribution and use in source and binary forms, with or without
7d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * modification, are permitted provided that the following conditions
8d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * are met:
9d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 1. Redistributions of source code must retain the above copyright
10d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    notice, this list of conditions and the following disclaimer.
11d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 2. Redistributions in binary form must reproduce the above copyright
12d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    notice, this list of conditions and the following disclaimer in the
13d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    documentation and/or other materials provided with the distribution.
14d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *
15d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * SUCH DAMAGE.
26d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan */
27d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
28d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/utsname.h>
29d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
30d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <ctype.h>
31d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <errno.h>
32d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <fcntl.h>
33d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <inttypes.h>
34d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stdlib.h>
35d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <string.h>
36d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <unistd.h>
37d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
38d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "config.h"
39d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
40d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "common.h"
41d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dhcp-common.h"
42d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dhcp.h"
43d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "if.h"
44d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "ipv6.h"
45d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
46d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
47d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_print_option_encoding(const struct dhcp_opt *opt, int cols)
48d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
49d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
50d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (cols < 40) {
51d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		putchar(' ');
52d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		cols++;
53d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
54d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	putchar('\t');
55d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (opt->type & EMBED)
56d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" embed");
57d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (opt->type & ENCAP)
58d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" encap");
59d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (opt->type & INDEX)
60d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" index");
61d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (opt->type & ARRAY)
62d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" array");
63d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (opt->type & UINT8)
64d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" byte");
65d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (opt->type & UINT16)
66d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" uint16");
67d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (opt->type & SINT16)
68d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" sint16");
69d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (opt->type & UINT32)
70d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" uint32");
71d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (opt->type & SINT32)
72d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" sint32");
73d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (opt->type & ADDRIPV4)
74d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" ipaddress");
75d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (opt->type & ADDRIPV6)
76d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" ip6address");
77d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (opt->type & FLAG)
78d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" flag");
79d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (opt->type & RFC3397)
80d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" domain");
81d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (opt->type & DOMAIN)
82d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" dname");
83d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (opt->type & ASCII)
84d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" ascii");
85d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (opt->type & RAW)
86d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" raw");
87d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (opt->type & BINHEX)
88d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" binhex");
89d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (opt->type & STRING)
90d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" string");
91d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (opt->type & RFC3361)
92d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" rfc3361");
93d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (opt->type & RFC3442)
94d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" rfc3442");
95d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (opt->type & RFC5969)
96d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" rfc5969");
97d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (opt->type & REQUEST)
98d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" request");
99d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (opt->type & NOREQ)
100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf(" norequest");
101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	putchar('\n');
102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct dhcp_opt *
105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvivso_find(uint32_t iana_en, const void *arg)
106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct interface *ifp;
108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t i;
109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_opt *opt;
110d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifp = arg;
112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0, opt = ifp->options->vivso_override;
113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    i < ifp->options->vivso_override_len;
114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    i++, opt++)
115d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (opt->option == iana_en)
116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return opt;
117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0, opt = ifp->ctx->vivso;
118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    i < ifp->ctx->vivso_len;
119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    i++, opt++)
120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (opt->option == iana_en)
121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return opt;
122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return NULL;
123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t
126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_vendor(char *str, size_t len)
127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct utsname utn;
129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *p;
130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int l;
131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
132d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (uname(&utn) != 0)
133d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return (ssize_t)snprintf(str, len, "%s-%s",
134d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    PACKAGE, VERSION);
135d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	p = str;
136d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	l = snprintf(p, len,
137d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    "%s-%s:%s-%s:%s", PACKAGE, VERSION,
138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    utn.sysname, utn.release, utn.machine);
139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (l == -1 || (size_t)(l + 1) > len)
140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	p += l;
142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len -= (size_t)l;
143d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	l = if_machinearch(p, len);
144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (l == -1 || (size_t)(l + 1) > len)
145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	p += l;
147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return p - str;
148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanmake_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct dhcp_opt *odopts, size_t odopts_len,
153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    uint8_t *mask, const char *opts, int add)
154d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *token, *o, *p;
156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct dhcp_opt *opt;
157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int match, e;
158d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	unsigned int n;
159d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t i;
160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (opts == NULL)
162d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
163d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	o = p = strdup(opts);
164d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while ((token = strsep(&p, ", "))) {
165d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (*token == '\0')
166d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
167d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		match = 0;
168d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		for (i = 0, opt = odopts; i < odopts_len; i++, opt++) {
169d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (strcmp(opt->var, token) == 0)
170d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				match = 1;
171d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			else {
172d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				n = (unsigned int)strtou(token, NULL, 0,
173d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    0, UINT_MAX, &e);
174d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (e == 0 && opt->option == n)
175d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					match = 1;
176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (match)
178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (match == 0) {
181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			for (i = 0, opt = dopts; i < dopts_len; i++, opt++) {
182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (strcmp(opt->var, token) == 0)
183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				        match = 1;
184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				else {
185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					n = (unsigned int)strtou(token, NULL, 0,
186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    0, UINT_MAX, &e);
187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					if (e == 0 && opt->option == n)
188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan						match = 1;
189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
190d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (match)
191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					break;
192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (!match || !opt->option) {
195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			free(o);
196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = ENOENT;
197d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
198d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (add == 2 && !(opt->type & ADDRIPV4)) {
200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			free(o);
201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = EINVAL;
202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
204d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (add == 1 || add == 2)
205d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			add_option_mask(mask, opt->option);
206d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
207d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			del_option_mask(mask, opt->option);
208d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
209d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(o);
210d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
211d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
212d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
213d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansize_t
214d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanencode_rfc1035(const char *src, uint8_t *dst)
215d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
216d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t *p;
217d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t *lp;
218d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
219d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t has_dot;
220d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
221d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (src == NULL || *src == '\0')
222d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
223d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
224d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dst) {
225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p = dst;
226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lp = p++;
227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Silence bogus GCC warnings */
229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p = lp = NULL;
231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = 1;
233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	has_dot = 0;
234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (; *src; src++) {
235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (*src == '\0')
236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (*src == '.') {
238d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* Skip the trailing . */
239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (src[1] == '\0')
240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			has_dot = 1;
242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (dst) {
243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				*lp = (uint8_t)(p - lp - 1);
244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (*lp == '\0')
245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					return len;
246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				lp = p++;
247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (dst)
249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = (uint8_t)*src;
250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		len++;
251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dst) {
254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*lp = (uint8_t)(p - lp - 1);
255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (has_dot)
256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = '\0';
257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (has_dot)
260d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		len++;
261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return len;
263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* Decode an RFC3397 DNS search order option into a space
266d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * separated string. Returns length of string (including
267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * terminating zero) or zero on error. out may be NULL
268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * to just determine output length. */
269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t
270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandecode_rfc3397(char *out, size_t len, const uint8_t *p, size_t pl)
271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const char *start;
273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t start_len, l, count;
274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *r, *q = p, *e;
275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int hops;
276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t ltype;
277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	count = 0;
279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	start = out;
280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	start_len = len;
281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	q = p;
282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e = p + pl;
283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (q < e) {
284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		r = NULL;
285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		hops = 0;
286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Check we are inside our length again in-case
287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * the name isn't fully qualified (ie, not terminated) */
288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		while (q < e && (l = (size_t)*q++)) {
289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ltype = l & 0xc0;
290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (ltype == 0x80 || ltype == 0x40)
291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				return -1;
292d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			else if (ltype == 0xc0) { /* pointer */
293d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (q == e) {
294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					errno = ERANGE;
295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					return -1;
296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				l = (l & 0x3f) << 8;
298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				l |= *q++;
299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				/* save source of first jump. */
300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (!r)
301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					r = q;
302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				hops++;
303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (hops > 255) {
304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					errno = ERANGE;
305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					return -1;
306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				q = p + l;
308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (q >= e) {
309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					errno = ERANGE;
310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					return -1;
311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			} else {
313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				/* straightforward name segment, add with '.' */
314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (q + l > e) {
315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					errno = ERANGE;
316d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					return -1;
317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				count += l + 1;
319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (out) {
320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					if (l + 1 > len) {
321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan						errno = ENOBUFS;
322d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan						return -1;
323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					}
324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					memcpy(out, q, l);
325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					out += l;
326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					*out++ = '.';
327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					len -= l;
328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					len--;
329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				q += l;
331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* change last dot to space */
334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (out && out != start)
335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*(out - 1) = ' ';
336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (r)
337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			q = r;
338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
340d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* change last space to zero terminator */
341d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (out) {
342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (out != start)
343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*(out - 1) = '\0';
344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else if (start_len > 0)
345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*out = '\0';
346d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
347d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (count)
349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Don't count the trailing NUL */
350d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		count--;
351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return (ssize_t)count;
352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* Check for a valid domain name as per RFC1123 with the exception of
355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * allowing - and _ (but not at start or end) as they seem to be widely used. */
356d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvalid_domainname(char *lbl, int type)
358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *slbl, *lst;
360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	unsigned char c;
361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int start, len, errset;
362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (lbl == NULL || *lbl == '\0') {
364d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EINVAL;
365d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
366d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	slbl = lbl;
369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	lst = NULL;
370d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	start = 1;
371d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = errset = 0;
372d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (;;) {
373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		c = (unsigned char)*lbl++;
374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (c == '\0')
375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return 1;
376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (c == ' ') {
377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (lbl - 1 == slbl) /* No space at start */
378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (!(type & ARRAY))
380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* Skip to the next label */
382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (!start) {
383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				start = 1;
384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				lst = lbl - 1;
385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (len)
387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				len = 0;
388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (c == '.') {
391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (*lbl == '.')
392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			len = 0;
394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (((c == '-' || c == '_') &&
397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    !start && *lbl != ' ' && *lbl != '\0') ||
398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    isalnum(c))
399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (++len > 63) {
401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				errno = ERANGE;
402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				errset = 1;
403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else
406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (start)
408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			start = 0;
409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!errset)
412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EINVAL;
413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (lst) {
414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* At least one valid domain, return it */
415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*lst = '\0';
416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 1;
417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/*
422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Prints a chunk of data to a string.
423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * PS_SHELL goes as it is these days, it's upto the target to validate it.
424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * PS_SAFE has all non ascii and non printables changes to escaped octal.
425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan */
426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const char hexchrs[] = "0123456789abcdef";
427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t
428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanprint_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *odst;
431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t c;
432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *e;
433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t bytes;
434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	odst = dst;
436d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	bytes = 0;
437d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e = data + dl;
438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (data < e) {
440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		c = *data++;
441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type & BINHEX) {
442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (dst) {
443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (len  == 0 || len == 1) {
444d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					errno = ENOSPC;
445d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					return -1;
446d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
447d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				*dst++ = hexchrs[(c & 0xF0) >> 4];
448d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				*dst++ = hexchrs[(c & 0x0F)];
449d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				len -= 2;
450d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
451d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			bytes += 2;
452d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
453d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
454d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type & ASCII && (!isascii(c))) {
455d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = EINVAL;
456d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
457d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
458d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (!(type & (ASCII | RAW | ESCSTRING | ESCFILE)) /* plain */ &&
459d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (!isascii(c) && !isprint(c)))
460d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
461d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = EINVAL;
462d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
463d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
464d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((type & (ESCSTRING | ESCFILE) &&
465d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (c == '\\' || !isascii(c) || !isprint(c))) ||
466d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (type & ESCFILE && (c == '/' || c == ' ')))
467d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
468d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = EINVAL;
469d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (c == '\\') {
470d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (dst) {
471d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					if (len  == 0 || len == 1) {
472d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan						errno = ENOSPC;
473d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan						return -1;
474d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					}
475d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					*dst++ = '\\'; *dst++ = '\\';
476d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					len -= 2;
477d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
478d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				bytes += 2;
479d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
480d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
481d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (dst) {
482d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (len < 5) {
483d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					errno = ENOSPC;
484d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					return -1;
485d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
486d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				*dst++ = '\\';
487d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		                *dst++ = (char)(((c >> 6) & 03) + '0');
488d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		                *dst++ = (char)(((c >> 3) & 07) + '0');
489d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		                *dst++ = (char)(( c       & 07) + '0');
490d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				len -= 4;
491d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
492d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			bytes += 4;
493d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else {
494d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (dst) {
495d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (len == 0) {
496d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					errno = ENOSPC;
497d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					return -1;
498d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
499d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				*dst++ = (char)c;
500d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				len--;
501d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
502d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			bytes++;
503d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
504d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
505d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
506d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* NULL */
507d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dst) {
508d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (len == 0) {
509d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = ENOSPC;
510d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
511d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
512d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*dst = '\0';
513d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
514d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Now we've printed it, validate the domain */
515d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type & DOMAIN && !valid_domainname(odst, type)) {
516d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*odst = '\0';
517d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return 1;
518d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
519d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
520d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
521d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
522d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return (ssize_t)bytes;
523d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
524d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
525d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define ADDR6SZ		16
526d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic size_t
527d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_optlen(const struct dhcp_opt *opt, size_t dl)
528d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
529d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t sz;
530d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
531ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	if (opt->type & ADDRIPV6)
532ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan		sz = ADDR6SZ;
533ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	else if (opt->type & (UINT32 | ADDRIPV4))
534ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan		sz = sizeof(uint32_t);
535ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	else if (opt->type & UINT16)
536ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan		sz = sizeof(uint16_t);
537ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	else if (opt->type & (UINT8 | BITFLAG))
538ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan		sz = sizeof(uint8_t);
539ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	else if (opt->type & FLAG)
540d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
541ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	else {
542ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan		/* All other types are variable length */
543d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (opt->len) {
544ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan			if ((size_t)opt->len > dl) {
545ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan				errno = ENODATA;
546ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan				return -1;
547ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan			}
548ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan			return (ssize_t)opt->len;
549d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
550ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan		return (ssize_t)dl;
551d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
552ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	if (dl < sz) {
553ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan		errno = ENODATA;
554ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan		return -1;
555d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
556d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
557ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	/* Trim any extra data.
558ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	 * Maybe we need a settng to reject DHCP options with extra data? */
559ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	if (opt->type & ARRAY)
560ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan		return (ssize_t)(dl - (dl % sz));
561ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	return (ssize_t)sz;
562d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
563d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
564d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET6
565d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define PO_IFNAME
566d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
567d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define PO_IFNAME __unused
568d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
569d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
570d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t
571d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanprint_option(char *s, size_t len, int type, const uint8_t *data, size_t dl,
572d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    PO_IFNAME const char *ifname)
573d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
574d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *e, *t;
575d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint16_t u16;
576d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int16_t s16;
577d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint32_t u32;
578d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int32_t s32;
579d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in_addr addr;
580d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ssize_t bytes = 0, sl;
581d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t l;
582d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *tmp;
583d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
584d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type & RFC3397) {
585d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		sl = decode_rfc3397(NULL, 0, data, dl);
586d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (sl == 0 || sl == -1)
587d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return sl;
588d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		l = (size_t)sl + 1;
589d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		tmp = malloc(l);
590d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (tmp == NULL)
591d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
592d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		decode_rfc3397(tmp, l, data, dl);
593d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		sl = print_string(s, len, type, (uint8_t *)tmp, l - 1);
594d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(tmp);
595d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return sl;
596d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
597d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
598d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET
599d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type & RFC3361) {
600d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((tmp = decode_rfc3361(data, dl)) == NULL)
601d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
602d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		l = strlen(tmp);
603d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		sl = print_string(s, len, type, (uint8_t *)tmp, l);
604d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(tmp);
605d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return sl;
606d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
607d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
608d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type & RFC3442)
609d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return decode_rfc3442(s, len, data, dl);
610d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
611d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type & RFC5969)
612d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return decode_rfc5969(s, len, data, dl);
613d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
614d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
615d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type & STRING)
616d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return print_string(s, len, type, data, dl);
617d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
618d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type & FLAG) {
619d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (s) {
620d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*s++ = '1';
621d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*s = '\0';
622d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
623d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 1;
624d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
625d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
626d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!s) {
627d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type & UINT8)
628d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			l = 3;
629d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else if (type & UINT16) {
630d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			l = 5;
631d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dl /= 2;
632d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (type & SINT16) {
633d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			l = 6;
634d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dl /= 2;
635d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (type & UINT32) {
636d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			l = 10;
637d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dl /= 4;
638d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (type & SINT32) {
639d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			l = 11;
640d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dl /= 4;
641d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (type & ADDRIPV4) {
642d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			l = 16;
643d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dl /= 4;
644d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
645d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET6
646d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else if (type & ADDRIPV6) {
647d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			e = data + dl;
648d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			l = 0;
649d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			while (data < e) {
650d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (l)
651d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					l++; /* space */
652d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				sl = ipv6_printaddr(NULL, 0, data, ifname);
653d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (sl != -1)
654d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					l += (size_t)sl;
655d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				data += 16;
656d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
657d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return (ssize_t)l;
658d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
659d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
660d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else {
661d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = EINVAL;
662d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
663d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
664d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return (ssize_t)(l * dl);
665d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
666d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
667d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	t = data;
668d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e = data + dl;
669d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (data < e) {
670d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (data != t) {
671d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*s++ = ' ';
672d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			bytes++;
673d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			len--;
674d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
675d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type & UINT8) {
676d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			sl = snprintf(s, len, "%u", *data);
677d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			data++;
678d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (type & UINT16) {
679d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&u16, data, sizeof(u16));
680d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			u16 = ntohs(u16);
681d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			sl = snprintf(s, len, "%u", u16);
682d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			data += sizeof(u16);
683d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (type & SINT16) {
684d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&u16, data, sizeof(u16));
685d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			s16 = (int16_t)ntohs(u16);
686d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			sl = snprintf(s, len, "%d", s16);
687d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			data += sizeof(u16);
688d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (type & UINT32) {
689d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&u32, data, sizeof(u32));
690d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			u32 = ntohl(u32);
691d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			sl = snprintf(s, len, "%u", u32);
692d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			data += sizeof(u32);
693d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (type & SINT32) {
694d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&u32, data, sizeof(u32));
695d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			s32 = (int32_t)ntohl(u32);
696d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			sl = snprintf(s, len, "%d", s32);
697d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			data += sizeof(u32);
698d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (type & ADDRIPV4) {
699d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
700d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			sl = snprintf(s, len, "%s", inet_ntoa(addr));
701d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			data += sizeof(addr.s_addr);
702d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
703d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET6
704d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else if (type & ADDRIPV6) {
705d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ssize_t r;
706d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
707d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			r = ipv6_printaddr(s, len, data, ifname);
708d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (r != -1)
709d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				sl = r;
710d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			else
711d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				sl = 0;
712d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			data += 16;
713d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
714d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
715d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
716d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			sl = 0;
7179ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan		if (len <= sl) {
7189ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan			bytes += len;
7199ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan			break;
7209ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan		}
721d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		len -= (size_t)sl;
722d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		bytes += sl;
723d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		s += sl;
724d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
725d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
726d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return bytes;
727d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
728d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
729e942e091ac1efb0ee1916add2b12f64fdfd59476Samuel Tan/* Lease file name is formatted according to the expectation of the ChromiumOS's
730e942e091ac1efb0ee1916add2b12f64fdfd59476Samuel Tan * connection manager (shill). */
731d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
732d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_set_leasefile(char *leasefile, size_t len, int family,
733d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct interface *ifp, const char *extra)
734d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
735d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char ssid[len];
736d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
737d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp->name[0] == '\0') {
738d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		strlcpy(leasefile, ifp->ctx->pidfile, len);
739d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
740d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
741d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
742a3595821594453ea89ef8e6790927694b0a1adf1Samuel Tan	if (strlen(ifp->lease_identifier) > 0) {
743e942e091ac1efb0ee1916add2b12f64fdfd59476Samuel Tan		return snprintf(leasefile, len,
744e942e091ac1efb0ee1916add2b12f64fdfd59476Samuel Tan				family == AF_INET ? LEASEFILE : LEASEFILE6,
74568df7cfd9156424667636ad3544d0fa9f337647dSamuel Tan				ifp->lease_identifier, "", extra);
746d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
747d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return snprintf(leasefile, len,
7488e603a0d0354b88712f1a81cc48dbd9936244fd5Samuel Tan			family == AF_INET ? LEASEFILE : LEASEFILE6,
74968df7cfd9156424667636ad3544d0fa9f337647dSamuel Tan			ifp->name, "", extra);
750d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
751d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
752d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic size_t
753d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_envoption1(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
754d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct dhcp_opt *opt, int vname, const uint8_t *od, size_t ol,
755d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const char *ifname)
756d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
757d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ssize_t len;
758d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t e;
759d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *v, *val;
760d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
761ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	/* Ensure a valid length */
762ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	ol = (size_t)dhcp_optlen(opt, ol);
763ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan	if ((ssize_t)ol == -1)
764ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan		return 0;
765ddbf02ae19016710a31fca4b2bc26f08a6fe191fSamuel Tan
766d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = print_option(NULL, 0, opt->type, od, ol, ifname);
767d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (len < 0)
768d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
769d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (vname)
770d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		e = strlen(opt->var) + 1;
771d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
772d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		e = 0;
773d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (prefix)
774d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		e += strlen(prefix);
775d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e += (size_t)len + 2;
776d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (env == NULL)
777d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return e;
778d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	v = val = *env = malloc(e);
779d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (v == NULL) {
780d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ctx, LOG_ERR, "%s: %m", __func__);
781d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
782d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
783d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (vname)
784d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		v += snprintf(val, e, "%s_%s=", prefix, opt->var);
785d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
786d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		v += snprintf(val, e, "%s=", prefix);
787d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (len != 0)
788d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		print_option(v, (size_t)len + 1, opt->type, od, ol, ifname);
789d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return e;
790d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
791d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
792d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansize_t
793d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
794d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const char *ifname, struct dhcp_opt *opt,
795d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
796d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    size_t *, unsigned int *, size_t *,
797d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const uint8_t *, size_t, struct dhcp_opt **),
798d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const uint8_t *od, size_t ol)
799d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
800d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t e, i, n, eos, eol;
801d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	unsigned int eoc;
802d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *eod;
803d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int ov;
804d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_opt *eopt, *oopt;
805d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *pfx;
806d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
807d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* If no embedded or encapsulated options, it's easy */
808d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (opt->embopts_len == 0 && opt->encopts_len == 0) {
809d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[0],
810d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    prefix, opt, 1, od, ol, ifname))
811d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return 1;
812d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
813d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
814d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
815d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Create a new prefix based on the option */
816d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (env) {
817d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (opt->type & INDEX) {
818d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (opt->index > 999) {
819d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				errno = ENOBUFS;
820d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ctx, LOG_ERR, "%s: %m", __func__);
821d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				return 0;
822d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
823d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
824d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		e = strlen(prefix) + strlen(opt->var) + 2 +
825d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (opt->type & INDEX ? 3 : 0);
826d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		pfx = malloc(e);
827d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (pfx == NULL) {
828d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ctx, LOG_ERR, "%s: %m", __func__);
829d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return 0;
830d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
831d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (opt->type & INDEX)
832d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			snprintf(pfx, e, "%s_%s%d", prefix,
833d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    opt->var, ++opt->index);
834d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
835d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			snprintf(pfx, e, "%s_%s", prefix, opt->var);
836d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else
837d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		pfx = NULL;
838d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
839d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Embedded options are always processed first as that
840d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * is a fixed layout */
841d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	n = 0;
842d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) {
843d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		e = dhcp_optlen(eopt, ol);
8440c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan		if (e == 0) {
8450c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan			/* An option was expected, but there is not enough
8460c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan			 * data for it.
8470c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan			 * This may not be an error as some options like
8480c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan			 * DHCP FQDN in RFC4702 have a string as the last
8490c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan			 * option which is optional.
8500c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan			 * FIXME: Add an flag to the options to indicate
8510c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan			 * wether this is allowable or not. */
8520c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan			 if (ol != 0 || i + 1 < opt->embopts_len)
8530c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan				logger(ctx, LOG_WARNING,
8540c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan				    "%s: %s: malformed option %d",
8550c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan				    ifname, __func__, opt->option);
8560c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan			 goto out;
8570c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tan		}
858d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Use the option prefix if the embedded option
859d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * name is different.
860d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * This avoids new_fqdn_fqdn which would be silly. */
861d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ov = strcmp(opt->var, eopt->var);
862d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[n],
863d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    pfx, eopt, ov, od, e, ifname))
864d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			n++;
865d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		od += e;
866d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ol -= e;
867d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
868d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
869d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Enumerate our encapsulated options */
870d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (opt->encopts_len && ol > 0) {
871d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Zero any option indexes
872d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * We assume that referenced encapsulated options are NEVER
873d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * recursive as the index order could break. */
874d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		for (i = 0, eopt = opt->encopts;
875d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i < opt->encopts_len;
876d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i++, eopt++)
877d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
878d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			eoc = opt->option;
879d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (eopt->type & OPTION) {
880d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				dgetopt(ctx, NULL, &eoc, NULL, NULL, 0, &oopt);
881d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (oopt)
882d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					oopt->index = 0;
883d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
884d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
885d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
886d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		while ((eod = dgetopt(ctx, &eos, &eoc, &eol, od, ol, &oopt))) {
887d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			for (i = 0, eopt = opt->encopts;
888d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    i < opt->encopts_len;
889d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    i++, eopt++)
890d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			{
891d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (eopt->option == eoc) {
892d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					if (eopt->type & OPTION) {
893d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan						if (oopt == NULL)
894d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan							/* Report error? */
895d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan							continue;
896d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					}
897d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					n += dhcp_envoption(ctx,
898d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    env == NULL ? NULL : &env[n], pfx,
899d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    ifname,
900d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    eopt->type & OPTION ? oopt : eopt,
901d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    dgetopt, eod, eol);
902d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					break;
903d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
904d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
905d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			od += eos + eol;
906d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ol -= eos + eol;
907d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
908d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
909d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
9100c07e7a4a10f902911d93f37e01b8a0308d67e96Samuel Tanout:
911d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (env)
912d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(pfx);
913d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
914d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Return number of options found */
915d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return n;
916d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
917d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
918d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
919d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_zero_index(struct dhcp_opt *opt)
920d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
921d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t i;
922d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_opt *o;
923d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
924d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	opt->index = 0;
925d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++)
926d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_zero_index(o);
927d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++)
928d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_zero_index(o);
929d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
930