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