xref: /netbsd-src/external/mpl/dhcp/dist/keama/options.c (revision f407d9293b6650aa8c33d6a995f797bb6aaefd90)
1 /*	$NetBSD: options.c,v 1.3 2022/04/03 01:10:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2017-2022 Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  *   Internet Systems Consortium, Inc.
19  *   PO Box 360
20  *   Newmarket, NH 03857 USA
21  *   <info@isc.org>
22  *   https://www.isc.org/
23  *
24  */
25 
26 #include <sys/cdefs.h>
27 __RCSID("$NetBSD: options.c,v 1.3 2022/04/03 01:10:59 christos Exp $");
28 
29 #include <assert.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include "keama.h"
34 
35 TAILQ_HEAD(spaces, space) spaces;
36 TAILQ_HEAD(options, option) options;
37 
38 /* From common/tables.c */
39 
40 /* Additional format codes:
41 
42    x - ISC DHCP and Kea string
43    Y - force full binary
44    u - undefined (parsed as X)
45 */
46 
47 /// SPACES
48 struct space_def space_defs[] = {
49 	{ "dhcp", "dhcp4", 2},
50 	{ "nwip", "nwip", 0},
51 	{ "agent", "dhcp-agent-options-space", 2},
52 	{ "vendor-class", "_vivco_", 0},
53 	{ "vendor", "_vivso_", 3},
54 	{ "isc", "_isc_", 0},
55 	{ "", "vendor-encapsulated-options-space", 1},
56 	{ "_docsis3_", "vendor-4491", 1},
57 	{ "dhcp6", "dhcp6", 2},
58 	{ "vsio", "_vendor-opts-space_", 3},
59 	{ "_vsio_", "vendor-opts-space", 1},
60 	{ "isc6", "_isc6_", 0},
61 	{ "_rsoo_", "rsoo-opts", 1},
62 	{ "_isc6_", "vendor-2495", 1},
63 	{ "server", "_server_", 0},
64 	{ NULL, NULL, 0}
65 };
66 
67 /// DHCPv4
68 struct option_def options4[] = {
69 	{ "subnet-mask", "I",			"dhcp",   1, 2},
70 	{ "time-offset", "l",			"dhcp",   2, 2},
71 	{ "routers", "Ia",			"dhcp",   3, 2},
72 	{ "time-servers", "Ia",			"dhcp",   4, 2},
73 	{ "ien116-name-servers", "Ia",		"dhcp",   5, 2},
74 	/// ien116-name-servers -> name-servers
75 	{ "domain-name-servers", "Ia",		"dhcp",   6, 2},
76 	{ "log-servers", "Ia",			"dhcp",   7, 2},
77 	{ "cookie-servers", "Ia",		"dhcp",   8, 2},
78 	{ "lpr-servers", "Ia",			"dhcp",   9, 2},
79 	{ "impress-servers", "Ia",		"dhcp",  10, 2},
80 	{ "resource-location-servers", "Ia",	"dhcp",  11, 2},
81 	{ "host-name", "t",			"dhcp",  12, 2},
82 	{ "boot-size", "S",			"dhcp",  13, 2},
83 	{ "merit-dump", "t",			"dhcp",  14, 2},
84 	{ "domain-name", "t",			"dhcp",  15, 2},
85 	{ "swap-server", "I",			"dhcp",  16, 2},
86 	{ "root-path", "t",			"dhcp",  17, 2},
87 	{ "extensions-path", "t",		"dhcp",  18, 2},
88 	{ "ip-forwarding", "f",			"dhcp",  19, 2},
89 	{ "non-local-source-routing", "f",	"dhcp",  20, 2},
90 	{ "policy-filter", "IIa",		"dhcp",  21, 2},
91 	{ "max-dgram-reassembly", "S",		"dhcp",  22, 2},
92 	{ "default-ip-ttl", "B",		"dhcp",  23, 2},
93 	{ "path-mtu-aging-timeout", "L",	"dhcp",  24, 2},
94 	{ "path-mtu-plateau-table", "Sa",	"dhcp",  25, 2},
95 	{ "interface-mtu", "S",			"dhcp",  26, 2},
96 	{ "all-subnets-local", "f",		"dhcp",  27, 2},
97 	{ "broadcast-address", "I",		"dhcp",  28, 2},
98 	{ "perform-mask-discovery", "f",	"dhcp",  29, 2},
99 	{ "mask-supplier", "f",			"dhcp",  30, 2},
100 	{ "router-discovery", "f",		"dhcp",  31, 2},
101 	{ "router-solicitation-address", "I",	"dhcp",  32, 2},
102 	{ "static-routes", "IIa",		"dhcp",  33, 2},
103 	{ "trailer-encapsulation", "f",		"dhcp",  34, 2},
104 	{ "arp-cache-timeout", "L",		"dhcp",  35, 2},
105 	{ "ieee802-3-encapsulation", "f",	"dhcp",  36, 2},
106 	{ "default-tcp-ttl", "B",		"dhcp",  37, 2},
107 	{ "tcp-keepalive-interval", "L",	"dhcp",  38, 2},
108 	{ "tcp-keepalive-garbage", "f",		"dhcp",  39, 2},
109 	{ "nis-domain", "t",			"dhcp",  40, 2},
110 	{ "nis-servers", "Ia",			"dhcp",  41, 2},
111 	{ "ntp-servers", "Ia",			"dhcp",  42, 2},
112 	{ "vendor-encapsulated-options", "E.",	"dhcp",  43, 2},
113 	{ "netbios-name-servers", "Ia",		"dhcp",  44, 2},
114 	{ "netbios-dd-server", "Ia",		"dhcp",  45, 2},
115 	{ "netbios-node-type", "B",		"dhcp",  46, 2},
116 	{ "netbios-scope", "t",			"dhcp",  47, 2},
117 	{ "font-servers", "Ia",			"dhcp",  48, 2},
118 	{ "x-display-manager", "Ia",		"dhcp",  49, 2},
119 	{ "dhcp-requested-address", "I",	"dhcp",  50, 2},
120 	{ "dhcp-lease-time", "L",		"dhcp",  51, 2},
121 	{ "dhcp-option-overload", "B",		"dhcp",  52, 2},
122 	{ "dhcp-message-type", "B",		"dhcp",  53, 2},
123 	{ "dhcp-server-identifier", "I",	"dhcp",  54, 2},
124 	{ "dhcp-parameter-request-list", "Ba",	"dhcp",  55, 2},
125 	{ "dhcp-message", "t",			"dhcp",  56, 2},
126 	{ "dhcp-max-message-size", "S",		"dhcp",  57, 2},
127 	{ "dhcp-renewal-time", "L",		"dhcp",  58, 2},
128 	{ "dhcp-rebinding-time", "L",		"dhcp",  59, 2},
129 	{ "vendor-class-identifier", "x",	"dhcp",  60, 2},
130 	{ "dhcp-client-identifier", "X",	"dhcp",  61, 2},
131 	{ "nwip-domain", "t",			"dhcp",  62, 2},
132 	/// nwip-domain nwip-domain-name
133 	{ "nwip-suboptions", "Enwip.",		"dhcp",  63, 2},
134 	{ "nisplus-domain", "t",		"dhcp",  64, 2},
135 	/// nisplus-domain nisplus-domain-name
136 	{ "nisplus-servers", "Ia",		"dhcp",  65, 2},
137 	{ "tftp-server-name", "t",		"dhcp",  66, 2},
138 	{ "bootfile-name", "t",			"dhcp",  67, 2},
139 	/// bootfile-name boot-file-name
140 	{ "mobile-ip-home-agent", "Ia",		"dhcp",  68, 2},
141 	{ "smtp-server", "Ia",			"dhcp",  69, 2},
142 	{ "pop-server", "Ia",			"dhcp",  70, 2},
143 	{ "nntp-server", "Ia",			"dhcp",  71, 2},
144 	{ "www-server", "Ia",			"dhcp",  72, 2},
145 	{ "finger-server", "Ia",		"dhcp",  73, 2},
146 	{ "irc-server", "Ia",			"dhcp",  74, 2},
147 	{ "streettalk-server", "Ia",		"dhcp",  75, 2},
148 	{ "streettalk-directory-assistance-server", "Ia",
149 						"dhcp",  76, 2},
150 	{ "user-class", "tY",			"dhcp",  77, 2},
151 	{ "slp-directory-agent", "fIa",		"dhcp",  78, 2},
152 	{ "slp-service-scope", "fto",		"dhcp",  79, 2},
153 	/* 80 is the zero-length rapid-commit (RFC 4039) */
154 	{ "fqdn", "Efqdn.",			"dhcp",  81, 2},
155 	{ "relay-agent-information", "Eagent.",	"dhcp",  82, 2},
156 	/// relay-agent-information dhcp-agent-options
157 	/* 83 is iSNS (RFC 4174) */
158 	/* 84 is unassigned */
159 	{ "nds-servers", "Ia",			"dhcp",  85, 2},
160 	{ "nds-tree-name", "t",			"dhcp",  86, 2},
161 	{ "nds-context", "t",			"dhcp",  87, 2},
162 	{ "bcms-controller-names", "D",		"dhcp",  88, 2},
163 	{ "bcms-controller-address", "Ia",	"dhcp",  89, 2},
164 	{ "authenticate", "X",			"dhcp",  90, 1},
165 	/// not supported by ISC DHCP
166 	{ "client-last-transaction-time", "L",  "dhcp",  91, 2},
167 	{ "associated-ip", "Ia",                "dhcp",  92, 2},
168 	{ "pxe-system-type", "Sa",		"dhcp",  93, 2},
169 	// pxe-system-type client-system
170 	{ "pxe-interface-id", "BBB",		"dhcp",  94, 2},
171 	// pxe-interface-id client-ndi
172 	{ "pxe-client-id", "BX",		"dhcp",  97, 2},
173 	// pxe-client-id uuid-guid
174 	{ "uap-servers", "t",			"dhcp",  98, 2},
175         { "geoconf-civic", "X",                 "dhcp",  99, 2},
176 	{ "pcode", "t",				"dhcp", 100, 2},
177 	{ "tcode", "t",				"dhcp", 101, 2},
178 	{ "v6-only-preferred", "L",		"dhcp", 108, 2},
179 	{ "netinfo-server-address", "Ia",	"dhcp", 112, 2},
180 	{ "netinfo-server-tag", "t",		"dhcp", 113, 2},
181 	{ "default-url", "t",			"dhcp", 114, 2},
182 	{ "auto-config", "B",			"dhcp", 116, 2},
183 	{ "name-service-search", "Sa",		"dhcp", 117, 2},
184 	{ "subnet-selection", "I",		"dhcp", 118, 2},
185 	{ "domain-search", "Dc",		"dhcp", 119, 2},
186 	{ "vivco", "Evendor-class.",		"dhcp", 124, 2},
187 	/// vivco vivco-suboptions
188 	{ "vivso", "Evendor.",			"dhcp", 125, 2},
189 	/// vivso vivso-suboptions
190 	{"pana-agent", "Ia",			"dhcp", 136, 2},
191 	{"v4-lost", "d",			"dhcp", 137, 2},
192 	{"capwap-ac-v4", "Ia",			"dhcp", 138, 2},
193 	{ "sip-ua-cs-domains", "Dc",		"dhcp", 141, 2},
194 	{ "ipv4-address-andsf", "Ia",		"dhcp", 142, 0},
195 	/// not supported by Kea
196         { "rdnss-selection", "BIID",		"dhcp", 146, 2},
197 	{ "tftp-server-address", "Ia",		"dhcp", 150, 0},
198 	/// not supported by Kea
199 	{ "v4-portparams", "BBS",		"dhcp", 159, 2},
200 	{ "v4-captive-portal", "t",		"dhcp", 160, 2},
201         { "option-6rd", "BB6Ia",		"dhcp", 212, 2},
202 	{"v4-access-domain", "d",		"dhcp", 213, 2},
203 	{ NULL, NULL, NULL, 0, 0 }
204 };
205 
206 /// DHCPv6
207 struct option_def options6[] = {
208 	{ "client-id", "X",			"dhcp6",  1, 2},
209 	/// client-id clientid
210 	{ "server-id", "X",			"dhcp6",  2, 2},
211 	/// server-id serverid
212 	{ "ia-na", "X",				"dhcp6",  3, 2},
213 	{ "ia-ta", "X",				"dhcp6",  4, 2},
214 	{ "ia-addr", "X",			"dhcp6",  5, 2},
215 	/// ia-addr iaaddr
216 	{ "oro", "Sa",				"dhcp6",  6, 2},
217 	{ "preference", "B",			"dhcp6",  7, 2},
218 	{ "elapsed-time", "S",			"dhcp6",  8, 2},
219 	{ "relay-msg", "X",			"dhcp6",  9, 2},
220         /// 10 is unassigned
221 	{ "auth", "X",				"dhcp6", 11, 1},
222 	/// not supported by ISC DHCP
223 	{ "unicast", "6",			"dhcp6", 12, 2},
224 	{ "status-code", "Nstatus-codes.to",	"dhcp6", 13, 2},
225 	{ "rapid-commit", "Z",			"dhcp6", 14, 2},
226 	{ "user-class", "X",			"dhcp6", 15, 1},
227 	/// not supported by ISC DHCP
228 	{ "vendor-class", "LX",			"dhcp6", 16, 1},
229 	/// not supported by ISC DHCP
230 	{ "vendor-opts", "Evsio.",		"dhcp6", 17, 2},
231 	{ "interface-id", "X",			"dhcp6", 18, 2},
232 	{ "reconf-msg", "Ndhcpv6-messages.",	"dhcp6", 19, 2},
233 	{ "reconf-accept", "Z",			"dhcp6", 20, 2},
234 	{ "sip-servers-names", "D",		"dhcp6", 21, 2},
235 	/// sip-servers-names sip-server-dns
236 	{ "sip-servers-addresses", "6a",	"dhcp6", 22, 2},
237 	/// sip-servers-addresses sip-server-addr
238 	{ "name-servers", "6a",			"dhcp6", 23, 2},
239 	/// name-servers dns-servers
240 	{ "domain-search", "D",			"dhcp6", 24, 2},
241 	{ "ia-pd", "X",				"dhcp6", 25, 2},
242 	{ "ia-prefix", "X",			"dhcp6", 26, 2},
243 	/// ia-prefix iaprefix
244 	{ "nis-servers", "6a", 			"dhcp6", 27, 2},
245 	{ "nisp-servers", "6a",			"dhcp6", 28, 2},
246 	{ "nis-domain-name", "D",		"dhcp6", 29, 2},
247 	{ "nisp-domain-name", "D",		"dhcp6", 30, 2},
248 	{ "sntp-servers", "6a",			"dhcp6", 31, 2},
249 	{ "info-refresh-time", "T",		"dhcp6", 32, 2},
250 	/// info-refresh-time information-refresh-time
251 	{ "bcms-server-d", "D",			"dhcp6", 33, 2},
252 	/// bcms-server-d bcms-server-dns
253 	{ "bcms-server-a", "6a",		"dhcp6", 34, 2},
254 	/// bcms-server-a bcms-server-addr
255 	/* Note that 35 is not assigned. */
256 	{ "geoconf-civic", "X",			"dhcp6", 36, 2},
257 	{ "remote-id", "X",			"dhcp6", 37, 2},
258 	{ "subscriber-id", "X",			"dhcp6", 38, 2},
259 	{ "fqdn", "Efqdn6-if-you-see-me-its-a-bug-bug-bug.",
260 						"dhcp6", 39, 2},
261 	/// fqdn client-fqdn
262 	{ "pana-agent", "6a",			"dhcp6", 40, 2},
263 	{ "new-posix-timezone", "t",		"dhcp6", 41, 2},
264 	{ "new-tzdb-timezone", "t",		"dhcp6", 42, 2},
265 	{ "ero", "Sa",				"dhcp6", 43, 2},
266 	{ "lq-query", "X",			"dhcp6", 44, 2},
267 	{ "client-data", "X",			"dhcp6", 45, 2},
268 	{ "clt-time", "L",			"dhcp6", 46, 2},
269 	{ "lq-relay-data", "6X",		"dhcp6", 47, 2},
270 	{ "lq-client-link", "6a",		"dhcp6", 48, 2},
271 	{ "v6-lost", "d",			"dhcp6", 51, 2},
272 	{ "capwap-ac-v6", "6a",			"dhcp6", 52, 2},
273 	{ "relay-id", "X",			"dhcp6", 53, 2},
274 	{ "v6-access-domain", "d",		"dhcp6", 57, 2},
275 	{ "sip-ua-cs-list", "D",		"dhcp6", 58, 2},
276 	{ "bootfile-url", "t",			"dhcp6", 59, 2},
277 	{ "bootfile-param", "X",		"dhcp6", 60, 2},
278 	{ "client-arch-type", "Sa",		"dhcp6", 61, 2},
279 	{ "nii", "BBB",				"dhcp6", 62, 2},
280 	{ "aftr-name", "d",			"dhcp6", 64, 2},
281 	{ "erp-local-domain-name", "d",		"dhcp6", 65, 2},
282 	{ "rsoo", "Ersoo.",			"dhcp6", 66, 1},
283 	/// not supported by ISC DHCP
284 	{ "pd-exclude", "X",			"dhcp6", 67, 1},
285 	/// not supported by ISC DHCP (prefix6 format)
286 	{ "rdnss-selection", "6BD",		"dhcp6", 74, 2},
287 	{ "client-linklayer-addr", "X",		"dhcp6", 79, 2},
288 	{ "link-address", "6",			"dhcp6", 80, 2},
289 	{ "solmax-rt", "L",			"dhcp6", 82, 2},
290 	{ "inf-max-rt", "L",			"dhcp6", 83, 2},
291 	{ "dhcpv4-msg", "X",			"dhcp6", 87, 2},
292 	/// dhcpv4-msg dhcpv4-message
293 	{ "dhcp4-o-dhcp6-server", "6a",		"dhcp6", 88, 2},
294 	/// dhcp4-o-dhcp6-server dhcp4o6-server-addr
295 	{ "v6-captive-portal", "t",		"dhcp6", 103, 2},
296 	{ "relay-source-port", "S",		"dhcp6", 135, 2},
297 	{ "ipv6-address-andsf", "6a",		"dhcp6", 143, 2},
298 	{ NULL, NULL, NULL, 0, 0 }
299 };
300 
301 /// DHCPv4 AGENT
302 struct option_def agents[] = {
303 	/// All not supported by Kea
304 	{ "circuit-id", "X",			"agent",   1, 0},
305 	{ "remote-id", "X",			"agent",   2, 0},
306 	{ "agent-id", "I",			"agent",   3, 0},
307 	{ "DOCSIS-device-class", "L",		"agent",   4, 0},
308 	{ "link-selection", "I",		"agent",   5, 0},
309 	{ "relay-port", "Z",			"agent",  19, 0},
310 	{ NULL, NULL, NULL, 0, 0 }
311 };
312 
313 /// SERVER
314 struct option_def configs[] = {
315 	{ "default-lease-time", "T",		"server",   1, 3},
316 	{ "max-lease-time", "T",		"server",   2, 3},
317 	{ "min-lease-time", "T",		"server",   3, 3},
318 	{ "dynamic-bootp-lease-cutoff", "T",	"server",   4, 0},
319 	{ "dynamic-bootp-lease-length", "L",	"server",   5, 0},
320 	{ "boot-unknown-clients", "f",		"server",   6, 0},
321 	{ "dynamic-bootp", "f",			"server",   7, 0},
322 	{ "allow-bootp", "f",			"server",   8, 0},
323 	{ "allow-booting", "f",			"server",   9, 0},
324 	{ "one-lease-per-client", "f",		"server",  10, 0},
325 	{ "get-lease-hostnames", "f",		"server",  11, 0},
326 	{ "use-host-decl-names", "f",		"server",  12, 0},
327 	{ "use-lease-addr-for-default-route", "f",
328 						"server",  13, 0},
329 	{ "min-secs", "B",			"server",  14, 0},
330 	{ "filename", "t",			"server",  15, 3},
331 	{ "server-name", "t",			"server",  16, 3},
332 	{ "next-server", "I",			"server",  17, 3},
333 	{ "authoritative", "f",			"server",  18, 3},
334 	{ "vendor-option-space", "U",		"server",  19, 3},
335 	{ "always-reply-rfc1048", "f",		"server",  20, 0},
336 	{ "site-option-space", "X",		"server",  21, 3},
337 	{ "always-broadcast", "f",		"server",  22, 0},
338 	{ "ddns-domainname", "t",		"server",  23, 3},
339 	{ "ddns-hostname", "t",			"server",  24, 0},
340 	{ "ddns-rev-domainname", "t",		"server",  25, 0},
341 	{ "lease-file-name", "t",		"server",  26, 0},
342 	{ "pid-file-name", "t",			"server",  27, 0},
343 	{ "duplicates", "f",			"server",  28, 0},
344 	{ "declines", "f",			"server",  29, 0},
345 	{ "ddns-updates", "f",			"server",  30, 3},
346 	{ "omapi-port", "S",			"server",  31, 0},
347 	{ "local-port", "S",			"server",  32, 0},
348 	{ "limited-broadcast-address", "I",	"server",  33, 0},
349 	{ "remote-port", "S",			"server",  34, 0},
350 	{ "local-address", "I",			"server",  35, 0},
351 	{ "omapi-key", "d",			"server",  36, 0},
352 	{ "stash-agent-options", "f",		"server",  37, 0},
353 	{ "ddns-ttl", "T",			"server",  38, 0},
354 	{ "ddns-update-style", "Nddns-styles.",	"server",  39, 3},
355 	{ "client-updates", "f",		"server",  40, 0},
356 	{ "update-optimization", "f",		"server",  41, 0},
357 	{ "ping-check", "f",			"server",  42, 0},
358 	{ "update-static-leases", "f",		"server",  43, 0},
359 	{ "log-facility", "Nsyslog-facilities.",
360 						"server",  44, 0},
361 	{ "do-forward-updates", "f",		"server",  45, 0},
362 	{ "ping-timeout", "T",			"server",  46, 0},
363 	{ "infinite-is-reserved", "f",		"server",  47, 0},
364 	{ "update-conflict-detection", "f",	"server",  48, 0},
365 	{ "leasequery", "f",			"server",  49, 0},
366 	{ "adaptive-lease-time-threshold", "B",	"server",  50, 0},
367 	{ "do-reverse-updates", "f",		"server",  51, 0},
368 	{ "fqdn-reply", "f",			"server",  52, 0},
369 	{ "preferred-lifetime", "T",		"server",  53, 3},
370 	{ "dhcpv6-lease-file-name", "t",	"server",  54, 0},
371 	{ "dhcpv6-pid-file-name", "t",		"server",  55, 0},
372 	{ "limit-addrs-per-ia", "L",		"server",  56, 0},
373 	{ "limit-prefs-per-ia", "L",		"server",  57, 0},
374  	{ "delayed-ack", "S",			"server",  58, 0},
375  	{ "max-ack-delay", "L",			"server",  59, 0},
376 	/* LDAP */
377 	{ "dhcp-cache-threshold", "B",		"server",  78, 0},
378 	{ "dont-use-fsync", "f",		"server",  79, 0},
379 	{ "ddns-local-address4", "I",		"server",  80, 0},
380 	{ "ddns-local-address6", "6",		"server",  81, 0},
381 	{ "ignore-client-uids", "f",		"server",  82, 3},
382 	{ "log-threshold-low", "B",		"server",  83, 0},
383 	{ "log-threshold-high", "B",		"server",  84, 0},
384 	{ "echo-client-id", "f",		"server",  85, 3},
385 	{ "server-id-check", "f",		"server",  86, 0},
386 	{ "prefix-length-mode", "Nprefix_length_modes.",
387 						"server",  87, 0},
388 	{ "dhcpv6-set-tee-times", "f",		"server",  88, 0},
389 	{ "abandon-lease-time", "T",		"server",  89, 0},
390  	{ "use-eui-64", "f",			"server",  90, 0},
391         { "check-secs-byte-order", "f",         "server",  91, 0},
392         { "persist-eui-64-leases", "f",         "server",  92, 0},
393         { "ddns-dual-stack-mixed-mode", "f",    "server",  93, 0},
394         { "ddns-guard-id-must-match", "f",      "server",  94, 0},
395         { "ddns-other-guard-is-dynamic", "f",   "server",  95, 0},
396 	{ "release-on-roam", "f",		"server",  96, 0},
397 	{ "local-address6", "6",		"server",  97, 0},
398         { "bind-local-address6", "f",           "server",  98, 0},
399 	{ "ping-cltt-secs", "T",		"server",  99, 0},
400 	{ "ping-timeout-ms", "T",		"server", 100, 0},
401 	{ NULL, NULL, NULL, 0, 0 }
402 };
403 
404 void
spaces_init(void)405 spaces_init(void)
406 {
407 	struct space_def *def;
408 	struct space *space;
409 
410 	TAILQ_INIT(&spaces);
411 
412 	/* Fill spaces */
413 	for (def = space_defs; def->name != NULL; def++) {
414 		space = (struct space *)malloc(sizeof(*space));
415 		assert(space != NULL);
416 		memset(space, 0, sizeof(*space));
417 		space->old = def->old;
418 		space->name = def->name;
419 		space->status = def->status;
420 		TAILQ_INSERT_TAIL(&spaces, space);
421 	}
422 }
423 
424 void
options_init(void)425 options_init(void)
426 {
427 	struct option_def *def;
428 	struct option *option;
429 
430 	TAILQ_INIT(&options);
431 
432 	/* Fill DHCPv4 options */
433 	for (def = options4; def->name != NULL; def++) {
434 		option = (struct option *)malloc(sizeof(*option));
435 		assert(option != NULL);
436 		memset(option, 0, sizeof(*option));
437 		option->old = def->name;
438 		switch (def->code) {
439 		case 5:
440 			option->name = "name-servers";
441 			break;
442 		case 62:
443 			option->name = "nwip-domain-name";
444 			break;
445 		case 64:
446 			option->name = "nisplus-domain-name";
447 			break;
448 		case 67:
449 			option->name = "boot-file-name";
450 			break;
451 		case 82:
452 			option->name = "dhcp-agent-options";
453 			break;
454 		case 93:
455 			option->name = "client-system";
456 			break;
457 		case 94:
458 			option->name = "client-ndi";
459 			break;
460 		case 97:
461 			option->name = "uuid-guid";
462 			break;
463 		case 124:
464 			option->name = "vivco-suboptions";
465 			break;
466 		case 125:
467 			option->name = "vivso-suboptions";
468 			break;
469 		default:
470 			option->name = def->name;
471 		}
472 		option->format = def->format;
473 		option->space = space_lookup(def->space);
474 		assert(option->space != NULL);
475 		option->code = def->code;
476 		option->status = def->status;
477 		TAILQ_INSERT_TAIL(&options, option);
478 	}
479 
480 	/* Fill DHCPv6 options */
481 	for (def = options6; def->name != NULL; def++) {
482 		option = (struct option *)malloc(sizeof(*option));
483 		assert(option != NULL);
484 		memset(option, 0, sizeof(*option));
485 		option->old = def->name;
486 		switch (def->code) {
487 		case 1:
488 			option->name = "clientid";
489 			break;
490 		case 2:
491 			option->name = "serverid";
492 			break;
493 		case 5:
494 			option->name = "iaaddr";
495 			break;
496 		case 21:
497 			option->name = "sip-server-dns";
498 			break;
499 		case 22:
500 			option->name = "sip-server-addr";
501 			break;
502 		case 23:
503 			option->name = "dns-servers";
504 			break;
505 		case 26:
506 			option->name = "iaprefix";
507 			break;
508 		case 32:
509 			option->name = "information-refresh-time";
510 			break;
511 		case 33:
512 			option->name = "bcms-server-dns";
513 			break;
514 		case 34:
515 			option->name = "bcms-server-addr ";
516 			break;
517 		case 39:
518 			option->name = "client-fqdn";
519 			break;
520 		case 87:
521 			option->name = "dhcpv4-message";
522 			break;
523 		case 88:
524 			option->name = "dhcp4o6-server-addr";
525 			break;
526 		default:
527 			option->name = def->name;
528 			break;
529 		}
530 		option->format = def->format;
531 		option->space = space_lookup(def->space);
532 		assert(option->space != NULL);
533 		option->code = def->code;
534 		option->status = def->status;
535 		TAILQ_INSERT_TAIL(&options, option);
536 	}
537 
538 	/* Fill agent options */
539 	for (def = agents; def->name != NULL; def++) {
540 		option = (struct option *)malloc(sizeof(*option));
541 		assert(option != NULL);
542 		memset(option, 0, sizeof(*option));
543 		option->old = def->name;
544 		option->name = def->name;
545 		option->format = def->format;
546 		option->space = space_lookup(def->space);
547 		assert(option->space != NULL);
548 		option->code = def->code;
549 		option->status = def->status;
550 		TAILQ_INSERT_TAIL(&options, option);
551 	}
552 
553 	/* Fill server config options */
554 	for (def = configs; def->name != NULL; def++) {
555 		option = (struct option *)malloc(sizeof(*option));
556 		assert(option != NULL);
557 		memset(option, 0, sizeof(*option));
558 		option->old = def->name;
559 		option->name = def->name;
560 		option->format = def->format;
561 		option->space = space_lookup(def->space);
562 		assert(option->space != NULL);
563 		option->code = def->code;
564 		option->status = def->status;
565 		TAILQ_INSERT_TAIL(&options, option);
566 	}
567 }
568 
569 struct space *
space_lookup(const char * name)570 space_lookup(const char *name)
571 {
572 	struct space *space;
573 
574 	TAILQ_FOREACH(space, &spaces) {
575 		if (space->status == isc_dhcp_unknown)
576 			continue;
577 		if (strcmp(name, space->old) == 0)
578 			return space;
579 	}
580 	return NULL;
581 }
582 
583 struct option *
option_lookup_name(const char * space,const char * name)584 option_lookup_name(const char *space, const char *name)
585 {
586 	struct space *universe;
587 	struct option *option;
588 
589 	universe = space_lookup(space);
590 	if (universe == NULL)
591 		return NULL;
592 	TAILQ_FOREACH(option, &options) {
593 		if (option->status == isc_dhcp_unknown)
594 			continue;
595 		if (universe != option->space)
596 			continue;
597 		if (strcmp(name, option->old) == 0)
598 			return option;
599 	}
600 	return NULL;
601 }
602 
603 struct option *
kea_lookup_name(const char * space,const char * name)604 kea_lookup_name(const char *space, const char *name)
605 {
606 	struct space *universe;
607 	struct option *option;
608 
609 	TAILQ_FOREACH(universe, &spaces) {
610 		if (universe->status == kea_unknown)
611 			continue;
612 		if (strcmp(name, universe->name) == 0)
613 			break;
614 	}
615 	if (universe == NULL)
616 		return NULL;
617 	TAILQ_FOREACH(option, &options) {
618 		if (option->status == kea_unknown)
619 			continue;
620 		if (universe != option->space)
621 			continue;
622 		if (strcmp(name, option->name) == 0)
623 			return option;
624 	}
625 	return NULL;
626 }
627 
628 struct option *
option_lookup_code(const char * space,unsigned code)629 option_lookup_code(const char *space, unsigned code)
630 {
631 	struct space *universe;
632 	struct option *option;
633 
634 	universe = space_lookup(space);
635 	if (universe == NULL)
636 		return NULL;
637 	TAILQ_FOREACH(option, &options) {
638 		if (universe != option->space)
639 			continue;
640 		if (code == option->code)
641 			return option;
642 	}
643 	return NULL;
644 }
645 
646 void
push_space(struct space * space)647 push_space(struct space *space)
648 {
649 	space->status = dynamic;
650 	TAILQ_INSERT_TAIL(&spaces, space);
651 }
652 
653 void
push_option(struct option * option)654 push_option(struct option *option)
655 {
656 	assert(option->space != NULL);
657 	option->old = option->name;
658 	option->status = dynamic;
659 	TAILQ_INSERT_TAIL(&options, option);
660 }
661 
662 void
add_option_data(struct element * src,struct element * dst)663 add_option_data(struct element *src, struct element *dst)
664 {
665 	struct string *sspace;
666 	struct element *scode;
667 	struct element *name;
668 	struct option *option;
669 	size_t i;
670 
671 	sspace = stringValue(mapGet(src, "space"));
672 	scode = mapGet(src, "code");
673 	name = mapGet(src, "name");
674 	assert((scode != NULL) || (name != NULL));
675 
676 	/* We'll use the code so fill it even it should always be available */
677 	if (scode == NULL) {
678 		option = kea_lookup_name(sspace->content,
679 					 stringValue(name)->content);
680 		assert(option != NULL);
681 		scode = createInt(option->code);
682 		mapSet(src, scode, "code");
683 	}
684 	assert(intValue(scode) != 0);
685 
686 	for (i = 0; i < listSize(dst); i++) {
687 		struct element *od;
688 		struct element *space;
689 		struct element *code;
690 
691 		od = listGet(dst, i);
692 		space = mapGet(od, "space");
693 		if (!eqString(sspace, stringValue(space)))
694 			continue;
695 		code = mapGet(od, "code");
696 		if (code == NULL) {
697 			name = mapGet(od, "name");
698 			assert(name != NULL);
699 			option = kea_lookup_name(sspace->content,
700 						 stringValue(name)->content);
701 			assert(option != NULL);
702 			code = createInt(option->code);
703 			mapSet(od, code, "code");
704 		}
705 		/* check if the option is already present */
706 		if (intValue(scode) == intValue(code))
707 				return;
708 	}
709 	listPush(dst, copy(src));
710 }
711 
712 void
merge_option_data(struct element * src,struct element * dst)713 merge_option_data(struct element *src, struct element *dst)
714 {
715 	struct element *od;
716 	size_t i;
717 
718 	for (i = 0; i < listSize(src); i++) {
719 		od = listGet(src, i);
720 		add_option_data(od, dst);
721 	}
722 }
723 
724 struct comments *
get_config_comments(unsigned code)725 get_config_comments(unsigned code)
726 {
727 	static struct comments comments;
728 	struct comment *comment = NULL;
729 
730 	TAILQ_INIT(&comments);
731 	switch (code) {
732 	case 4: /* dynamic-bootp-lease-cutoff */
733 	case 5: /* dynamic-bootp-lease-length */
734 	case 6: /* boot-unknown-clients */
735 	case 7: /* dynamic-bootp */
736 	case 8: /* allow-bootp */
737 	no_bootp:
738 		comment = createComment("/// bootp protocol is not supported");
739 		TAILQ_INSERT_TAIL(&comments, comment);
740 		break;
741 
742 	case 9: /* allow-booting */
743 		comment = createComment("/// allow-booting is not supported");
744 		TAILQ_INSERT_TAIL(&comments, comment);
745 		comment = createComment("/// no concrete usage known?");
746 		TAILQ_INSERT_TAIL(&comments, comment);
747 		comment = createComment("/// Reference Kea #239");
748 		TAILQ_INSERT_TAIL(&comments, comment);
749 		break;
750 
751 	case 10: /* one-lease-per-client */
752 		comment = createComment("/// one-lease-per-client is not "
753 				       "supported");
754 		TAILQ_INSERT_TAIL(&comments, comment);
755 		comment = createComment("/// Reference Kea #238");
756 		TAILQ_INSERT_TAIL(&comments, comment);
757 		break;
758 
759 	case 11: /* get-lease-hostnames */
760 		comment = createComment("/// get-lease-hostnames is not "
761 				       "supported");
762 		TAILQ_INSERT_TAIL(&comments, comment);
763 		comment = createComment("/// Reference Kea #240");
764 		TAILQ_INSERT_TAIL(&comments, comment);
765 		break;
766 
767 	case 12: /* use-host-decl-names */
768 		comment = createComment("/// use-host-decl-names defaults "
769 				       "to always on");
770 		TAILQ_INSERT_TAIL(&comments, comment);
771 		break;
772 
773 	case 13: /* use-lease-addr-for-default-route */
774 		comment = createComment("/// use-lease-addr-for-default-route "
775 				       "is obsolete");
776 		TAILQ_INSERT_TAIL(&comments, comment);
777 		break;
778 
779 	case 14: /* min-secs */
780 		comment = createComment("/// min-secs is not (yet?) "
781 					"supported");
782 		TAILQ_INSERT_TAIL(&comments, comment);
783 		comment = createComment("/// Reference Kea #223");
784 		TAILQ_INSERT_TAIL(&comments, comment);
785 		break;
786 
787 	case 20: /* always-reply-rfc1048 */
788 		goto no_bootp;
789 
790 	case 22: /* always-broadcast */
791 		comment = createComment("/// always-broadcast is not "
792 				       "supported");
793 		TAILQ_INSERT_TAIL(&comments, comment);
794 		comment = createComment("/// Reference Kea #241");
795 		TAILQ_INSERT_TAIL(&comments, comment);
796 		break;
797 
798 	case 24: /* ddns-hostname */
799 		comment = createComment("/// ddns-hostname is not supported");
800 		TAILQ_INSERT_TAIL(&comments, comment);
801 		comment = createComment("/// Please use hostname in a "
802 				       "host reservation instead");
803 		TAILQ_INSERT_TAIL(&comments, comment);
804 		break;
805 
806 	case 25: /* ddns-rev-domainname */
807 		comment = createComment("/// ddns-rev-domainname is an "
808 				       "obsolete (so not supported) feature");
809 		TAILQ_INSERT_TAIL(&comments, comment);
810 		break;
811 
812 	case 26: /* lease-file-name */
813 		comment = createComment("/// lease-file-name is an internal "
814 				       "ISC DHCP feature");
815 		TAILQ_INSERT_TAIL(&comments, comment);
816                 break;
817 
818 	case 27: /* pid-file-name */
819 		comment = createComment("/// pid-file-nam is an internal "
820 				       "ISC DHCP feature");
821 		TAILQ_INSERT_TAIL(&comments, comment);
822 		break;
823 
824 	case 28: /* duplicates */
825 		comment = createComment("/// duplicates is not supported");
826 		TAILQ_INSERT_TAIL(&comments, comment);
827 		comment = createComment("/// Kea model is different (and "
828 				       "stricter)");
829 		TAILQ_INSERT_TAIL(&comments, comment);
830 		break;
831 
832 	case 29: /* declines */
833 		comment = createComment("/// declines is not supported");
834 		TAILQ_INSERT_TAIL(&comments, comment);
835                 comment = createComment("/// Kea honors decline messages "
836 				       " and holds address for "
837 				       "decline-probation-period");
838 		TAILQ_INSERT_TAIL(&comments, comment);
839 		break;
840 
841 	case 31: /* omapi-port */
842 		comment = createComment("/// omapi-port is an internal "
843 				       "ISC DHCP feature");
844                 TAILQ_INSERT_TAIL(&comments, comment);
845                 break;
846 
847 	case 32: /* local-port */
848 		comment = createComment("/// local-port is not supported");
849 		TAILQ_INSERT_TAIL(&comments, comment);
850 		comment = createComment("/// command line -p parameter "
851 				       "should be used instead");
852 		TAILQ_INSERT_TAIL(&comments, comment);
853                 break;
854 
855 	case 33: /* limited-broadcast-address */
856 		comment = createComment("/// limited-broadcast-address "
857 				       "is not (yet?) supported");
858 		TAILQ_INSERT_TAIL(&comments, comment);
859                 comment = createComment("/// Reference Kea #224");
860                 TAILQ_INSERT_TAIL(&comments, comment);
861                 break;
862 
863 	case 34: /* remote-port */
864 		comment = createComment("/// remote-port is a not portable "
865 				       "(so not supported) feature");
866 		TAILQ_INSERT_TAIL(&comments, comment);
867                 break;
868 
869 	case 35: /* local-address */
870 		comment = createComment("/// local-address is not supported");
871 		TAILQ_INSERT_TAIL(&comments, comment);
872 		comment = createComment("/// Kea equivalent feature is "
873 					"to specify an interface address");
874 		TAILQ_INSERT_TAIL(&comments, comment);
875 		break;
876 
877 	case 36: /* omapi-key */
878 		comment = createComment("/// omapi-key is an internal "
879 					"ISC DHCP feature");
880                 TAILQ_INSERT_TAIL(&comments, comment);
881 		break;
882 
883 	case 37: /* stash-agent-options */
884 		comment = createComment("/// stash-agent-options is not "
885 					"(yet?) supported");
886 		TAILQ_INSERT_TAIL(&comments, comment);
887 		comment = createComment("/// Reference Kea #218");
888                 TAILQ_INSERT_TAIL(&comments, comment);
889                 break;
890 
891 	case 38: /* ddns-ttl */
892 		comment = createComment("/// ddns-ttl is a D2 not (yet?) "
893 					"supported feature");
894 		TAILQ_INSERT_TAIL(&comments, comment);
895                 comment = createComment("/// Reference Kea #225");
896                 TAILQ_INSERT_TAIL(&comments, comment);
897                 break;
898 
899 	case 40: /* client-updates */
900 		comment = createComment("/// ddns-ttl client-updates is "
901 					"not supported");
902 		TAILQ_INSERT_TAIL(&comments, comment);
903 		comment = createComment("/// Kea model is very different");
904 		TAILQ_INSERT_TAIL(&comments, comment);
905 		break;
906 
907 	case 41: /* update-optimization */
908 		comment = createComment("/// update-optimization is not "
909 					"supported");
910 		TAILQ_INSERT_TAIL(&comments, comment);
911                 comment = createComment("/// Kea follows RFC 4702");
912 		TAILQ_INSERT_TAIL(&comments, comment);
913 		break;
914 
915 	case 42: /* ping-check */
916 		comment = createComment("/// ping-check is not supported");
917 		TAILQ_INSERT_TAIL(&comments, comment);
918 	no_ping:
919 		comment = createComment("/// Kea has no ping probing");
920 		TAILQ_INSERT_TAIL(&comments, comment);
921 		break;
922 
923 	case 43: /* update-static-leases */
924 		comment = createComment("/// update-static-leases is an "
925 					"obsolete feature");
926 		TAILQ_INSERT_TAIL(&comments, comment);
927 		break;
928 
929 	case 44: /* log-facility */
930 		comment = createComment("/// log-facility is not supported");
931 		TAILQ_INSERT_TAIL(&comments, comment);
932 		comment = createComment("/// Please use the "
933 					"KEA_LOGGER_DESTINATION environment "
934 					"variable instead");
935 		TAILQ_INSERT_TAIL(&comments, comment);
936 		break;
937 
938 	case 45: /* do-forward-updates */
939 		comment = createComment("/// do-forward-updates is not "
940 					"supported");
941 		TAILQ_INSERT_TAIL(&comments, comment);
942 	ddns_updates:
943 		comment = createComment("/// Kea model is equivalent but "
944 					"different");
945 		TAILQ_INSERT_TAIL(&comments, comment);
946 		break;
947 
948 	case 46: /* ping-timeout */
949 		comment = createComment("/// ping-timeout is not supported");
950 		TAILQ_INSERT_TAIL(&comments, comment);
951 		goto no_ping;
952 
953 	case 47: /* infinite-is-reserved */
954 		comment = createComment("/// infinite-is-reserved is not "
955 					"supported");
956 		TAILQ_INSERT_TAIL(&comments, comment);
957 		comment = createComment("/// Kea does not support reserved "
958 					"leases");
959 		TAILQ_INSERT_TAIL(&comments, comment);
960                 break;
961 
962 	case 48: /* update-conflict-detection */
963 		comment = createComment("/// update-conflict-detection is not "
964 					"supported");
965 		TAILQ_INSERT_TAIL(&comments, comment);
966 		comment = createComment("/// DDNS is handled by the D2 "
967 					"server using a dedicated config");
968 		TAILQ_INSERT_TAIL(&comments, comment);
969 		break;
970 
971 	case 49: /* leasequery */
972 		comment = createComment("/// leasequery is not supported");
973 		TAILQ_INSERT_TAIL(&comments, comment);
974 		comment = createComment("/// Kea does not (yet) support "
975 					"the leasequery protocol");
976 		TAILQ_INSERT_TAIL(&comments, comment);
977 		break;
978 
979 	case 50: /* adaptive-lease-time-threshold */
980 		comment = createComment("/// adaptive-lease-time-threshold is "
981 					"not supported");
982 		TAILQ_INSERT_TAIL(&comments, comment);
983 		comment = createComment("/// Reference Kea #226");
984 		TAILQ_INSERT_TAIL(&comments, comment);
985                 break;
986 
987 	case 51: /* do-reverse-updates */
988 		comment = createComment("/// do-reverse-updates is not "
989 					"supported");
990 		TAILQ_INSERT_TAIL(&comments, comment);
991 		goto ddns_updates;
992 
993 	case 52: /* fqdn-reply */
994 		comment = createComment("/// fqdn-reply is an obsolete "
995 					"feature");
996 		TAILQ_INSERT_TAIL(&comments, comment);
997 		break;
998 
999 	case 54: /* dhcpv6-lease-file-name */
1000 		comment = createComment("/// dhcpv6-lease-file-name "
1001 					"is an internal ISC DHCP feature");
1002                 TAILQ_INSERT_TAIL(&comments, comment);
1003                 break;
1004 
1005 	case 55: /* dhcpv6-pid-file-name */
1006 		comment = createComment("/// dhcpv6-pid-file-name "
1007                                         "is an internal ISC DHCP feature");
1008                 TAILQ_INSERT_TAIL(&comments, comment);
1009                 break;
1010 
1011 	case 56: /* limit-addrs-per-ia */
1012 		comment = createComment("/// limit-addrs-per-ia "
1013 					"is not (yet?) supported");
1014 		TAILQ_INSERT_TAIL(&comments, comment);
1015 	limit_resources:
1016 		comment = createComment("/// Reference Kea #227");
1017                 TAILQ_INSERT_TAIL(&comments, comment);
1018                 break;
1019 
1020 	case 57: /* limit-prefs-per-ia */
1021 		comment = createComment("/// limit-prefs-per-ia"
1022                                         "is not (yet?) supported");
1023                 TAILQ_INSERT_TAIL(&comments, comment);
1024 		goto limit_resources;
1025 
1026 	case 58: /* delayed-ack */
1027 	case 59: /* max-ack-delay */
1028 		comment = createComment("/// delayed ack no supported");
1029 		TAILQ_INSERT_TAIL(&comments, comment);
1030 		break;
1031 
1032 	case 78: /* dhcp-cache-threshold */
1033 		comment = createComment("/// dhcp-cache-threshold "
1034 					"is not (yet?) supported");
1035 		TAILQ_INSERT_TAIL(&comments, comment);
1036 		comment = createComment("/// Reference Kea #228");
1037                 TAILQ_INSERT_TAIL(&comments, comment);
1038                 break;
1039 
1040 	case 79: /* dont-use-fsync */
1041 		comment = createComment("/// dont-use-fsync is an internal "
1042 					"ISC DHCP feature");
1043                 TAILQ_INSERT_TAIL(&comments, comment);
1044                 break;
1045 
1046 	case 80: /* ddns-local-address4 */
1047 		comment = createComment("/// ddns-local-address4 is not "
1048 					"supported");
1049 		TAILQ_INSERT_TAIL(&comments, comment);
1050 	d2_ip_address:
1051 		comment = createComment("/// Kea D2 equivalent config is "
1052 					"ip-address");
1053 		TAILQ_INSERT_TAIL(&comments, comment);
1054 		break;
1055 
1056 	case 81: /* ddns-local-address6 */
1057 		comment = createComment("/// ddns-local-address6 is not "
1058 					"supported");
1059 		TAILQ_INSERT_TAIL(&comments, comment);
1060 		goto d2_ip_address;
1061 
1062 	case 83: /* log-threshold-low */
1063 		comment = createComment("/// log-threshold-low is not (yet?) "
1064 					"supported");
1065                 TAILQ_INSERT_TAIL(&comments, comment);
1066 	log_threshold:
1067 		comment = createComment("/// Reference Kea #222");
1068                 TAILQ_INSERT_TAIL(&comments, comment);
1069                 break;
1070 
1071 	case 84: /* log-threshold-high */
1072 		comment = createComment("/// log-threshold-high is not (yet?) "
1073                                         "supported");
1074                 TAILQ_INSERT_TAIL(&comments, comment);
1075 		goto log_threshold;
1076 
1077 	case 86: /* server-id-check */
1078 		comment = createComment("/// server-id-check is not (yet?) "
1079 					"supported");
1080 		TAILQ_INSERT_TAIL(&comments, comment);
1081 		comment = createComment("/// Reference Kea #242");
1082                 TAILQ_INSERT_TAIL(&comments, comment);
1083 		break;
1084 
1085 	case 87: /* prefix-length-mode */
1086 		comment = createComment("/// prefix-length-mode is not "
1087 					"supported");
1088 		TAILQ_INSERT_TAIL(&comments, comment);
1089 		comment = createComment("/// Kea model is different (and "
1090 					"simpler?)");
1091                 TAILQ_INSERT_TAIL(&comments, comment);
1092                 break;
1093 	case 88: /* dhcpv6-set-tee-times */
1094 		comment = createComment("/// dhcpv6-set-tee-times is a "
1095 					"transitional (so not supported) "
1096 					"feature");
1097 		TAILQ_INSERT_TAIL(&comments, comment);
1098 		comment = createComment("/// T1 and T2 are .5 and .8 times "
1099 					"preferred-lifetime");
1100 		TAILQ_INSERT_TAIL(&comments, comment);
1101 		break;
1102 	case 89: /* abandon-lease-time */
1103 		comment = createComment("/// abandon-lease-time is not "
1104 					"supported");
1105 		TAILQ_INSERT_TAIL(&comments, comment);
1106 		comment = createComment("/// Kea support equivalent (and "
1107 					"richer) expired-lease-processing "
1108 					"and decline-probation-period");
1109 		TAILQ_INSERT_TAIL(&comments, comment);
1110 		break;
1111 	case 90: /* use-eui-64 */
1112 		comment = createComment("/// EUI-64 is not (yet) supported");
1113 		TAILQ_INSERT_TAIL(&comments, comment);
1114 		comment = createComment("/// Reference Kea #265");
1115 		TAILQ_INSERT_TAIL(&comments, comment);
1116                 break;
1117 	case 96: /* release-on-roam */
1118 		comment = createComment("/// release-on-roam is not (yet) "
1119 					"supported");
1120 		TAILQ_INSERT_TAIL(&comments, comment);
1121 		comment = createComment("/// Reference Kea #266");
1122 		TAILQ_INSERT_TAIL(&comments, comment);
1123                 break;
1124 	case 97: /* local-address6 */
1125 		comment = createComment("/// local-address6 is not supported");
1126 		TAILQ_INSERT_TAIL(&comments, comment);
1127 		comment = createComment("/// Kea equivalent feature is "
1128 					"to specify an interface address");
1129 		TAILQ_INSERT_TAIL(&comments, comment);
1130 		break;
1131 	case 99: /* ping-cltt-secs */
1132 		comment = createComment("/// ping-cltt-secs is not supported");
1133 		TAILQ_INSERT_TAIL(&comments, comment);
1134 		goto no_ping;
1135 	case 100: /* ping-timeout-ms */
1136 		comment = createComment("/// ping-timeout-ms is not "
1137 					"supported");
1138 		TAILQ_INSERT_TAIL(&comments, comment);
1139 		goto no_ping;
1140 	}
1141 	return &comments;
1142 }
1143 
1144 const char *
display_status(enum option_status status)1145 display_status(enum option_status status)
1146 {
1147 	switch (status) {
1148 	case kea_unknown:
1149 	case special:
1150 		return "known (unknown)";
1151 	case isc_dhcp_unknown:
1152 		return "unknown (known)";
1153 	case known:
1154 		return "known (known)";
1155 	case dynamic:
1156 		return "dynamic (dynamic)";
1157 	default:
1158 		return "??? (" "???" ")";
1159 	}
1160 }
1161