xref: /titanic_41/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_dhcpv6.c (revision ea42b017f4e2e37ffdb661c40eb5199d37cc25dc)
1d04ccbb3Scarlsonj /*
2d04ccbb3Scarlsonj  * CDDL HEADER START
3d04ccbb3Scarlsonj  *
4d04ccbb3Scarlsonj  * The contents of this file are subject to the terms of the
5d04ccbb3Scarlsonj  * Common Development and Distribution License (the "License").
6d04ccbb3Scarlsonj  * You may not use this file except in compliance with the License.
7d04ccbb3Scarlsonj  *
8d04ccbb3Scarlsonj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d04ccbb3Scarlsonj  * or http://www.opensolaris.org/os/licensing.
10d04ccbb3Scarlsonj  * See the License for the specific language governing permissions
11d04ccbb3Scarlsonj  * and limitations under the License.
12d04ccbb3Scarlsonj  *
13d04ccbb3Scarlsonj  * When distributing Covered Code, include this CDDL HEADER in each
14d04ccbb3Scarlsonj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d04ccbb3Scarlsonj  * If applicable, add the following below this CDDL HEADER, with the
16d04ccbb3Scarlsonj  * fields enclosed by brackets "[]" replaced with your own identifying
17d04ccbb3Scarlsonj  * information: Portions Copyright [yyyy] [name of copyright owner]
18d04ccbb3Scarlsonj  *
19d04ccbb3Scarlsonj  * CDDL HEADER END
20d04ccbb3Scarlsonj  */
21d04ccbb3Scarlsonj 
22d04ccbb3Scarlsonj /*
2336e852a1SRaja Andra  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24d04ccbb3Scarlsonj  * Use is subject to license terms.
25d04ccbb3Scarlsonj  */
26d04ccbb3Scarlsonj 
27d04ccbb3Scarlsonj /*
28d04ccbb3Scarlsonj  * Dynamic Host Configuration Protocol version 6, for IPv6.  Supports
29d04ccbb3Scarlsonj  * RFCs 3315, 3319, 3646, 3898, 4075, 4242, 4280, 4580, 4649, and 4704.
30d04ccbb3Scarlsonj  */
31d04ccbb3Scarlsonj 
32*ea42b017SDavid Höppner #include <ctype.h>
33d04ccbb3Scarlsonj #include <stdio.h>
34d04ccbb3Scarlsonj #include <stdlib.h>
35d04ccbb3Scarlsonj #include <string.h>
36d04ccbb3Scarlsonj #include <time.h>
37d04ccbb3Scarlsonj #include <sys/types.h>
38d04ccbb3Scarlsonj #include <sys/socket.h>
39d04ccbb3Scarlsonj #include <netinet/in.h>
40d04ccbb3Scarlsonj #include <netinet/dhcp6.h>
41d04ccbb3Scarlsonj #include <arpa/inet.h>
42d04ccbb3Scarlsonj #include <dhcp_impl.h>
43d04ccbb3Scarlsonj #include <dhcp_inittab.h>
44d04ccbb3Scarlsonj 
45d04ccbb3Scarlsonj #include "snoop.h"
46d04ccbb3Scarlsonj 
47d04ccbb3Scarlsonj static const char *mtype_to_str(uint8_t);
48d04ccbb3Scarlsonj static const char *option_to_str(uint8_t);
49d04ccbb3Scarlsonj static const char *duidtype_to_str(uint16_t);
50d04ccbb3Scarlsonj static const char *status_to_str(uint16_t);
51d04ccbb3Scarlsonj static const char *entr_to_str(uint32_t);
52d04ccbb3Scarlsonj static const char *reconf_to_str(uint8_t);
53d04ccbb3Scarlsonj static const char *authproto_to_str(uint8_t);
54d04ccbb3Scarlsonj static const char *authalg_to_str(uint8_t, uint8_t);
55d04ccbb3Scarlsonj static const char *authrdm_to_str(uint8_t);
56d04ccbb3Scarlsonj static const char *cwhat_to_str(uint8_t);
57d04ccbb3Scarlsonj static const char *catype_to_str(uint8_t);
58d04ccbb3Scarlsonj static void show_hex(const uint8_t *, int, const char *);
59d04ccbb3Scarlsonj static void show_ascii(const uint8_t *, int, const char *);
60d04ccbb3Scarlsonj static void show_address(const char *, const void *);
61d04ccbb3Scarlsonj static void show_options(const uint8_t *, int);
62d04ccbb3Scarlsonj 
63d04ccbb3Scarlsonj int
interpret_dhcpv6(int flags,const uint8_t * data,int len)64d04ccbb3Scarlsonj interpret_dhcpv6(int flags, const uint8_t *data, int len)
65d04ccbb3Scarlsonj {
66d04ccbb3Scarlsonj 	int olen = len;
67d04ccbb3Scarlsonj 	char *line, *lstart;
68d04ccbb3Scarlsonj 	dhcpv6_relay_t d6r;
69d04ccbb3Scarlsonj 	dhcpv6_message_t d6m;
70d04ccbb3Scarlsonj 	uint_t optlen;
71d04ccbb3Scarlsonj 	uint16_t statuscode;
72d04ccbb3Scarlsonj 
73d04ccbb3Scarlsonj 	if (len <= 0) {
74d04ccbb3Scarlsonj 		(void) strlcpy(get_sum_line(), "DHCPv6?", MAXLINE);
75d04ccbb3Scarlsonj 		return (0);
76d04ccbb3Scarlsonj 	}
77d04ccbb3Scarlsonj 	if (flags & F_SUM) {
78d04ccbb3Scarlsonj 		uint_t ias;
79d04ccbb3Scarlsonj 		dhcpv6_option_t *d6o;
80d04ccbb3Scarlsonj 		in6_addr_t link, peer;
81d04ccbb3Scarlsonj 		char linkstr[INET6_ADDRSTRLEN];
82d04ccbb3Scarlsonj 		char peerstr[INET6_ADDRSTRLEN];
83d04ccbb3Scarlsonj 
84d04ccbb3Scarlsonj 		line = lstart = get_sum_line();
85d04ccbb3Scarlsonj 		line += snprintf(line, MAXLINE, "DHCPv6 %s",
86d04ccbb3Scarlsonj 		    mtype_to_str(data[0]));
87d04ccbb3Scarlsonj 		if (data[0] == DHCPV6_MSG_RELAY_FORW ||
88d04ccbb3Scarlsonj 		    data[0] == DHCPV6_MSG_RELAY_REPL) {
89d04ccbb3Scarlsonj 			if (len < sizeof (d6r)) {
90d04ccbb3Scarlsonj 				(void) strlcpy(line, "?",
91d04ccbb3Scarlsonj 				    MAXLINE - (line - lstart));
92d04ccbb3Scarlsonj 				return (olen);
93d04ccbb3Scarlsonj 			}
94d04ccbb3Scarlsonj 			/* Not much in DHCPv6 is aligned. */
95d04ccbb3Scarlsonj 			(void) memcpy(&d6r, data, sizeof (d6r));
96d04ccbb3Scarlsonj 			(void) memcpy(&link, d6r.d6r_linkaddr, sizeof (link));
97d04ccbb3Scarlsonj 			(void) memcpy(&peer, d6r.d6r_peeraddr, sizeof (peer));
98d04ccbb3Scarlsonj 			line += snprintf(line, MAXLINE - (line - lstart),
99d04ccbb3Scarlsonj 			    " HC=%d link=%s peer=%s", d6r.d6r_hop_count,
100d04ccbb3Scarlsonj 			    inet_ntop(AF_INET6, &link, linkstr,
101d04ccbb3Scarlsonj 			    sizeof (linkstr)),
102d04ccbb3Scarlsonj 			    inet_ntop(AF_INET6, &peer, peerstr,
103d04ccbb3Scarlsonj 			    sizeof (peerstr)));
104d04ccbb3Scarlsonj 			data += sizeof (d6r);
105d04ccbb3Scarlsonj 			len -= sizeof (d6r);
106d04ccbb3Scarlsonj 		} else {
107d04ccbb3Scarlsonj 			if (len < sizeof (d6m)) {
108d04ccbb3Scarlsonj 				(void) strlcpy(line, "?",
109d04ccbb3Scarlsonj 				    MAXLINE - (line - lstart));
110d04ccbb3Scarlsonj 				return (olen);
111d04ccbb3Scarlsonj 			}
112d04ccbb3Scarlsonj 			(void) memcpy(&d6m, data, sizeof (d6m));
113d04ccbb3Scarlsonj 			line += snprintf(line, MAXLINE - (line - lstart),
114d04ccbb3Scarlsonj 			    " xid=%x", DHCPV6_GET_TRANSID(&d6m));
115d04ccbb3Scarlsonj 			data += sizeof (d6m);
116d04ccbb3Scarlsonj 			len -= sizeof (d6m);
117d04ccbb3Scarlsonj 		}
118d04ccbb3Scarlsonj 		ias = 0;
119d04ccbb3Scarlsonj 		d6o = NULL;
120d04ccbb3Scarlsonj 		while ((d6o = dhcpv6_find_option(data, len, d6o,
121d04ccbb3Scarlsonj 		    DHCPV6_OPT_IA_NA, NULL)) != NULL)
122d04ccbb3Scarlsonj 			ias++;
123d04ccbb3Scarlsonj 		if (ias > 0)
124d04ccbb3Scarlsonj 			line += snprintf(line, MAXLINE - (line - lstart),
125d04ccbb3Scarlsonj 			    " IAs=%u", ias);
126d04ccbb3Scarlsonj 		d6o = dhcpv6_find_option(data, len, NULL,
127d04ccbb3Scarlsonj 		    DHCPV6_OPT_STATUS_CODE, &optlen);
128d04ccbb3Scarlsonj 		optlen -= sizeof (*d6o);
129d04ccbb3Scarlsonj 		if (d6o != NULL && optlen >= sizeof (statuscode)) {
130d04ccbb3Scarlsonj 			(void) memcpy(&statuscode, d6o + 1,
131d04ccbb3Scarlsonj 			    sizeof (statuscode));
132d04ccbb3Scarlsonj 			line += snprintf(line, MAXLINE - (line - lstart),
133d04ccbb3Scarlsonj 			    " status=%u", ntohs(statuscode));
134d04ccbb3Scarlsonj 			optlen -= sizeof (statuscode);
135d04ccbb3Scarlsonj 			if (optlen > 0) {
136d04ccbb3Scarlsonj 				line += snprintf(line,
137d04ccbb3Scarlsonj 				    MAXLINE - (line - lstart), " \"%.*s\"",
138d04ccbb3Scarlsonj 				    optlen, (char *)(d6o + 1) + 2);
139d04ccbb3Scarlsonj 			}
140d04ccbb3Scarlsonj 		}
141d04ccbb3Scarlsonj 		d6o = dhcpv6_find_option(data, len, NULL,
142d04ccbb3Scarlsonj 		    DHCPV6_OPT_RELAY_MSG, &optlen);
143d04ccbb3Scarlsonj 		optlen -= sizeof (*d6o);
144d04ccbb3Scarlsonj 		if (d6o != NULL && optlen >= 1) {
145d04ccbb3Scarlsonj 			line += snprintf(line, MAXLINE - (line - lstart),
146d04ccbb3Scarlsonj 			    " relay=%s", mtype_to_str(*(uint8_t *)(d6o + 1)));
147d04ccbb3Scarlsonj 		}
148d04ccbb3Scarlsonj 	} else if (flags & F_DTAIL) {
149d04ccbb3Scarlsonj 		show_header("DHCPv6: ",
150d04ccbb3Scarlsonj 		    "Dynamic Host Configuration Protocol Version 6", len);
151d04ccbb3Scarlsonj 		show_space();
152d04ccbb3Scarlsonj 		(void) snprintf(get_line(0, 0), get_line_remain(),
153d04ccbb3Scarlsonj 		    "Message type (msg-type) = %u (%s)", data[0],
154d04ccbb3Scarlsonj 		    mtype_to_str(data[0]));
155d04ccbb3Scarlsonj 		if (data[0] == DHCPV6_MSG_RELAY_FORW ||
156d04ccbb3Scarlsonj 		    data[0] == DHCPV6_MSG_RELAY_REPL) {
157d04ccbb3Scarlsonj 			if (len < sizeof (d6r)) {
158d04ccbb3Scarlsonj 				(void) strlcpy(get_line(0, 0), "Truncated",
159d04ccbb3Scarlsonj 				    get_line_remain());
160d04ccbb3Scarlsonj 				return (olen);
161d04ccbb3Scarlsonj 			}
162d04ccbb3Scarlsonj 			(void) memcpy(&d6r, data, sizeof (d6r));
163d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
164d04ccbb3Scarlsonj 			    "Hop count = %u", d6r.d6r_hop_count);
165d04ccbb3Scarlsonj 			show_address("Link address", d6r.d6r_linkaddr);
166d04ccbb3Scarlsonj 			show_address("Peer address", d6r.d6r_peeraddr);
167d04ccbb3Scarlsonj 			data += sizeof (d6r);
168d04ccbb3Scarlsonj 			len -= sizeof (d6r);
169d04ccbb3Scarlsonj 		} else {
170d04ccbb3Scarlsonj 			if (len < sizeof (d6m)) {
171d04ccbb3Scarlsonj 				(void) strlcpy(get_line(0, 0), "Truncated",
172d04ccbb3Scarlsonj 				    get_line_remain());
173d04ccbb3Scarlsonj 				return (olen);
174d04ccbb3Scarlsonj 			}
175d04ccbb3Scarlsonj 			(void) memcpy(&d6m, data, sizeof (d6m));
176d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
177d04ccbb3Scarlsonj 			    "Transaction ID = %x", DHCPV6_GET_TRANSID(&d6m));
178d04ccbb3Scarlsonj 			data += sizeof (d6m);
179d04ccbb3Scarlsonj 			len -= sizeof (d6m);
180d04ccbb3Scarlsonj 		}
181d04ccbb3Scarlsonj 		show_space();
182d04ccbb3Scarlsonj 		show_options(data, len);
183d04ccbb3Scarlsonj 		show_space();
184d04ccbb3Scarlsonj 	}
185d04ccbb3Scarlsonj 	return (olen);
186d04ccbb3Scarlsonj }
187d04ccbb3Scarlsonj 
188d04ccbb3Scarlsonj static const char *
mtype_to_str(uint8_t mtype)189d04ccbb3Scarlsonj mtype_to_str(uint8_t mtype)
190d04ccbb3Scarlsonj {
191d04ccbb3Scarlsonj 	switch (mtype) {
192d04ccbb3Scarlsonj 	case DHCPV6_MSG_SOLICIT:
193d04ccbb3Scarlsonj 		return ("Solicit");
194d04ccbb3Scarlsonj 	case DHCPV6_MSG_ADVERTISE:
195d04ccbb3Scarlsonj 		return ("Advertise");
196d04ccbb3Scarlsonj 	case DHCPV6_MSG_REQUEST:
197d04ccbb3Scarlsonj 		return ("Request");
198d04ccbb3Scarlsonj 	case DHCPV6_MSG_CONFIRM:
199d04ccbb3Scarlsonj 		return ("Confirm");
200d04ccbb3Scarlsonj 	case DHCPV6_MSG_RENEW:
201d04ccbb3Scarlsonj 		return ("Renew");
202d04ccbb3Scarlsonj 	case DHCPV6_MSG_REBIND:
203d04ccbb3Scarlsonj 		return ("Rebind");
204d04ccbb3Scarlsonj 	case DHCPV6_MSG_REPLY:
205d04ccbb3Scarlsonj 		return ("Reply");
206d04ccbb3Scarlsonj 	case DHCPV6_MSG_RELEASE:
207d04ccbb3Scarlsonj 		return ("Release");
208d04ccbb3Scarlsonj 	case DHCPV6_MSG_DECLINE:
209d04ccbb3Scarlsonj 		return ("Decline");
210d04ccbb3Scarlsonj 	case DHCPV6_MSG_RECONFIGURE:
211d04ccbb3Scarlsonj 		return ("Reconfigure");
212d04ccbb3Scarlsonj 	case DHCPV6_MSG_INFO_REQ:
213d04ccbb3Scarlsonj 		return ("Information-Request");
214d04ccbb3Scarlsonj 	case DHCPV6_MSG_RELAY_FORW:
215d04ccbb3Scarlsonj 		return ("Relay-Forward");
216d04ccbb3Scarlsonj 	case DHCPV6_MSG_RELAY_REPL:
217d04ccbb3Scarlsonj 		return ("Relay-Reply");
218d04ccbb3Scarlsonj 	default:
219d04ccbb3Scarlsonj 		return ("Unknown");
220d04ccbb3Scarlsonj 	}
221d04ccbb3Scarlsonj }
222d04ccbb3Scarlsonj 
223d04ccbb3Scarlsonj static const char *
option_to_str(uint8_t mtype)224d04ccbb3Scarlsonj option_to_str(uint8_t mtype)
225d04ccbb3Scarlsonj {
226d04ccbb3Scarlsonj 	switch (mtype) {
227d04ccbb3Scarlsonj 	case DHCPV6_OPT_CLIENTID:
228d04ccbb3Scarlsonj 		return ("Client Identifier");
229d04ccbb3Scarlsonj 	case DHCPV6_OPT_SERVERID:
230d04ccbb3Scarlsonj 		return ("Server Identifier");
231d04ccbb3Scarlsonj 	case DHCPV6_OPT_IA_NA:
232d04ccbb3Scarlsonj 		return ("Identity Association for Non-temporary Addresses");
233d04ccbb3Scarlsonj 	case DHCPV6_OPT_IA_TA:
234d04ccbb3Scarlsonj 		return ("Identity Association for Temporary Addresses");
235d04ccbb3Scarlsonj 	case DHCPV6_OPT_IAADDR:
236d04ccbb3Scarlsonj 		return ("IA Address");
237d04ccbb3Scarlsonj 	case DHCPV6_OPT_ORO:
238d04ccbb3Scarlsonj 		return ("Option Request");
239d04ccbb3Scarlsonj 	case DHCPV6_OPT_PREFERENCE:
240d04ccbb3Scarlsonj 		return ("Preference");
241d04ccbb3Scarlsonj 	case DHCPV6_OPT_ELAPSED_TIME:
242d04ccbb3Scarlsonj 		return ("Elapsed Time");
243d04ccbb3Scarlsonj 	case DHCPV6_OPT_RELAY_MSG:
244d04ccbb3Scarlsonj 		return ("Relay Message");
245d04ccbb3Scarlsonj 	case DHCPV6_OPT_AUTH:
246d04ccbb3Scarlsonj 		return ("Authentication");
247d04ccbb3Scarlsonj 	case DHCPV6_OPT_UNICAST:
248d04ccbb3Scarlsonj 		return ("Server Unicast");
249d04ccbb3Scarlsonj 	case DHCPV6_OPT_STATUS_CODE:
250d04ccbb3Scarlsonj 		return ("Status Code");
251d04ccbb3Scarlsonj 	case DHCPV6_OPT_RAPID_COMMIT:
252d04ccbb3Scarlsonj 		return ("Rapid Commit");
253d04ccbb3Scarlsonj 	case DHCPV6_OPT_USER_CLASS:
254d04ccbb3Scarlsonj 		return ("User Class");
255d04ccbb3Scarlsonj 	case DHCPV6_OPT_VENDOR_CLASS:
256d04ccbb3Scarlsonj 		return ("Vendor Class");
257d04ccbb3Scarlsonj 	case DHCPV6_OPT_VENDOR_OPT:
258d04ccbb3Scarlsonj 		return ("Vendor-specific Information");
259d04ccbb3Scarlsonj 	case DHCPV6_OPT_INTERFACE_ID:
260d04ccbb3Scarlsonj 		return ("Interface-Id");
261d04ccbb3Scarlsonj 	case DHCPV6_OPT_RECONF_MSG:
262d04ccbb3Scarlsonj 		return ("Reconfigure Message");
263d04ccbb3Scarlsonj 	case DHCPV6_OPT_RECONF_ACC:
264d04ccbb3Scarlsonj 		return ("Reconfigure Accept");
265d04ccbb3Scarlsonj 	case DHCPV6_OPT_SIP_NAMES:
266d04ccbb3Scarlsonj 		return ("SIP Servers Domain Name List");
267d04ccbb3Scarlsonj 	case DHCPV6_OPT_SIP_ADDR:
268d04ccbb3Scarlsonj 		return ("SIP Servers IPv6 Address List");
269d04ccbb3Scarlsonj 	case DHCPV6_OPT_DNS_ADDR:
270d04ccbb3Scarlsonj 		return ("DNS Recursive Name Server");
271d04ccbb3Scarlsonj 	case DHCPV6_OPT_DNS_SEARCH:
272d04ccbb3Scarlsonj 		return ("Domain Search List");
273d04ccbb3Scarlsonj 	case DHCPV6_OPT_IA_PD:
274d04ccbb3Scarlsonj 		return ("Identity Association for Prefix Delegation");
275d04ccbb3Scarlsonj 	case DHCPV6_OPT_IAPREFIX:
276d04ccbb3Scarlsonj 		return ("IA_PD Prefix");
277d04ccbb3Scarlsonj 	case DHCPV6_OPT_NIS_SERVERS:
278d04ccbb3Scarlsonj 		return ("Network Information Service Servers");
279d04ccbb3Scarlsonj 	case DHCPV6_OPT_NIS_DOMAIN:
280d04ccbb3Scarlsonj 		return ("Network Information Service Domain Name");
281d04ccbb3Scarlsonj 	case DHCPV6_OPT_SNTP_SERVERS:
282d04ccbb3Scarlsonj 		return ("Simple Network Time Protocol Servers");
283d04ccbb3Scarlsonj 	case DHCPV6_OPT_INFO_REFTIME:
284d04ccbb3Scarlsonj 		return ("Information Refresh Time");
285d04ccbb3Scarlsonj 	case DHCPV6_OPT_BCMCS_SRV_D:
286d04ccbb3Scarlsonj 		return ("BCMCS Controller Domain Name List");
287d04ccbb3Scarlsonj 	case DHCPV6_OPT_BCMCS_SRV_A:
288d04ccbb3Scarlsonj 		return ("BCMCS Controller IPv6 Address");
289d04ccbb3Scarlsonj 	case DHCPV6_OPT_GEOCONF_CVC:
290d04ccbb3Scarlsonj 		return ("Civic Location");
291d04ccbb3Scarlsonj 	case DHCPV6_OPT_REMOTE_ID:
292d04ccbb3Scarlsonj 		return ("Relay Agent Remote-ID");
293d04ccbb3Scarlsonj 	case DHCPV6_OPT_SUBSCRIBER:
294d04ccbb3Scarlsonj 		return ("Relay Agent Subscriber-ID");
295d04ccbb3Scarlsonj 	case DHCPV6_OPT_CLIENT_FQDN:
296d04ccbb3Scarlsonj 		return ("Client FQDN");
297d04ccbb3Scarlsonj 	default:
298d04ccbb3Scarlsonj 		return ("Unknown");
299d04ccbb3Scarlsonj 	}
300d04ccbb3Scarlsonj }
301d04ccbb3Scarlsonj 
302d04ccbb3Scarlsonj static const char *
duidtype_to_str(uint16_t dtype)303d04ccbb3Scarlsonj duidtype_to_str(uint16_t dtype)
304d04ccbb3Scarlsonj {
305d04ccbb3Scarlsonj 	switch (dtype) {
306d04ccbb3Scarlsonj 	case DHCPV6_DUID_LLT:
307d04ccbb3Scarlsonj 		return ("Link-layer Address Plus Time");
308d04ccbb3Scarlsonj 	case DHCPV6_DUID_EN:
309d04ccbb3Scarlsonj 		return ("Enterprise Number");
310d04ccbb3Scarlsonj 	case DHCPV6_DUID_LL:
311d04ccbb3Scarlsonj 		return ("Link-layer Address");
312d04ccbb3Scarlsonj 	default:
313d04ccbb3Scarlsonj 		return ("Unknown");
314d04ccbb3Scarlsonj 	}
315d04ccbb3Scarlsonj }
316d04ccbb3Scarlsonj 
317d04ccbb3Scarlsonj static const char *
status_to_str(uint16_t status)318d04ccbb3Scarlsonj status_to_str(uint16_t status)
319d04ccbb3Scarlsonj {
320d04ccbb3Scarlsonj 	switch (status) {
321d04ccbb3Scarlsonj 	case DHCPV6_STAT_SUCCESS:
322d04ccbb3Scarlsonj 		return ("Success");
323d04ccbb3Scarlsonj 	case DHCPV6_STAT_UNSPECFAIL:
324d04ccbb3Scarlsonj 		return ("Failure, reason unspecified");
325d04ccbb3Scarlsonj 	case DHCPV6_STAT_NOADDRS:
326d04ccbb3Scarlsonj 		return ("No addresses for IAs");
327d04ccbb3Scarlsonj 	case DHCPV6_STAT_NOBINDING:
328d04ccbb3Scarlsonj 		return ("Client binding unavailable");
329d04ccbb3Scarlsonj 	case DHCPV6_STAT_NOTONLINK:
330d04ccbb3Scarlsonj 		return ("Prefix not on link");
331d04ccbb3Scarlsonj 	case DHCPV6_STAT_USEMCAST:
332d04ccbb3Scarlsonj 		return ("Use multicast");
333d04ccbb3Scarlsonj 	case DHCPV6_STAT_NOPREFIX:
334d04ccbb3Scarlsonj 		return ("No prefix available");
335d04ccbb3Scarlsonj 	default:
336d04ccbb3Scarlsonj 		return ("Unknown");
337d04ccbb3Scarlsonj 	}
338d04ccbb3Scarlsonj }
339d04ccbb3Scarlsonj 
340d04ccbb3Scarlsonj static const char *
entr_to_str(uint32_t entr)341d04ccbb3Scarlsonj entr_to_str(uint32_t entr)
342d04ccbb3Scarlsonj {
343d04ccbb3Scarlsonj 	switch (entr) {
344d04ccbb3Scarlsonj 	case DHCPV6_SUN_ENT:
345d04ccbb3Scarlsonj 		return ("Sun Microsystems");
346d04ccbb3Scarlsonj 	default:
347d04ccbb3Scarlsonj 		return ("Unknown");
348d04ccbb3Scarlsonj 	}
349d04ccbb3Scarlsonj }
350d04ccbb3Scarlsonj 
351d04ccbb3Scarlsonj static const char *
reconf_to_str(uint8_t msgtype)352d04ccbb3Scarlsonj reconf_to_str(uint8_t msgtype)
353d04ccbb3Scarlsonj {
354d04ccbb3Scarlsonj 	switch (msgtype) {
355d04ccbb3Scarlsonj 	case DHCPV6_RECONF_RENEW:
356d04ccbb3Scarlsonj 		return ("Renew");
357d04ccbb3Scarlsonj 	case DHCPV6_RECONF_INFO:
358d04ccbb3Scarlsonj 		return ("Information-request");
359d04ccbb3Scarlsonj 	default:
360d04ccbb3Scarlsonj 		return ("Unknown");
361d04ccbb3Scarlsonj 	}
362d04ccbb3Scarlsonj }
363d04ccbb3Scarlsonj 
364d04ccbb3Scarlsonj static const char *
authproto_to_str(uint8_t aproto)365d04ccbb3Scarlsonj authproto_to_str(uint8_t aproto)
366d04ccbb3Scarlsonj {
367d04ccbb3Scarlsonj 	switch (aproto) {
368d04ccbb3Scarlsonj 	case DHCPV6_PROTO_DELAYED:
369d04ccbb3Scarlsonj 		return ("Delayed");
370d04ccbb3Scarlsonj 	case DHCPV6_PROTO_RECONFIG:
371d04ccbb3Scarlsonj 		return ("Reconfigure Key");
372d04ccbb3Scarlsonj 	default:
373d04ccbb3Scarlsonj 		return ("Unknown");
374d04ccbb3Scarlsonj 	}
375d04ccbb3Scarlsonj }
376d04ccbb3Scarlsonj 
377d04ccbb3Scarlsonj static const char *
authalg_to_str(uint8_t aproto,uint8_t aalg)378d04ccbb3Scarlsonj authalg_to_str(uint8_t aproto, uint8_t aalg)
379d04ccbb3Scarlsonj {
380d04ccbb3Scarlsonj 	switch (aproto) {
381d04ccbb3Scarlsonj 	case DHCPV6_PROTO_DELAYED:
382d04ccbb3Scarlsonj 	case DHCPV6_PROTO_RECONFIG:
383d04ccbb3Scarlsonj 		switch (aalg) {
384d04ccbb3Scarlsonj 		case DHCPV6_ALG_HMAC_MD5:
385d04ccbb3Scarlsonj 			return ("HMAC-MD5 Signature");
386d04ccbb3Scarlsonj 		default:
387d04ccbb3Scarlsonj 			return ("Unknown");
388d04ccbb3Scarlsonj 		}
389d04ccbb3Scarlsonj 		break;
390d04ccbb3Scarlsonj 	default:
391d04ccbb3Scarlsonj 		return ("Unknown");
392d04ccbb3Scarlsonj 	}
393d04ccbb3Scarlsonj }
394d04ccbb3Scarlsonj 
395d04ccbb3Scarlsonj static const char *
authrdm_to_str(uint8_t ardm)396d04ccbb3Scarlsonj authrdm_to_str(uint8_t ardm)
397d04ccbb3Scarlsonj {
398d04ccbb3Scarlsonj 	switch (ardm) {
399d04ccbb3Scarlsonj 	case DHCPV6_RDM_MONOCNT:
400d04ccbb3Scarlsonj 		return ("Monotonic Counter");
401d04ccbb3Scarlsonj 	default:
402d04ccbb3Scarlsonj 		return ("Unknown");
403d04ccbb3Scarlsonj 	}
404d04ccbb3Scarlsonj }
405d04ccbb3Scarlsonj 
406d04ccbb3Scarlsonj static const char *
cwhat_to_str(uint8_t what)407d04ccbb3Scarlsonj cwhat_to_str(uint8_t what)
408d04ccbb3Scarlsonj {
409d04ccbb3Scarlsonj 	switch (what) {
410d04ccbb3Scarlsonj 	case DHCPV6_CWHAT_SERVER:
411d04ccbb3Scarlsonj 		return ("Server");
412d04ccbb3Scarlsonj 	case DHCPV6_CWHAT_NETWORK:
413d04ccbb3Scarlsonj 		return ("Network");
414d04ccbb3Scarlsonj 	case DHCPV6_CWHAT_CLIENT:
415d04ccbb3Scarlsonj 		return ("Client");
416d04ccbb3Scarlsonj 	default:
417d04ccbb3Scarlsonj 		return ("Unknown");
418d04ccbb3Scarlsonj 	}
419d04ccbb3Scarlsonj }
420d04ccbb3Scarlsonj 
421d04ccbb3Scarlsonj static const char *
catype_to_str(uint8_t catype)422d04ccbb3Scarlsonj catype_to_str(uint8_t catype)
423d04ccbb3Scarlsonj {
424d04ccbb3Scarlsonj 	switch (catype) {
425d04ccbb3Scarlsonj 	case CIVICADDR_LANG:
426d04ccbb3Scarlsonj 		return ("Language; RFC 2277");
427d04ccbb3Scarlsonj 	case CIVICADDR_A1:
428d04ccbb3Scarlsonj 		return ("National division (state)");
429d04ccbb3Scarlsonj 	case CIVICADDR_A2:
430d04ccbb3Scarlsonj 		return ("County");
431d04ccbb3Scarlsonj 	case CIVICADDR_A3:
432d04ccbb3Scarlsonj 		return ("City");
433d04ccbb3Scarlsonj 	case CIVICADDR_A4:
434d04ccbb3Scarlsonj 		return ("City division");
435d04ccbb3Scarlsonj 	case CIVICADDR_A5:
436d04ccbb3Scarlsonj 		return ("Neighborhood");
437d04ccbb3Scarlsonj 	case CIVICADDR_A6:
438d04ccbb3Scarlsonj 		return ("Street group");
439d04ccbb3Scarlsonj 	case CIVICADDR_PRD:
440d04ccbb3Scarlsonj 		return ("Leading street direction");
441d04ccbb3Scarlsonj 	case CIVICADDR_POD:
442d04ccbb3Scarlsonj 		return ("Trailing street suffix");
443d04ccbb3Scarlsonj 	case CIVICADDR_STS:
444d04ccbb3Scarlsonj 		return ("Street suffix or type");
445d04ccbb3Scarlsonj 	case CIVICADDR_HNO:
446d04ccbb3Scarlsonj 		return ("House number");
447d04ccbb3Scarlsonj 	case CIVICADDR_HNS:
448d04ccbb3Scarlsonj 		return ("House number suffix");
449d04ccbb3Scarlsonj 	case CIVICADDR_LMK:
450d04ccbb3Scarlsonj 		return ("Landmark");
451d04ccbb3Scarlsonj 	case CIVICADDR_LOC:
452d04ccbb3Scarlsonj 		return ("Additional location information");
453d04ccbb3Scarlsonj 	case CIVICADDR_NAM:
454d04ccbb3Scarlsonj 		return ("Name/occupant");
455d04ccbb3Scarlsonj 	case CIVICADDR_PC:
456d04ccbb3Scarlsonj 		return ("Postal Code/ZIP");
457d04ccbb3Scarlsonj 	case CIVICADDR_BLD:
458d04ccbb3Scarlsonj 		return ("Building");
459d04ccbb3Scarlsonj 	case CIVICADDR_UNIT:
460d04ccbb3Scarlsonj 		return ("Unit/apt/suite");
461d04ccbb3Scarlsonj 	case CIVICADDR_FLR:
462d04ccbb3Scarlsonj 		return ("Floor");
463d04ccbb3Scarlsonj 	case CIVICADDR_ROOM:
464d04ccbb3Scarlsonj 		return ("Room number");
465d04ccbb3Scarlsonj 	case CIVICADDR_TYPE:
466d04ccbb3Scarlsonj 		return ("Place type");
467d04ccbb3Scarlsonj 	case CIVICADDR_PCN:
468d04ccbb3Scarlsonj 		return ("Postal community name");
469d04ccbb3Scarlsonj 	case CIVICADDR_POBOX:
470d04ccbb3Scarlsonj 		return ("Post office box");
471d04ccbb3Scarlsonj 	case CIVICADDR_ADDL:
472d04ccbb3Scarlsonj 		return ("Additional code");
473d04ccbb3Scarlsonj 	case CIVICADDR_SEAT:
474d04ccbb3Scarlsonj 		return ("Seat/desk");
475d04ccbb3Scarlsonj 	case CIVICADDR_ROAD:
476d04ccbb3Scarlsonj 		return ("Primary road or street");
477d04ccbb3Scarlsonj 	case CIVICADDR_RSEC:
478d04ccbb3Scarlsonj 		return ("Road section");
479d04ccbb3Scarlsonj 	case CIVICADDR_RBRA:
480d04ccbb3Scarlsonj 		return ("Road branch");
481d04ccbb3Scarlsonj 	case CIVICADDR_RSBR:
482d04ccbb3Scarlsonj 		return ("Road sub-branch");
483d04ccbb3Scarlsonj 	case CIVICADDR_SPRE:
484d04ccbb3Scarlsonj 		return ("Street name pre-modifier");
485d04ccbb3Scarlsonj 	case CIVICADDR_SPOST:
486d04ccbb3Scarlsonj 		return ("Street name post-modifier");
487d04ccbb3Scarlsonj 	case CIVICADDR_SCRIPT:
488d04ccbb3Scarlsonj 		return ("Script");
489d04ccbb3Scarlsonj 	default:
490d04ccbb3Scarlsonj 		return ("Unknown");
491d04ccbb3Scarlsonj 	}
492d04ccbb3Scarlsonj }
493d04ccbb3Scarlsonj 
494d04ccbb3Scarlsonj static void
show_hex(const uint8_t * data,int len,const char * name)495d04ccbb3Scarlsonj show_hex(const uint8_t *data, int len, const char *name)
496d04ccbb3Scarlsonj {
497d04ccbb3Scarlsonj 	char buffer[16 * 3 + 1];
498d04ccbb3Scarlsonj 	int nlen;
499d04ccbb3Scarlsonj 	int i;
500d04ccbb3Scarlsonj 	char sep;
501d04ccbb3Scarlsonj 
502d04ccbb3Scarlsonj 	nlen = strlen(name);
503d04ccbb3Scarlsonj 	sep = '=';
504d04ccbb3Scarlsonj 	while (len > 0) {
505d04ccbb3Scarlsonj 		for (i = 0; i < 16 && i < len; i++)
506d04ccbb3Scarlsonj 			(void) snprintf(buffer + 3 * i, 4, " %02x", *data++);
507d04ccbb3Scarlsonj 		(void) snprintf(get_line(0, 0), get_line_remain(), "%*s %c%s",
508d04ccbb3Scarlsonj 		    nlen, name, sep, buffer);
509d04ccbb3Scarlsonj 		name = "";
510d04ccbb3Scarlsonj 		sep = ' ';
511d04ccbb3Scarlsonj 		len -= i;
512d04ccbb3Scarlsonj 	}
513d04ccbb3Scarlsonj }
514d04ccbb3Scarlsonj 
515d04ccbb3Scarlsonj static void
show_ascii(const uint8_t * data,int len,const char * name)516d04ccbb3Scarlsonj show_ascii(const uint8_t *data, int len, const char *name)
517d04ccbb3Scarlsonj {
518d04ccbb3Scarlsonj 	char buffer[64], *bp;
519d04ccbb3Scarlsonj 	int nlen;
520d04ccbb3Scarlsonj 	int i;
521d04ccbb3Scarlsonj 	char sep;
522d04ccbb3Scarlsonj 
523d04ccbb3Scarlsonj 	nlen = strlen(name);
524d04ccbb3Scarlsonj 	sep = '=';
525d04ccbb3Scarlsonj 	while (len > 0) {
526d04ccbb3Scarlsonj 		bp = buffer;
527d04ccbb3Scarlsonj 		for (i = 0; i < sizeof (buffer) - 4 && len > 0; len--) {
528d04ccbb3Scarlsonj 			if (!isascii(*data) || !isprint(*data))
529d04ccbb3Scarlsonj 				bp += snprintf(bp, 5, "\\%03o", *data++);
530d04ccbb3Scarlsonj 			else
531d04ccbb3Scarlsonj 				*bp++;
532d04ccbb3Scarlsonj 		}
533d04ccbb3Scarlsonj 		*bp = '\0';
534d04ccbb3Scarlsonj 		(void) snprintf(get_line(0, 0), get_line_remain(),
535d04ccbb3Scarlsonj 		    "%*s %c \"%s\"", nlen, name, sep, buffer);
536d04ccbb3Scarlsonj 		sep = ' ';
537d04ccbb3Scarlsonj 		name = "";
538d04ccbb3Scarlsonj 	}
539d04ccbb3Scarlsonj }
540d04ccbb3Scarlsonj 
541d04ccbb3Scarlsonj static void
show_address(const char * addrname,const void * aptr)542d04ccbb3Scarlsonj show_address(const char *addrname, const void *aptr)
543d04ccbb3Scarlsonj {
544d04ccbb3Scarlsonj 	char *hname;
545d04ccbb3Scarlsonj 	char addrstr[INET6_ADDRSTRLEN];
546d04ccbb3Scarlsonj 	in6_addr_t addr;
547d04ccbb3Scarlsonj 
548d04ccbb3Scarlsonj 	(void) memcpy(&addr, aptr, sizeof (in6_addr_t));
549d04ccbb3Scarlsonj 	(void) inet_ntop(AF_INET6, &addr, addrstr, sizeof (addrstr));
550d04ccbb3Scarlsonj 	hname = addrtoname(AF_INET6, &addr);
551d04ccbb3Scarlsonj 	if (strcmp(hname, addrstr) == 0) {
552d04ccbb3Scarlsonj 		(void) snprintf(get_line(0, 0), get_line_remain(), "%s = %s",
553d04ccbb3Scarlsonj 		    addrname, addrstr);
554d04ccbb3Scarlsonj 	} else {
555d04ccbb3Scarlsonj 		(void) snprintf(get_line(0, 0), get_line_remain(),
556d04ccbb3Scarlsonj 		    "%s = %s (%s)", addrname, addrstr, hname);
557d04ccbb3Scarlsonj 	}
558d04ccbb3Scarlsonj }
559d04ccbb3Scarlsonj 
560d04ccbb3Scarlsonj static void
nest_options(const uint8_t * data,uint_t olen,char * prefix,char * title)561d04ccbb3Scarlsonj nest_options(const uint8_t *data, uint_t olen, char *prefix, char *title)
562d04ccbb3Scarlsonj {
563d04ccbb3Scarlsonj 	char *str, *oldnest, *oldprefix;
564d04ccbb3Scarlsonj 
565d04ccbb3Scarlsonj 	if (olen <= 0)
566d04ccbb3Scarlsonj 		return;
567d04ccbb3Scarlsonj 	oldprefix = prot_prefix;
568d04ccbb3Scarlsonj 	oldnest = prot_nest_prefix;
569d04ccbb3Scarlsonj 	str = malloc(strlen(prot_nest_prefix) + strlen(prot_prefix) + 1);
570d04ccbb3Scarlsonj 	if (str == NULL) {
571d04ccbb3Scarlsonj 		prot_nest_prefix = prot_prefix;
572d04ccbb3Scarlsonj 	} else {
573d04ccbb3Scarlsonj 		(void) sprintf(str, "%s%s", prot_nest_prefix, prot_prefix);
574d04ccbb3Scarlsonj 		prot_nest_prefix = str;
575d04ccbb3Scarlsonj 	}
576d04ccbb3Scarlsonj 	show_header(prefix, title, 0);
577d04ccbb3Scarlsonj 	show_options(data, olen);
578d04ccbb3Scarlsonj 	free(str);
579d04ccbb3Scarlsonj 	prot_prefix = oldprefix;
580d04ccbb3Scarlsonj 	prot_nest_prefix = oldnest;
581d04ccbb3Scarlsonj }
582d04ccbb3Scarlsonj 
583d04ccbb3Scarlsonj static void
show_options(const uint8_t * data,int len)584d04ccbb3Scarlsonj show_options(const uint8_t *data, int len)
585d04ccbb3Scarlsonj {
586d04ccbb3Scarlsonj 	dhcpv6_option_t d6o;
587d04ccbb3Scarlsonj 	uint_t olen, retlen;
588d04ccbb3Scarlsonj 	uint16_t val16;
589d04ccbb3Scarlsonj 	uint16_t type;
590d04ccbb3Scarlsonj 	uint32_t val32;
591d04ccbb3Scarlsonj 	const uint8_t *ostart;
592d04ccbb3Scarlsonj 	char *str, *sp;
593d04ccbb3Scarlsonj 	char *oldnest;
594d04ccbb3Scarlsonj 
595d04ccbb3Scarlsonj 	/*
596d04ccbb3Scarlsonj 	 * Be very careful with negative numbers; ANSI signed/unsigned
597d04ccbb3Scarlsonj 	 * comparison doesn't work as expected.
598d04ccbb3Scarlsonj 	 */
599d04ccbb3Scarlsonj 	while (len >= (signed)sizeof (d6o)) {
600d04ccbb3Scarlsonj 		(void) memcpy(&d6o, data, sizeof (d6o));
601d04ccbb3Scarlsonj 		d6o.d6o_code = ntohs(d6o.d6o_code);
602d04ccbb3Scarlsonj 		d6o.d6o_len = olen = ntohs(d6o.d6o_len);
603d04ccbb3Scarlsonj 		(void) snprintf(get_line(0, 0), get_line_remain(),
604d04ccbb3Scarlsonj 		    "Option Code = %u (%s)", d6o.d6o_code,
605d04ccbb3Scarlsonj 		    option_to_str(d6o.d6o_code));
606d04ccbb3Scarlsonj 		ostart = data += sizeof (d6o);
607d04ccbb3Scarlsonj 		len -= sizeof (d6o);
608d04ccbb3Scarlsonj 		if (olen > len) {
609d04ccbb3Scarlsonj 			(void) strlcpy(get_line(0, 0), "Option truncated",
610d04ccbb3Scarlsonj 			    get_line_remain());
611d04ccbb3Scarlsonj 			olen = len;
612d04ccbb3Scarlsonj 		}
613d04ccbb3Scarlsonj 		switch (d6o.d6o_code) {
614d04ccbb3Scarlsonj 		case DHCPV6_OPT_CLIENTID:
615d04ccbb3Scarlsonj 		case DHCPV6_OPT_SERVERID:
616d04ccbb3Scarlsonj 			if (olen < sizeof (val16))
617d04ccbb3Scarlsonj 				break;
618d04ccbb3Scarlsonj 			(void) memcpy(&val16, data, sizeof (val16));
619d04ccbb3Scarlsonj 			data += sizeof (val16);
620d04ccbb3Scarlsonj 			olen -= sizeof (val16);
621d04ccbb3Scarlsonj 			type = ntohs(val16);
622d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
623d04ccbb3Scarlsonj 			    "  DUID Type = %u (%s)", type,
624d04ccbb3Scarlsonj 			    duidtype_to_str(type));
625d04ccbb3Scarlsonj 			if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) {
626d04ccbb3Scarlsonj 				if (olen < sizeof (val16))
627d04ccbb3Scarlsonj 					break;
628d04ccbb3Scarlsonj 				(void) memcpy(&val16, data, sizeof (val16));
629d04ccbb3Scarlsonj 				data += sizeof (val16);
630d04ccbb3Scarlsonj 				olen -= sizeof (val16);
631d04ccbb3Scarlsonj 				val16 = ntohs(val16);
632d04ccbb3Scarlsonj 				(void) snprintf(get_line(0, 0),
633d04ccbb3Scarlsonj 				    get_line_remain(),
634d04ccbb3Scarlsonj 				    "  Hardware Type = %u (%s)", val16,
635*ea42b017SDavid Höppner 				    arp_htype(val16));
636d04ccbb3Scarlsonj 			}
637d04ccbb3Scarlsonj 			if (type == DHCPV6_DUID_LLT) {
638d04ccbb3Scarlsonj 				time_t timevalue;
639d04ccbb3Scarlsonj 
640d04ccbb3Scarlsonj 				if (olen < sizeof (val32))
641d04ccbb3Scarlsonj 					break;
642d04ccbb3Scarlsonj 				(void) memcpy(&val32, data, sizeof (val32));
643d04ccbb3Scarlsonj 				data += sizeof (val32);
644d04ccbb3Scarlsonj 				olen -= sizeof (val32);
645d04ccbb3Scarlsonj 				timevalue = ntohl(val32) + DUID_TIME_BASE;
646d04ccbb3Scarlsonj 				(void) snprintf(get_line(0, 0),
647d04ccbb3Scarlsonj 				    get_line_remain(),
648d04ccbb3Scarlsonj 				    "  Time = %lu (%.24s)", ntohl(val32),
649d04ccbb3Scarlsonj 				    ctime(&timevalue));
650d04ccbb3Scarlsonj 			}
651d04ccbb3Scarlsonj 			if (type == DHCPV6_DUID_EN) {
652d04ccbb3Scarlsonj 				if (olen < sizeof (val32))
653d04ccbb3Scarlsonj 					break;
654d04ccbb3Scarlsonj 				(void) memcpy(&val32, data, sizeof (val32));
655d04ccbb3Scarlsonj 				data += sizeof (val32);
656d04ccbb3Scarlsonj 				olen -= sizeof (val32);
657d04ccbb3Scarlsonj 				val32 = ntohl(val32);
658d04ccbb3Scarlsonj 				(void) snprintf(get_line(0, 0),
659d04ccbb3Scarlsonj 				    get_line_remain(),
660d04ccbb3Scarlsonj 				    "  Enterprise Number = %lu (%s)", val32,
661d04ccbb3Scarlsonj 				    entr_to_str(val32));
662d04ccbb3Scarlsonj 			}
663d04ccbb3Scarlsonj 			if (olen == 0)
664d04ccbb3Scarlsonj 				break;
665d04ccbb3Scarlsonj 			if ((str = malloc(olen * 3)) == NULL)
666d04ccbb3Scarlsonj 				pr_err("interpret_dhcpv6: no mem");
667d04ccbb3Scarlsonj 			sp = str + snprintf(str, 3, "%02x", *data++);
668d04ccbb3Scarlsonj 			while (--olen > 0) {
669d04ccbb3Scarlsonj 				*sp++ = (type == DHCPV6_DUID_LLT ||
670d04ccbb3Scarlsonj 				    type == DHCPV6_DUID_LL) ? ':' : ' ';
671d04ccbb3Scarlsonj 				sp = sp + snprintf(sp, 3, "%02x", *data++);
672d04ccbb3Scarlsonj 			}
673d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
674d04ccbb3Scarlsonj 			    (type == DHCPV6_DUID_LLT ||
675d04ccbb3Scarlsonj 			    type == DHCPV6_DUID_LL) ?
676d04ccbb3Scarlsonj 			    "  Link Layer Address = %s" :
677d04ccbb3Scarlsonj 			    "  Identifier = %s", str);
678d04ccbb3Scarlsonj 			free(str);
679d04ccbb3Scarlsonj 			break;
680d04ccbb3Scarlsonj 		case DHCPV6_OPT_IA_NA:
681d04ccbb3Scarlsonj 		case DHCPV6_OPT_IA_PD: {
682d04ccbb3Scarlsonj 			dhcpv6_ia_na_t d6in;
683d04ccbb3Scarlsonj 
684d04ccbb3Scarlsonj 			if (olen < sizeof (d6in) - sizeof (d6o))
685d04ccbb3Scarlsonj 				break;
686d04ccbb3Scarlsonj 			(void) memcpy(&d6in, data - sizeof (d6o),
687d04ccbb3Scarlsonj 			    sizeof (d6in));
688d04ccbb3Scarlsonj 			data += sizeof (d6in) - sizeof (d6o);
689d04ccbb3Scarlsonj 			olen -= sizeof (d6in) - sizeof (d6o);
690d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
691d04ccbb3Scarlsonj 			    "  IAID = %u", ntohl(d6in.d6in_iaid));
692d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
693d04ccbb3Scarlsonj 			    "  T1 (renew) = %u seconds", ntohl(d6in.d6in_t1));
694d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
695d04ccbb3Scarlsonj 			    "  T2 (rebind) = %u seconds", ntohl(d6in.d6in_t2));
696d04ccbb3Scarlsonj 			nest_options(data, olen, "IA: ",
697d04ccbb3Scarlsonj 			    "Identity Association");
698d04ccbb3Scarlsonj 			break;
699d04ccbb3Scarlsonj 		}
700d04ccbb3Scarlsonj 		case DHCPV6_OPT_IA_TA: {
701d04ccbb3Scarlsonj 			dhcpv6_ia_ta_t d6it;
702d04ccbb3Scarlsonj 
703d04ccbb3Scarlsonj 			if (olen < sizeof (d6it) - sizeof (d6o))
704d04ccbb3Scarlsonj 				break;
705d04ccbb3Scarlsonj 			(void) memcpy(&d6it, data - sizeof (d6o),
706d04ccbb3Scarlsonj 			    sizeof (d6it));
707d04ccbb3Scarlsonj 			data += sizeof (d6it) - sizeof (d6o);
708d04ccbb3Scarlsonj 			olen -= sizeof (d6it) - sizeof (d6o);
709d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
710d04ccbb3Scarlsonj 			    "  IAID = %u", ntohl(d6it.d6it_iaid));
711d04ccbb3Scarlsonj 			nest_options(data, olen, "IA: ",
712d04ccbb3Scarlsonj 			    "Identity Association");
713d04ccbb3Scarlsonj 			break;
714d04ccbb3Scarlsonj 		}
715d04ccbb3Scarlsonj 		case DHCPV6_OPT_IAADDR: {
716d04ccbb3Scarlsonj 			dhcpv6_iaaddr_t d6ia;
717d04ccbb3Scarlsonj 
718d04ccbb3Scarlsonj 			if (olen < sizeof (d6ia) - sizeof (d6o))
719d04ccbb3Scarlsonj 				break;
720d04ccbb3Scarlsonj 			(void) memcpy(&d6ia, data - sizeof (d6o),
721d04ccbb3Scarlsonj 			    sizeof (d6ia));
722d04ccbb3Scarlsonj 			data += sizeof (d6ia) - sizeof (d6o);
723d04ccbb3Scarlsonj 			olen -= sizeof (d6ia) - sizeof (d6o);
724d04ccbb3Scarlsonj 			show_address("  Address", &d6ia.d6ia_addr);
725d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
726d04ccbb3Scarlsonj 			    "  Preferred lifetime = %u seconds",
727d04ccbb3Scarlsonj 			    ntohl(d6ia.d6ia_preflife));
728d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
729d04ccbb3Scarlsonj 			    "  Valid lifetime = %u seconds",
730d04ccbb3Scarlsonj 			    ntohl(d6ia.d6ia_vallife));
731d04ccbb3Scarlsonj 			nest_options(data, olen, "ADDR: ", "Address");
732d04ccbb3Scarlsonj 			break;
733d04ccbb3Scarlsonj 		}
734d04ccbb3Scarlsonj 		case DHCPV6_OPT_ORO:
735d04ccbb3Scarlsonj 			while (olen >= sizeof (val16)) {
736d04ccbb3Scarlsonj 				(void) memcpy(&val16, data, sizeof (val16));
737d04ccbb3Scarlsonj 				val16 = ntohs(val16);
738d04ccbb3Scarlsonj 				(void) snprintf(get_line(0, 0),
739d04ccbb3Scarlsonj 				    get_line_remain(),
740d04ccbb3Scarlsonj 				    "  Requested Option Code = %u (%s)", val16,
741d04ccbb3Scarlsonj 				    option_to_str(val16));
742d04ccbb3Scarlsonj 				data += sizeof (val16);
743d04ccbb3Scarlsonj 				olen -= sizeof (val16);
744d04ccbb3Scarlsonj 			}
745d04ccbb3Scarlsonj 			break;
746d04ccbb3Scarlsonj 		case DHCPV6_OPT_PREFERENCE:
747d04ccbb3Scarlsonj 			if (olen > 0) {
748d04ccbb3Scarlsonj 				(void) snprintf(get_line(0, 0),
749d04ccbb3Scarlsonj 				    get_line_remain(),
750d04ccbb3Scarlsonj 				    *data == 255 ?
751d04ccbb3Scarlsonj 				    "  Preference = %u (immediate)" :
752d04ccbb3Scarlsonj 				    "  Preference = %u", *data);
753d04ccbb3Scarlsonj 			}
754d04ccbb3Scarlsonj 			break;
755d04ccbb3Scarlsonj 		case DHCPV6_OPT_ELAPSED_TIME:
756d04ccbb3Scarlsonj 			if (olen == sizeof (val16)) {
757d04ccbb3Scarlsonj 				(void) memcpy(&val16, data, sizeof (val16));
758d04ccbb3Scarlsonj 				val16 = ntohs(val16);
759d04ccbb3Scarlsonj 				(void) snprintf(get_line(0, 0),
760d04ccbb3Scarlsonj 				    get_line_remain(),
761d04ccbb3Scarlsonj 				    "  Elapsed Time = %u.%02u seconds",
762d04ccbb3Scarlsonj 				    val16 / 100, val16 % 100);
763d04ccbb3Scarlsonj 			}
764d04ccbb3Scarlsonj 			break;
765d04ccbb3Scarlsonj 		case DHCPV6_OPT_RELAY_MSG:
766d04ccbb3Scarlsonj 			if (olen > 0) {
767d04ccbb3Scarlsonj 				oldnest = prot_nest_prefix;
768d04ccbb3Scarlsonj 				prot_nest_prefix = prot_prefix;
769d04ccbb3Scarlsonj 				retlen = interpret_dhcpv6(F_DTAIL, data, olen);
770d04ccbb3Scarlsonj 				prot_prefix = prot_nest_prefix;
771d04ccbb3Scarlsonj 				prot_nest_prefix = oldnest;
772d04ccbb3Scarlsonj 			}
773d04ccbb3Scarlsonj 			break;
774d04ccbb3Scarlsonj 		case DHCPV6_OPT_AUTH: {
775d04ccbb3Scarlsonj 			dhcpv6_auth_t d6a;
776d04ccbb3Scarlsonj 
777d04ccbb3Scarlsonj 			if (olen < DHCPV6_AUTH_SIZE - sizeof (d6o))
778d04ccbb3Scarlsonj 				break;
779d04ccbb3Scarlsonj 			(void) memcpy(&d6a, data - sizeof (d6o),
780d04ccbb3Scarlsonj 			    DHCPV6_AUTH_SIZE);
781d04ccbb3Scarlsonj 			data += DHCPV6_AUTH_SIZE - sizeof (d6o);
782d04ccbb3Scarlsonj 			olen += DHCPV6_AUTH_SIZE - sizeof (d6o);
783d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
784d04ccbb3Scarlsonj 			    "  Protocol = %u (%s)", d6a.d6a_proto,
785d04ccbb3Scarlsonj 			    authproto_to_str(d6a.d6a_proto));
786d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
787d04ccbb3Scarlsonj 			    "  Algorithm = %u (%s)", d6a.d6a_alg,
788d04ccbb3Scarlsonj 			    authalg_to_str(d6a.d6a_proto, d6a.d6a_alg));
789d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
790d04ccbb3Scarlsonj 			    "  Replay Detection Method = %u (%s)", d6a.d6a_rdm,
791d04ccbb3Scarlsonj 			    authrdm_to_str(d6a.d6a_rdm));
792d04ccbb3Scarlsonj 			show_hex(d6a.d6a_replay, sizeof (d6a.d6a_replay),
793d04ccbb3Scarlsonj 			    "  RDM Data");
794d04ccbb3Scarlsonj 			if (olen > 0)
795d04ccbb3Scarlsonj 				show_hex(data, olen, "  Auth Info");
796d04ccbb3Scarlsonj 			break;
797d04ccbb3Scarlsonj 		}
798d04ccbb3Scarlsonj 		case DHCPV6_OPT_UNICAST:
799d04ccbb3Scarlsonj 			if (olen >= sizeof (in6_addr_t))
800d04ccbb3Scarlsonj 				show_address("  Server Address", data);
801d04ccbb3Scarlsonj 			break;
802d04ccbb3Scarlsonj 		case DHCPV6_OPT_STATUS_CODE:
803d04ccbb3Scarlsonj 			if (olen < sizeof (val16))
804d04ccbb3Scarlsonj 				break;
805d04ccbb3Scarlsonj 			(void) memcpy(&val16, data, sizeof (val16));
806d04ccbb3Scarlsonj 			val16 = ntohs(val16);
807d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
808d04ccbb3Scarlsonj 			    "  Status Code = %u (%s)", val16,
809d04ccbb3Scarlsonj 			    status_to_str(val16));
810d04ccbb3Scarlsonj 			data += sizeof (val16);
811d04ccbb3Scarlsonj 			olen -= sizeof (val16);
812d04ccbb3Scarlsonj 			if (olen > 0)
813d04ccbb3Scarlsonj 				(void) snprintf(get_line(0, 0),
814d04ccbb3Scarlsonj 				    get_line_remain(), "  Text = \"%.*s\"",
815d04ccbb3Scarlsonj 				    olen, data);
816d04ccbb3Scarlsonj 			break;
817d04ccbb3Scarlsonj 		case DHCPV6_OPT_VENDOR_CLASS:
818d04ccbb3Scarlsonj 			if (olen < sizeof (val32))
819d04ccbb3Scarlsonj 				break;
820d04ccbb3Scarlsonj 			(void) memcpy(&val32, data, sizeof (val32));
821d04ccbb3Scarlsonj 			data += sizeof (val32);
822d04ccbb3Scarlsonj 			olen -= sizeof (val32);
823d04ccbb3Scarlsonj 			val32 = ntohl(val32);
824d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
825d04ccbb3Scarlsonj 			    "  Enterprise Number = %lu (%s)", val32,
826d04ccbb3Scarlsonj 			    entr_to_str(val32));
827d04ccbb3Scarlsonj 			/* FALLTHROUGH */
828d04ccbb3Scarlsonj 		case DHCPV6_OPT_USER_CLASS:
829d04ccbb3Scarlsonj 			while (olen >= sizeof (val16)) {
830d04ccbb3Scarlsonj 				(void) memcpy(&val16, data, sizeof (val16));
831d04ccbb3Scarlsonj 				data += sizeof (val16);
832d04ccbb3Scarlsonj 				olen -= sizeof (val16);
833d04ccbb3Scarlsonj 				val16 = ntohs(val16);
834d04ccbb3Scarlsonj 				if (val16 > olen) {
835d04ccbb3Scarlsonj 					(void) strlcpy(get_line(0, 0),
836d04ccbb3Scarlsonj 					    "  Truncated class",
837d04ccbb3Scarlsonj 					    get_line_remain());
838d04ccbb3Scarlsonj 					val16 = olen;
839d04ccbb3Scarlsonj 				}
840d04ccbb3Scarlsonj 				show_hex(data, olen, "  Class");
841d04ccbb3Scarlsonj 				data += val16;
842d04ccbb3Scarlsonj 				olen -= val16;
843d04ccbb3Scarlsonj 			}
844d04ccbb3Scarlsonj 			break;
845d04ccbb3Scarlsonj 		case DHCPV6_OPT_VENDOR_OPT: {
846d04ccbb3Scarlsonj 			dhcpv6_option_t sd6o;
847d04ccbb3Scarlsonj 
848d04ccbb3Scarlsonj 			if (olen < sizeof (val32))
849d04ccbb3Scarlsonj 				break;
850d04ccbb3Scarlsonj 			(void) memcpy(&val32, data, sizeof (val32));
851d04ccbb3Scarlsonj 			data += sizeof (val32);
852d04ccbb3Scarlsonj 			olen -= sizeof (val32);
853d04ccbb3Scarlsonj 			val32 = ntohl(val32);
854d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
855d04ccbb3Scarlsonj 			    "  Enterprise Number = %lu (%s)", val32,
856d04ccbb3Scarlsonj 			    entr_to_str(val32));
857d04ccbb3Scarlsonj 			while (olen >= sizeof (sd6o)) {
858d04ccbb3Scarlsonj 				(void) memcpy(&sd6o, data, sizeof (sd6o));
859d04ccbb3Scarlsonj 				sd6o.d6o_code = ntohs(sd6o.d6o_code);
860d04ccbb3Scarlsonj 				sd6o.d6o_len = ntohs(sd6o.d6o_len);
861d04ccbb3Scarlsonj 				(void) snprintf(get_line(0, 0),
862d04ccbb3Scarlsonj 				    get_line_remain(),
863d04ccbb3Scarlsonj 				    "  Vendor Option Code = %u", d6o.d6o_code);
864d04ccbb3Scarlsonj 				data += sizeof (d6o);
865d04ccbb3Scarlsonj 				olen -= sizeof (d6o);
866d04ccbb3Scarlsonj 				if (sd6o.d6o_len > olen) {
867d04ccbb3Scarlsonj 					(void) strlcpy(get_line(0, 0),
868d04ccbb3Scarlsonj 					    "  Vendor Option truncated",
869d04ccbb3Scarlsonj 					    get_line_remain());
870d04ccbb3Scarlsonj 					sd6o.d6o_len = olen;
871d04ccbb3Scarlsonj 				}
872d04ccbb3Scarlsonj 				if (sd6o.d6o_len > 0) {
873d04ccbb3Scarlsonj 					show_hex(data, sd6o.d6o_len,
874d04ccbb3Scarlsonj 					    "    Data");
875d04ccbb3Scarlsonj 					data += sd6o.d6o_len;
876d04ccbb3Scarlsonj 					olen -= sd6o.d6o_len;
877d04ccbb3Scarlsonj 				}
878d04ccbb3Scarlsonj 			}
879d04ccbb3Scarlsonj 			break;
880d04ccbb3Scarlsonj 		}
881d04ccbb3Scarlsonj 		case DHCPV6_OPT_REMOTE_ID:
882d04ccbb3Scarlsonj 			if (olen < sizeof (val32))
883d04ccbb3Scarlsonj 				break;
884d04ccbb3Scarlsonj 			(void) memcpy(&val32, data, sizeof (val32));
885d04ccbb3Scarlsonj 			data += sizeof (val32);
886d04ccbb3Scarlsonj 			olen -= sizeof (val32);
887d04ccbb3Scarlsonj 			val32 = ntohl(val32);
888d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
889d04ccbb3Scarlsonj 			    "  Enterprise Number = %lu (%s)", val32,
890d04ccbb3Scarlsonj 			    entr_to_str(val32));
891d04ccbb3Scarlsonj 			/* FALLTHROUGH */
892d04ccbb3Scarlsonj 		case DHCPV6_OPT_INTERFACE_ID:
893d04ccbb3Scarlsonj 		case DHCPV6_OPT_SUBSCRIBER:
894d04ccbb3Scarlsonj 			if (olen > 0)
895d04ccbb3Scarlsonj 				show_hex(data, olen, "  ID");
896d04ccbb3Scarlsonj 			break;
897d04ccbb3Scarlsonj 		case DHCPV6_OPT_RECONF_MSG:
898d04ccbb3Scarlsonj 			if (olen > 0) {
899d04ccbb3Scarlsonj 				(void) snprintf(get_line(0, 0),
900d04ccbb3Scarlsonj 				    get_line_remain(),
901d04ccbb3Scarlsonj 				    "  Message Type = %u (%s)", *data,
902d04ccbb3Scarlsonj 				    reconf_to_str(*data));
903d04ccbb3Scarlsonj 			}
904d04ccbb3Scarlsonj 			break;
905d04ccbb3Scarlsonj 		case DHCPV6_OPT_SIP_NAMES:
906d04ccbb3Scarlsonj 		case DHCPV6_OPT_DNS_SEARCH:
907d04ccbb3Scarlsonj 		case DHCPV6_OPT_NIS_DOMAIN:
908d04ccbb3Scarlsonj 		case DHCPV6_OPT_BCMCS_SRV_D: {
909d04ccbb3Scarlsonj 			dhcp_symbol_t *symp;
910d04ccbb3Scarlsonj 			char *sp2;
911d04ccbb3Scarlsonj 
912d04ccbb3Scarlsonj 			symp = inittab_getbycode(
913d04ccbb3Scarlsonj 			    ITAB_CAT_STANDARD | ITAB_CAT_V6, ITAB_CONS_SNOOP,
914d04ccbb3Scarlsonj 			    d6o.d6o_code);
915d04ccbb3Scarlsonj 			if (symp != NULL) {
916d04ccbb3Scarlsonj 				str = inittab_decode(symp, data, olen, B_TRUE);
917d04ccbb3Scarlsonj 				if (str != NULL) {
918d04ccbb3Scarlsonj 					sp = str;
919d04ccbb3Scarlsonj 					do {
920d04ccbb3Scarlsonj 						sp2 = strchr(sp, ' ');
921d04ccbb3Scarlsonj 						if (sp2 != NULL)
922d04ccbb3Scarlsonj 							*sp2++ = '\0';
923d04ccbb3Scarlsonj 						(void) snprintf(get_line(0, 0),
924d04ccbb3Scarlsonj 						    get_line_remain(),
925d04ccbb3Scarlsonj 						    "  Name = %s", sp);
926d04ccbb3Scarlsonj 					} while ((sp = sp2) != NULL);
927d04ccbb3Scarlsonj 					free(str);
928d04ccbb3Scarlsonj 				}
929d04ccbb3Scarlsonj 				free(symp);
930d04ccbb3Scarlsonj 			}
931d04ccbb3Scarlsonj 			break;
932d04ccbb3Scarlsonj 		}
933d04ccbb3Scarlsonj 		case DHCPV6_OPT_SIP_ADDR:
934d04ccbb3Scarlsonj 		case DHCPV6_OPT_DNS_ADDR:
935d04ccbb3Scarlsonj 		case DHCPV6_OPT_NIS_SERVERS:
936d04ccbb3Scarlsonj 		case DHCPV6_OPT_SNTP_SERVERS:
937d04ccbb3Scarlsonj 		case DHCPV6_OPT_BCMCS_SRV_A:
938d04ccbb3Scarlsonj 			while (olen >= sizeof (in6_addr_t)) {
939d04ccbb3Scarlsonj 				show_address("  Address", data);
940d04ccbb3Scarlsonj 				data += sizeof (in6_addr_t);
941d04ccbb3Scarlsonj 				olen -= sizeof (in6_addr_t);
942d04ccbb3Scarlsonj 			}
943d04ccbb3Scarlsonj 			break;
944d04ccbb3Scarlsonj 		case DHCPV6_OPT_IAPREFIX: {
945d04ccbb3Scarlsonj 			dhcpv6_iaprefix_t d6ip;
946d04ccbb3Scarlsonj 
947d04ccbb3Scarlsonj 			if (olen < DHCPV6_IAPREFIX_SIZE - sizeof (d6o))
948d04ccbb3Scarlsonj 				break;
949d04ccbb3Scarlsonj 			(void) memcpy(&d6ip, data - sizeof (d6o),
950d04ccbb3Scarlsonj 			    DHCPV6_IAPREFIX_SIZE);
951d04ccbb3Scarlsonj 			data += DHCPV6_IAPREFIX_SIZE - sizeof (d6o);
952d04ccbb3Scarlsonj 			olen -= DHCPV6_IAPREFIX_SIZE - sizeof (d6o);
953d04ccbb3Scarlsonj 			show_address("  Prefix", d6ip.d6ip_addr);
954d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
955d04ccbb3Scarlsonj 			    "  Preferred lifetime = %u seconds",
956d04ccbb3Scarlsonj 			    ntohl(d6ip.d6ip_preflife));
957d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
958d04ccbb3Scarlsonj 			    "  Valid lifetime = %u seconds",
959d04ccbb3Scarlsonj 			    ntohl(d6ip.d6ip_vallife));
960d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
961d04ccbb3Scarlsonj 			    "  Prefix length = %u", d6ip.d6ip_preflen);
962d04ccbb3Scarlsonj 			nest_options(data, olen, "ADDR: ", "Address");
963d04ccbb3Scarlsonj 			break;
964d04ccbb3Scarlsonj 		}
965d04ccbb3Scarlsonj 		case DHCPV6_OPT_INFO_REFTIME:
966d04ccbb3Scarlsonj 			if (olen < sizeof (val32))
967d04ccbb3Scarlsonj 				break;
968d04ccbb3Scarlsonj 			(void) memcpy(&val32, data, sizeof (val32));
969d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
970d04ccbb3Scarlsonj 			    "  Refresh Time = %lu seconds", ntohl(val32));
971d04ccbb3Scarlsonj 			break;
972d04ccbb3Scarlsonj 		case DHCPV6_OPT_GEOCONF_CVC: {
973d04ccbb3Scarlsonj 			dhcpv6_civic_t d6c;
974d04ccbb3Scarlsonj 			int solen;
975d04ccbb3Scarlsonj 
976d04ccbb3Scarlsonj 			if (olen < DHCPV6_CIVIC_SIZE - sizeof (d6o))
977d04ccbb3Scarlsonj 				break;
978d04ccbb3Scarlsonj 			(void) memcpy(&d6c, data - sizeof (d6o),
979d04ccbb3Scarlsonj 			    DHCPV6_CIVIC_SIZE);
980d04ccbb3Scarlsonj 			data += DHCPV6_CIVIC_SIZE - sizeof (d6o);
981d04ccbb3Scarlsonj 			olen -= DHCPV6_CIVIC_SIZE - sizeof (d6o);
982d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
983d04ccbb3Scarlsonj 			    "  What Location = %u (%s)", d6c.d6c_what,
984d04ccbb3Scarlsonj 			    cwhat_to_str(d6c.d6c_what));
985d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
986d04ccbb3Scarlsonj 			    "  Country Code = %.*s", sizeof (d6c.d6c_cc),
987d04ccbb3Scarlsonj 			    d6c.d6c_cc);
988d04ccbb3Scarlsonj 			while (olen >= 2) {
989d04ccbb3Scarlsonj 				(void) snprintf(get_line(0, 0),
990d04ccbb3Scarlsonj 				    get_line_remain(),
991d04ccbb3Scarlsonj 				    "  CA Element = %u (%s)", *data,
992d04ccbb3Scarlsonj 				    catype_to_str(*data));
993d04ccbb3Scarlsonj 				solen = data[1];
994d04ccbb3Scarlsonj 				data += 2;
995d04ccbb3Scarlsonj 				olen -= 2;
996d04ccbb3Scarlsonj 				if (solen > olen) {
997d04ccbb3Scarlsonj 					(void) strlcpy(get_line(0, 0),
998d04ccbb3Scarlsonj 					    "  CA Element truncated",
999d04ccbb3Scarlsonj 					    get_line_remain());
1000d04ccbb3Scarlsonj 					solen = olen;
1001d04ccbb3Scarlsonj 				}
1002d04ccbb3Scarlsonj 				if (solen > 0) {
1003d04ccbb3Scarlsonj 					show_ascii(data, solen, "  CA Data");
1004d04ccbb3Scarlsonj 					data += solen;
1005d04ccbb3Scarlsonj 					olen -= solen;
1006d04ccbb3Scarlsonj 				}
1007d04ccbb3Scarlsonj 			}
1008d04ccbb3Scarlsonj 			break;
1009d04ccbb3Scarlsonj 		}
1010d04ccbb3Scarlsonj 		case DHCPV6_OPT_CLIENT_FQDN: {
1011d04ccbb3Scarlsonj 			dhcp_symbol_t *symp;
1012d04ccbb3Scarlsonj 
1013d04ccbb3Scarlsonj 			if (olen == 0)
1014d04ccbb3Scarlsonj 				break;
1015d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
1016d04ccbb3Scarlsonj 			    "  Flags = %02x", *data);
1017d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
1018d04ccbb3Scarlsonj 			    "        %s", getflag(*data, DHCPV6_FQDNF_S,
1019d04ccbb3Scarlsonj 			    "Perform AAAA RR updates", "No AAAA RR updates"));
1020d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
1021d04ccbb3Scarlsonj 			    "        %s", getflag(*data, DHCPV6_FQDNF_O,
1022d04ccbb3Scarlsonj 			    "Server override updates",
1023d04ccbb3Scarlsonj 			    "No server override updates"));
1024d04ccbb3Scarlsonj 			(void) snprintf(get_line(0, 0), get_line_remain(),
1025d04ccbb3Scarlsonj 			    "        %s", getflag(*data, DHCPV6_FQDNF_N,
1026d04ccbb3Scarlsonj 			    "Server performs no updates",
1027d04ccbb3Scarlsonj 			    "Server performs updates"));
1028d04ccbb3Scarlsonj 			symp = inittab_getbycode(
1029d04ccbb3Scarlsonj 			    ITAB_CAT_STANDARD | ITAB_CAT_V6, ITAB_CONS_SNOOP,
1030d04ccbb3Scarlsonj 			    d6o.d6o_code);
1031d04ccbb3Scarlsonj 			if (symp != NULL) {
1032d04ccbb3Scarlsonj 				str = inittab_decode(symp, data, olen, B_TRUE);
1033d04ccbb3Scarlsonj 				if (str != NULL) {
1034d04ccbb3Scarlsonj 					(void) snprintf(get_line(0, 0),
1035d04ccbb3Scarlsonj 					    get_line_remain(),
1036d04ccbb3Scarlsonj 					    "  FQDN = %s", str);
1037d04ccbb3Scarlsonj 					free(str);
1038d04ccbb3Scarlsonj 				}
1039d04ccbb3Scarlsonj 				free(symp);
1040d04ccbb3Scarlsonj 			}
1041d04ccbb3Scarlsonj 			break;
1042d04ccbb3Scarlsonj 		}
1043d04ccbb3Scarlsonj 		}
1044d04ccbb3Scarlsonj 		data = ostart + d6o.d6o_len;
1045d04ccbb3Scarlsonj 		len -= d6o.d6o_len;
1046d04ccbb3Scarlsonj 	}
1047d04ccbb3Scarlsonj 	if (len != 0) {
1048d04ccbb3Scarlsonj 		(void) strlcpy(get_line(0, 0), "Option entry truncated",
1049d04ccbb3Scarlsonj 		    get_line_remain());
1050d04ccbb3Scarlsonj 	}
1051d04ccbb3Scarlsonj }
1052