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