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 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