Home | History | Annotate | Line # | Download | only in keama
      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 (at) 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
    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
    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 *
    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 *
    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 *
    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 *
    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
    647 push_space(struct space *space)
    648 {
    649 	space->status = dynamic;
    650 	TAILQ_INSERT_TAIL(&spaces, space);
    651 }
    652 
    653 void
    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
    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
    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 *
    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 *
   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