xref: /freebsd/contrib/tcpdump/print-dhcp6.c (revision b1f9167f94059fd55c630891d359bcff987bd7eb)
1 /*
2  * Copyright (C) 1998 and 1999 WIDE Project.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 /*
30  * RFC3315: DHCPv6
31  * supported DHCPv6 options:
32  *  RFC3319: Session Initiation Protocol (SIP) Servers options,
33  *  RFC3633: IPv6 Prefix options,
34  *  RFC3646: DNS Configuration options,
35  *  RFC3898: Network Information Service (NIS) Configuration options,
36  *  RFC4075: Simple Network Time Protocol (SNTP) Configuration option,
37  *  RFC4242: Information Refresh Time option,
38  *  RFC4280: Broadcast and Multicast Control Servers options,
39  *  RFC6334: Dual-Stack Lite option,
40  */
41 
42 #ifndef lint
43 static const char rcsid[] _U_ =
44     "@(#) $Header: /tcpdump/master/tcpdump/print-dhcp6.c,v 1.37 2008-02-06 10:26:09 guy Exp $";
45 #endif
46 
47 #ifdef HAVE_CONFIG_H
48 #include "config.h"
49 #endif
50 
51 #include <tcpdump-stdinc.h>
52 
53 #include <stdio.h>
54 #include <string.h>
55 
56 #include "interface.h"
57 #include "addrtoname.h"
58 #include "extract.h"
59 
60 /* lease duration */
61 #define DHCP6_DURATITION_INFINITE 0xffffffff
62 
63 /* Error Values */
64 #define DH6ERR_FAILURE		16
65 #define DH6ERR_AUTHFAIL		17
66 #define DH6ERR_POORLYFORMED	18
67 #define DH6ERR_UNAVAIL		19
68 #define DH6ERR_OPTUNAVAIL	20
69 
70 /* Message type */
71 #define DH6_SOLICIT	1
72 #define DH6_ADVERTISE	2
73 #define DH6_REQUEST	3
74 #define DH6_CONFIRM	4
75 #define DH6_RENEW	5
76 #define DH6_REBIND	6
77 #define DH6_REPLY	7
78 #define DH6_RELEASE	8
79 #define DH6_DECLINE	9
80 #define DH6_RECONFIGURE	10
81 #define DH6_INFORM_REQ	11
82 #define DH6_RELAY_FORW	12
83 #define DH6_RELAY_REPLY	13
84 #define DH6_LEASEQUERY	14
85 #define DH6_LQ_REPLY	15
86 
87 /* DHCP6 base packet format */
88 struct dhcp6 {
89 	union {
90 		u_int8_t m;
91 		u_int32_t x;
92 	} dh6_msgtypexid;
93 	/* options follow */
94 };
95 #define dh6_msgtype	dh6_msgtypexid.m
96 #define dh6_xid		dh6_msgtypexid.x
97 #define DH6_XIDMASK	0x00ffffff
98 
99 /* DHCPv6 relay messages */
100 struct dhcp6_relay {
101 	u_int8_t dh6relay_msgtype;
102 	u_int8_t dh6relay_hcnt;
103 	u_int8_t dh6relay_linkaddr[16];	/* XXX: badly aligned */
104 	u_int8_t dh6relay_peeraddr[16];
105 	/* options follow */
106 };
107 
108 /* options */
109 #define DH6OPT_CLIENTID	1
110 #define DH6OPT_SERVERID	2
111 #define DH6OPT_IA_NA 3
112 #define DH6OPT_IA_TA 4
113 #define DH6OPT_IA_ADDR 5
114 #define DH6OPT_ORO 6
115 #define DH6OPT_PREFERENCE 7
116 #  define DH6OPT_PREF_MAX 255
117 #define DH6OPT_ELAPSED_TIME 8
118 #define DH6OPT_RELAY_MSG 9
119 /*#define DH6OPT_SERVER_MSG 10 deprecated */
120 #define DH6OPT_AUTH 11
121 #  define DH6OPT_AUTHPROTO_DELAYED 2
122 #  define DH6OPT_AUTHPROTO_RECONFIG 3
123 #  define DH6OPT_AUTHALG_HMACMD5 1
124 #  define DH6OPT_AUTHRDM_MONOCOUNTER 0
125 #  define DH6OPT_AUTHRECONFIG_KEY 1
126 #  define DH6OPT_AUTHRECONFIG_HMACMD5 2
127 #define DH6OPT_UNICAST 12
128 #define DH6OPT_STATUS_CODE 13
129 #  define DH6OPT_STCODE_SUCCESS 0
130 #  define DH6OPT_STCODE_UNSPECFAIL 1
131 #  define DH6OPT_STCODE_NOADDRAVAIL 2
132 #  define DH6OPT_STCODE_NOBINDING 3
133 #  define DH6OPT_STCODE_NOTONLINK 4
134 #  define DH6OPT_STCODE_USEMULTICAST 5
135 #  define DH6OPT_STCODE_NOPREFIXAVAIL 6
136 #  define DH6OPT_STCODE_UNKNOWNQUERYTYPE 7
137 #  define DH6OPT_STCODE_MALFORMEDQUERY 8
138 #  define DH6OPT_STCODE_NOTCONFIGURED 9
139 #  define DH6OPT_STCODE_NOTALLOWED 10
140 #define DH6OPT_RAPID_COMMIT 14
141 #define DH6OPT_USER_CLASS 15
142 #define DH6OPT_VENDOR_CLASS 16
143 #define DH6OPT_VENDOR_OPTS 17
144 #define DH6OPT_INTERFACE_ID 18
145 #define DH6OPT_RECONF_MSG 19
146 #define DH6OPT_RECONF_ACCEPT 20
147 #define DH6OPT_SIP_SERVER_D 21
148 #define DH6OPT_SIP_SERVER_A 22
149 #define DH6OPT_DNS 23
150 #define DH6OPT_DNSNAME 24
151 #define DH6OPT_IA_PD 25
152 #define DH6OPT_IA_PD_PREFIX 26
153 #define DH6OPT_NIS_SERVERS 27
154 #define DH6OPT_NISP_SERVERS 28
155 #define DH6OPT_NIS_NAME 29
156 #define DH6OPT_NISP_NAME 30
157 #define DH6OPT_NTP_SERVERS 31
158 #define DH6OPT_LIFETIME 32
159 #define DH6OPT_BCMCS_SERVER_D 33
160 #define DH6OPT_BCMCS_SERVER_A 34
161 #define DH6OPT_GEOCONF_CIVIC 36
162 #define DH6OPT_REMOTE_ID 37
163 #define DH6OPT_SUBSCRIBER_ID 38
164 #define DH6OPT_CLIENT_FQDN 39
165 #define DH6OPT_PANA_AGENT 40
166 #define DH6OPT_NEW_POSIX_TIMEZONE 41
167 #define DH6OPT_NEW_TZDB_TIMEZONE 42
168 #define DH6OPT_ERO 43
169 #define DH6OPT_LQ_QUERY 44
170 #define DH6OPT_CLIENT_DATA 45
171 #define DH6OPT_CLT_TIME 46
172 #define DH6OPT_LQ_RELAY_DATA 47
173 #define DH6OPT_LQ_CLIENT_LINK 48
174 #define DH6OPT_AFTR_NAME 64
175 
176 struct dhcp6opt {
177 	u_int16_t dh6opt_type;
178 	u_int16_t dh6opt_len;
179 	/* type-dependent data follows */
180 };
181 
182 static const char *
183 dhcp6opt_name(int type)
184 {
185 	static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */
186 
187 	if (type > 65535)
188 		return "INVALID-option";
189 
190 	switch(type) {
191 	case DH6OPT_CLIENTID:
192 		return "client-ID";
193 	case DH6OPT_SERVERID:
194 		return "server-ID";
195 	case DH6OPT_IA_NA:
196 		return "IA_NA";
197 	case DH6OPT_IA_TA:
198 		return "IA_TA";
199 	case DH6OPT_IA_ADDR:
200 		return "IA_ADDR";
201 	case DH6OPT_ORO:
202 		return "option-request";
203 	case DH6OPT_PREFERENCE:
204 		return "preference";
205 	case DH6OPT_ELAPSED_TIME:
206 		return "elapsed-time";
207 	case DH6OPT_RELAY_MSG:
208 		return "relay-message";
209 	case DH6OPT_AUTH:
210 		return "authentication";
211 	case DH6OPT_UNICAST:
212 		return "server-unicast";
213 	case DH6OPT_STATUS_CODE:
214 		return "status-code";
215 	case DH6OPT_RAPID_COMMIT:
216 		return "rapid-commit";
217 	case DH6OPT_USER_CLASS:
218 		return "user-class";
219 	case DH6OPT_VENDOR_CLASS:
220 		return "vendor-class";
221 	case DH6OPT_VENDOR_OPTS:
222 		return "vendor-specific-info";
223 	case DH6OPT_INTERFACE_ID:
224 		return "interface-ID";
225 	case DH6OPT_RECONF_MSG:
226 		return "reconfigure-message";
227 	case DH6OPT_RECONF_ACCEPT:
228 		return "reconfigure-accept";
229 	case DH6OPT_SIP_SERVER_D:
230 		return "SIP-servers-domain";
231 	case DH6OPT_SIP_SERVER_A:
232 		return "SIP-servers-address";
233 	case DH6OPT_DNS:
234 		return "DNS-server";
235 	case DH6OPT_DNSNAME:
236 		return "DNS-search-list";
237 	case DH6OPT_IA_PD:
238 		return "IA_PD";
239 	case DH6OPT_IA_PD_PREFIX:
240 		return "IA_PD-prefix";
241 	case DH6OPT_NTP_SERVERS:
242 		return "NTP-server";
243 	case DH6OPT_LIFETIME:
244 		return "lifetime";
245 	case DH6OPT_NIS_SERVERS:
246 		return "NIS-server";
247 	case DH6OPT_NISP_SERVERS:
248 		return "NIS+-server";
249 	case DH6OPT_NIS_NAME:
250 		return "NIS-domain-name";
251 	case DH6OPT_NISP_NAME:
252 		return "NIS+-domain-name";
253 	case DH6OPT_BCMCS_SERVER_D:
254 		return "BCMCS-domain-name";
255 	case DH6OPT_BCMCS_SERVER_A:
256 		return "BCMCS-server";
257 	case DH6OPT_GEOCONF_CIVIC:
258 		return "Geoconf-Civic";
259 	case DH6OPT_REMOTE_ID:
260 		return "Remote-ID";
261 	case DH6OPT_SUBSCRIBER_ID:
262 		return "Subscriber-ID";
263 	case DH6OPT_CLIENT_FQDN:
264 		return "Client-FQDN";
265 	case DH6OPT_PANA_AGENT:
266 		return "PANA-agent";
267 	case DH6OPT_NEW_POSIX_TIMEZONE:
268 		return "POSIX-timezone";
269 	case DH6OPT_NEW_TZDB_TIMEZONE:
270 		return "POSIX-tz-database";
271 	case DH6OPT_ERO:
272 		return "Echo-request-option";
273 	case DH6OPT_LQ_QUERY:
274 		return "Lease-query";
275 	case DH6OPT_CLIENT_DATA:
276 		return "LQ-client-data";
277 	case DH6OPT_CLT_TIME:
278 		return "Clt-time";
279 	case DH6OPT_LQ_RELAY_DATA:
280 		return "LQ-relay-data";
281 	case DH6OPT_LQ_CLIENT_LINK:
282 		return "LQ-client-link";
283 	case DH6OPT_AFTR_NAME:
284 		return "AFTR-Name";
285 	default:
286 		snprintf(genstr, sizeof(genstr), "opt_%d", type);
287 		return(genstr);
288 	}
289 }
290 
291 static const char *
292 dhcp6stcode(int code)
293 {
294 	static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */
295 
296 	if (code > 255)
297 		return "INVALID code";
298 
299 	switch(code) {
300 	case DH6OPT_STCODE_SUCCESS:
301 		return "success";
302 	case DH6OPT_STCODE_UNSPECFAIL:
303 		return "unspec failure";
304 	case DH6OPT_STCODE_NOADDRAVAIL:
305 		return "no addresses";
306 	case DH6OPT_STCODE_NOBINDING:
307 		return "no binding";
308 	case DH6OPT_STCODE_NOTONLINK:
309 		return "not on-link";
310 	case DH6OPT_STCODE_USEMULTICAST:
311 		return "use multicast";
312 	case DH6OPT_STCODE_NOPREFIXAVAIL:
313 		return "no prefixes";
314 	case DH6OPT_STCODE_UNKNOWNQUERYTYPE:
315 		return "unknown query type";
316 	case DH6OPT_STCODE_MALFORMEDQUERY:
317 		return "malformed query";
318 	case DH6OPT_STCODE_NOTCONFIGURED:
319 		return "not configured";
320 	case DH6OPT_STCODE_NOTALLOWED:
321 		return "not allowed";
322 	default:
323 		snprintf(genstr, sizeof(genstr), "code%d", code);
324 		return(genstr);
325 	}
326 }
327 
328 static void
329 dhcp6opt_print(const u_char *cp, const u_char *ep)
330 {
331 	struct dhcp6opt *dh6o;
332 	u_char *tp;
333 	size_t i;
334 	u_int16_t opttype;
335 	size_t optlen;
336 	u_int8_t auth_proto;
337 	u_int authinfolen, authrealmlen;
338 
339 	if (cp == ep)
340 		return;
341 	while (cp < ep) {
342 		if (ep < cp + sizeof(*dh6o))
343 			goto trunc;
344 		dh6o = (struct dhcp6opt *)cp;
345 		TCHECK(*dh6o);
346 		optlen = EXTRACT_16BITS(&dh6o->dh6opt_len);
347 		if (ep < cp + sizeof(*dh6o) + optlen)
348 			goto trunc;
349 		opttype = EXTRACT_16BITS(&dh6o->dh6opt_type);
350 		printf(" (%s", dhcp6opt_name(opttype));
351 		switch (opttype) {
352 		case DH6OPT_CLIENTID:
353 		case DH6OPT_SERVERID:
354 			if (optlen < 2) {
355 				/*(*/
356 				printf(" ?)");
357 				break;
358 			}
359 			tp = (u_char *)(dh6o + 1);
360 			switch (EXTRACT_16BITS(tp)) {
361 			case 1:
362 				if (optlen >= 2 + 6) {
363 					printf(" hwaddr/time type %u time %u ",
364 					    EXTRACT_16BITS(&tp[2]),
365 					    EXTRACT_32BITS(&tp[4]));
366 					for (i = 8; i < optlen; i++)
367 						printf("%02x", tp[i]);
368 					/*(*/
369 					printf(")");
370 				} else {
371 					/*(*/
372 					printf(" ?)");
373 				}
374 				break;
375 			case 2:
376 				if (optlen >= 2 + 8) {
377 					printf(" vid ");
378 					for (i = 2; i < 2 + 8; i++)
379 						printf("%02x", tp[i]);
380 					/*(*/
381 					printf(")");
382 				} else {
383 					/*(*/
384 					printf(" ?)");
385 				}
386 				break;
387 			case 3:
388 				if (optlen >= 2 + 2) {
389 					printf(" hwaddr type %u ",
390 					    EXTRACT_16BITS(&tp[2]));
391 					for (i = 4; i < optlen; i++)
392 						printf("%02x", tp[i]);
393 					/*(*/
394 					printf(")");
395 				} else {
396 					/*(*/
397 					printf(" ?)");
398 				}
399 				break;
400 			default:
401 				printf(" type %d)", EXTRACT_16BITS(tp));
402 				break;
403 			}
404 			break;
405 		case DH6OPT_IA_ADDR:
406 			if (optlen < 24) {
407 				/*(*/
408 				printf(" ?)");
409 				break;
410 			}
411 			tp = (u_char *)(dh6o + 1);
412 			printf(" %s", ip6addr_string(&tp[0]));
413 			printf(" pltime:%u vltime:%u",
414 			    EXTRACT_32BITS(&tp[16]),
415 			    EXTRACT_32BITS(&tp[20]));
416 			if (optlen > 24) {
417 				/* there are sub-options */
418 				dhcp6opt_print(tp + 24, tp + optlen);
419 			}
420 			printf(")");
421 			break;
422 		case DH6OPT_ORO:
423 		case DH6OPT_ERO:
424 			if (optlen % 2) {
425 				printf(" ?)");
426 				break;
427 			}
428 			tp = (u_char *)(dh6o + 1);
429 			for (i = 0; i < optlen; i += 2) {
430 				printf(" %s",
431 				    dhcp6opt_name(EXTRACT_16BITS(&tp[i])));
432 			}
433 			printf(")");
434 			break;
435 		case DH6OPT_PREFERENCE:
436 			if (optlen != 1) {
437 				printf(" ?)");
438 				break;
439 			}
440 			tp = (u_char *)(dh6o + 1);
441 			printf(" %d)", *tp);
442 			break;
443 		case DH6OPT_ELAPSED_TIME:
444 			if (optlen != 2) {
445 				printf(" ?)");
446 				break;
447 			}
448 			tp = (u_char *)(dh6o + 1);
449 			printf(" %d)", EXTRACT_16BITS(tp));
450 			break;
451 		case DH6OPT_RELAY_MSG:
452 			printf(" (");
453 			tp = (u_char *)(dh6o + 1);
454 			dhcp6_print(tp, optlen);
455 			printf(")");
456 			break;
457 		case DH6OPT_AUTH:
458 			if (optlen < 11) {
459 				printf(" ?)");
460 				break;
461 			}
462 			tp = (u_char *)(dh6o + 1);
463 			auth_proto = *tp;
464 			switch (auth_proto) {
465 			case DH6OPT_AUTHPROTO_DELAYED:
466 				printf(" proto: delayed");
467 				break;
468 			case DH6OPT_AUTHPROTO_RECONFIG:
469 				printf(" proto: reconfigure");
470 				break;
471 			default:
472 				printf(" proto: %d", auth_proto);
473 				break;
474 			}
475 			tp++;
476 			switch (*tp) {
477 			case DH6OPT_AUTHALG_HMACMD5:
478 				/* XXX: may depend on the protocol */
479 				printf(", alg: HMAC-MD5");
480 				break;
481 			default:
482 				printf(", alg: %d", *tp);
483 				break;
484 			}
485 			tp++;
486 			switch (*tp) {
487 			case DH6OPT_AUTHRDM_MONOCOUNTER:
488 				printf(", RDM: mono");
489 				break;
490 			default:
491 				printf(", RDM: %d", *tp);
492 				break;
493 			}
494 			tp++;
495 			printf(", RD:");
496 			for (i = 0; i < 4; i++, tp += 2)
497 				printf(" %04x", EXTRACT_16BITS(tp));
498 
499 			/* protocol dependent part */
500 			authinfolen = optlen - 11;
501 			switch (auth_proto) {
502 			case DH6OPT_AUTHPROTO_DELAYED:
503 				if (authinfolen == 0)
504 					break;
505 				if (authinfolen < 20) {
506 					printf(" ??");
507 					break;
508 				}
509 				authrealmlen = authinfolen - 20;
510 				if (authrealmlen > 0) {
511 					printf(", realm: ");
512 				}
513 				for (i = 0; i < authrealmlen; i++, tp++)
514 					printf("%02x", *tp);
515 				printf(", key ID: %08x", EXTRACT_32BITS(tp));
516 				tp += 4;
517 				printf(", HMAC-MD5:");
518 				for (i = 0; i < 4; i++, tp+= 4)
519 					printf(" %08x", EXTRACT_32BITS(tp));
520 				break;
521 			case DH6OPT_AUTHPROTO_RECONFIG:
522 				if (authinfolen != 17) {
523 					printf(" ??");
524 					break;
525 				}
526 				switch (*tp++) {
527 				case DH6OPT_AUTHRECONFIG_KEY:
528 					printf(" reconfig-key");
529 					break;
530 				case DH6OPT_AUTHRECONFIG_HMACMD5:
531 					printf(" type: HMAC-MD5");
532 					break;
533 				default:
534 					printf(" type: ??");
535 					break;
536 				}
537 				printf(" value:");
538 				for (i = 0; i < 4; i++, tp+= 4)
539 					printf(" %08x", EXTRACT_32BITS(tp));
540 				break;
541 			default:
542 				printf(" ??");
543 				break;
544 			}
545 
546 			printf(")");
547 			break;
548 		case DH6OPT_RAPID_COMMIT: /* nothing todo */
549 			printf(")");
550 			break;
551 		case DH6OPT_INTERFACE_ID:
552 		case DH6OPT_SUBSCRIBER_ID:
553 			/*
554 			 * Since we cannot predict the encoding, print hex dump
555 			 * at most 10 characters.
556 			 */
557 			tp = (u_char *)(dh6o + 1);
558 			printf(" ");
559 			for (i = 0; i < optlen && i < 10; i++)
560 				printf("%02x", tp[i]);
561 			printf("...)");
562 			break;
563 		case DH6OPT_RECONF_MSG:
564 			tp = (u_char *)(dh6o + 1);
565 			switch (*tp) {
566 			case DH6_RENEW:
567 				printf(" for renew)");
568 				break;
569 			case DH6_INFORM_REQ:
570 				printf(" for inf-req)");
571 				break;
572 			default:
573 				printf(" for ?\?\?(%02x))", *tp);
574 				break;
575 			}
576 			break;
577 		case DH6OPT_RECONF_ACCEPT: /* nothing todo */
578 			printf(")");
579 			break;
580 		case DH6OPT_SIP_SERVER_A:
581 		case DH6OPT_DNS:
582 		case DH6OPT_NTP_SERVERS:
583 		case DH6OPT_NIS_SERVERS:
584 		case DH6OPT_NISP_SERVERS:
585 		case DH6OPT_BCMCS_SERVER_A:
586 		case DH6OPT_PANA_AGENT:
587 		case DH6OPT_LQ_CLIENT_LINK:
588 			if (optlen % 16) {
589 				printf(" ?)");
590 				break;
591 			}
592 			tp = (u_char *)(dh6o + 1);
593 			for (i = 0; i < optlen; i += 16)
594 				printf(" %s", ip6addr_string(&tp[i]));
595 			printf(")");
596 			break;
597 		case DH6OPT_STATUS_CODE:
598 			if (optlen < 2) {
599 				printf(" ?)");
600 				break;
601 			}
602 			tp = (u_char *)(dh6o + 1);
603 			printf(" %s)", dhcp6stcode(EXTRACT_16BITS(&tp[0])));
604 			break;
605 		case DH6OPT_IA_NA:
606 		case DH6OPT_IA_PD:
607 			if (optlen < 12) {
608 				printf(" ?)");
609 				break;
610 			}
611 			tp = (u_char *)(dh6o + 1);
612 			printf(" IAID:%u T1:%u T2:%u",
613 			    EXTRACT_32BITS(&tp[0]),
614 			    EXTRACT_32BITS(&tp[4]),
615 			    EXTRACT_32BITS(&tp[8]));
616 			if (optlen > 12) {
617 				/* there are sub-options */
618 				dhcp6opt_print(tp + 12, tp + optlen);
619 			}
620 			printf(")");
621 			break;
622 		case DH6OPT_IA_TA:
623 			if (optlen < 4) {
624 				printf(" ?)");
625 				break;
626 			}
627 			tp = (u_char *)(dh6o + 1);
628 			printf(" IAID:%u", EXTRACT_32BITS(tp));
629 			if (optlen > 4) {
630 				/* there are sub-options */
631 				dhcp6opt_print(tp + 4, tp + optlen);
632 			}
633 			printf(")");
634 			break;
635 		case DH6OPT_IA_PD_PREFIX:
636 			if (optlen < 25) {
637 				printf(" ?)");
638 				break;
639 			}
640 			tp = (u_char *)(dh6o + 1);
641 			printf(" %s/%d", ip6addr_string(&tp[9]), tp[8]);
642 			printf(" pltime:%u vltime:%u",
643 			    EXTRACT_32BITS(&tp[0]),
644 			    EXTRACT_32BITS(&tp[4]));
645 			if (optlen > 25) {
646 				/* there are sub-options */
647 				dhcp6opt_print(tp + 25, tp + optlen);
648 			}
649 			printf(")");
650 			break;
651 		case DH6OPT_LIFETIME:
652 		case DH6OPT_CLT_TIME:
653 			if (optlen != 4) {
654 				printf(" ?)");
655 				break;
656 			}
657 			tp = (u_char *)(dh6o + 1);
658 			printf(" %d)", EXTRACT_32BITS(tp));
659 			break;
660 		case DH6OPT_REMOTE_ID:
661 			if (optlen < 4) {
662 				printf(" ?)");
663 				break;
664 			}
665 			tp = (u_char *)(dh6o + 1);
666 			printf(" %d ", EXTRACT_32BITS(tp));
667 			/*
668 			 * Print hex dump first 10 characters.
669 			 */
670 			for (i = 4; i < optlen && i < 14; i++)
671 				printf("%02x", tp[i]);
672 			printf("...)");
673 			break;
674 		case DH6OPT_LQ_QUERY:
675 			if (optlen < 17) {
676 				printf(" ?)");
677 				break;
678 			}
679 			tp = (u_char *)(dh6o + 1);
680 			switch (*tp) {
681 			case 1:
682 				printf(" by-address");
683 				break;
684 			case 2:
685 				printf(" by-clientID");
686 				break;
687 			default:
688 				printf(" type_%d", (int)*tp);
689 				break;
690 			}
691 			printf(" %s", ip6addr_string(&tp[1]));
692 			if (optlen > 17) {
693 				/* there are query-options */
694 				dhcp6opt_print(tp + 17, tp + optlen);
695 			}
696 			printf(")");
697 			break;
698 		case DH6OPT_CLIENT_DATA:
699 			tp = (u_char *)(dh6o + 1);
700 			if (optlen > 0) {
701 				/* there are encapsulated options */
702 				dhcp6opt_print(tp, tp + optlen);
703 			}
704 			printf(")");
705 			break;
706 		case DH6OPT_LQ_RELAY_DATA:
707 			if (optlen < 16) {
708 				printf(" ?)");
709 				break;
710 			}
711 			tp = (u_char *)(dh6o + 1);
712 			printf(" %s ", ip6addr_string(&tp[0]));
713 			/*
714 			 * Print hex dump first 10 characters.
715 			 */
716 			for (i = 16; i < optlen && i < 26; i++)
717 				printf("%02x", tp[i]);
718 			printf("...)");
719 			break;
720 		case DH6OPT_AFTR_NAME:
721 			if (optlen < 3) {
722 				printf(" ?)");
723 				break;
724 			}
725 			tp = (u_char *)(dh6o + 1);
726 			int remain_len = optlen;
727 			printf(" ");
728 			/* Encoding is described in section 3.1 of RFC 1035 */
729 			int label_len; /* Label length */
730 			while (remain_len && *tp) {
731 				label_len =  *tp++;
732 				if (label_len < remain_len - 1) {
733 					printf("%.*s", label_len, tp);
734 					tp += label_len;
735 					remain_len -= (label_len + 1);
736 					if(*tp) printf(".");
737 				} else {
738 					printf(" ?");
739 					break;
740 				}
741 			}
742 			printf(")");
743 			break;
744 		default:
745 			printf(")");
746 			break;
747 		}
748 
749 		cp += sizeof(*dh6o) + optlen;
750 	}
751 	return;
752 
753 trunc:
754 	printf("[|dhcp6ext]");
755 }
756 
757 /*
758  * Print dhcp6 packets
759  */
760 void
761 dhcp6_print(const u_char *cp, u_int length)
762 {
763 	struct dhcp6 *dh6;
764 	struct dhcp6_relay *dh6relay;
765 	const u_char *ep;
766 	u_char *extp;
767 	const char *name;
768 
769 	printf("dhcp6");
770 
771 	ep = (u_char *)snapend;
772 	if (cp + length < ep)
773 		ep = cp + length;
774 
775 	dh6 = (struct dhcp6 *)cp;
776 	dh6relay = (struct dhcp6_relay *)cp;
777 	TCHECK(dh6->dh6_xid);
778 	switch (dh6->dh6_msgtype) {
779 	case DH6_SOLICIT:
780 		name = "solicit";
781 		break;
782 	case DH6_ADVERTISE:
783 		name = "advertise";
784 		break;
785 	case DH6_REQUEST:
786 		name = "request";
787 		break;
788 	case DH6_CONFIRM:
789 		name = "confirm";
790 		break;
791 	case DH6_RENEW:
792 		name = "renew";
793 		break;
794 	case DH6_REBIND:
795 		name = "rebind";
796 		break;
797 	case DH6_REPLY:
798 		name = "reply";
799 		break;
800 	case DH6_RELEASE:
801 		name = "release";
802 		break;
803 	case DH6_DECLINE:
804 		name = "decline";
805 		break;
806 	case DH6_RECONFIGURE:
807 		name = "reconfigure";
808 		break;
809 	case DH6_INFORM_REQ:
810 		name= "inf-req";
811 		break;
812 	case DH6_RELAY_FORW:
813 		name= "relay-fwd";
814 		break;
815 	case DH6_RELAY_REPLY:
816 		name= "relay-reply";
817 		break;
818 	case DH6_LEASEQUERY:
819 		name= "leasequery";
820 		break;
821 	case DH6_LQ_REPLY:
822 		name= "leasequery-reply";
823 		break;
824 	default:
825 		name = NULL;
826 		break;
827 	}
828 
829 	if (!vflag) {
830 		if (name)
831 			printf(" %s", name);
832 		else if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
833 		    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
834 			printf(" msgtype-%u", dh6->dh6_msgtype);
835 		}
836 		return;
837 	}
838 
839 	/* XXX relay agent messages have to be handled differently */
840 
841 	if (name)
842 		printf(" %s (", name);	/*)*/
843 	else
844 		printf(" msgtype-%u (", dh6->dh6_msgtype);	/*)*/
845 	if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
846 	    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
847 		printf("xid=%x", EXTRACT_32BITS(&dh6->dh6_xid) & DH6_XIDMASK);
848 		extp = (u_char *)(dh6 + 1);
849 		dhcp6opt_print(extp, ep);
850 	} else {		/* relay messages */
851 		struct in6_addr addr6;
852 
853 		TCHECK(dh6relay->dh6relay_peeraddr);
854 
855 		memcpy(&addr6, dh6relay->dh6relay_linkaddr, sizeof (addr6));
856 		printf("linkaddr=%s", ip6addr_string(&addr6));
857 
858 		memcpy(&addr6, dh6relay->dh6relay_peeraddr, sizeof (addr6));
859 		printf(" peeraddr=%s", ip6addr_string(&addr6));
860 
861 		dhcp6opt_print((u_char *)(dh6relay + 1), ep);
862 	}
863 	/*(*/
864 	printf(")");
865 	return;
866 
867 trunc:
868 	printf("[|dhcp6]");
869 }
870