xref: /netbsd/external/bsd/tcpdump/dist/print-dhcp6.c (revision 6550d01e)
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 #include <sys/cdefs.h>
42 #ifndef lint
43 #if 0
44 static const char rcsid[] _U_ =
45     "@(#) Header: /tcpdump/master/tcpdump/print-dhcp6.c,v 1.37 2008-02-06 10:26:09 guy Exp";
46 #else
47 __RCSID("$NetBSD: print-dhcp6.c,v 1.2 2010/12/05 05:11:30 christos Exp $");
48 #endif
49 #endif
50 
51 #ifdef HAVE_CONFIG_H
52 #include "config.h"
53 #endif
54 
55 #include <tcpdump-stdinc.h>
56 
57 #include <stdio.h>
58 #include <string.h>
59 
60 #include "interface.h"
61 #include "addrtoname.h"
62 #include "extract.h"
63 
64 /* lease duration */
65 #define DHCP6_DURATITION_INFINITE 0xffffffff
66 
67 /* Error Values */
68 #define DH6ERR_FAILURE		16
69 #define DH6ERR_AUTHFAIL		17
70 #define DH6ERR_POORLYFORMED	18
71 #define DH6ERR_UNAVAIL		19
72 #define DH6ERR_OPTUNAVAIL	20
73 
74 /* Message type */
75 #define DH6_SOLICIT	1
76 #define DH6_ADVERTISE	2
77 #define DH6_REQUEST	3
78 #define DH6_CONFIRM	4
79 #define DH6_RENEW	5
80 #define DH6_REBIND	6
81 #define DH6_REPLY	7
82 #define DH6_RELEASE	8
83 #define DH6_DECLINE	9
84 #define DH6_RECONFIGURE	10
85 #define DH6_INFORM_REQ	11
86 #define DH6_RELAY_FORW	12
87 #define DH6_RELAY_REPLY	13
88 #define DH6_LEASEQUERY	14
89 #define DH6_LQ_REPLY	15
90 
91 /* DHCP6 base packet format */
92 struct dhcp6 {
93 	union {
94 		u_int8_t m;
95 		u_int32_t x;
96 	} dh6_msgtypexid;
97 	/* options follow */
98 };
99 #define dh6_msgtype	dh6_msgtypexid.m
100 #define dh6_xid		dh6_msgtypexid.x
101 #define DH6_XIDMASK	0x00ffffff
102 
103 /* DHCPv6 relay messages */
104 struct dhcp6_relay {
105 	u_int8_t dh6relay_msgtype;
106 	u_int8_t dh6relay_hcnt;
107 	u_int8_t dh6relay_linkaddr[16];	/* XXX: badly aligned */
108 	u_int8_t dh6relay_peeraddr[16];
109 	/* options follow */
110 };
111 
112 /* options */
113 #define DH6OPT_CLIENTID	1
114 #define DH6OPT_SERVERID	2
115 #define DH6OPT_IA_NA 3
116 #define DH6OPT_IA_TA 4
117 #define DH6OPT_IA_ADDR 5
118 #define DH6OPT_ORO 6
119 #define DH6OPT_PREFERENCE 7
120 #  define DH6OPT_PREF_MAX 255
121 #define DH6OPT_ELAPSED_TIME 8
122 #define DH6OPT_RELAY_MSG 9
123 /*#define DH6OPT_SERVER_MSG 10 deprecated */
124 #define DH6OPT_AUTH 11
125 #  define DH6OPT_AUTHPROTO_DELAYED 2
126 #  define DH6OPT_AUTHPROTO_RECONFIG 3
127 #  define DH6OPT_AUTHALG_HMACMD5 1
128 #  define DH6OPT_AUTHRDM_MONOCOUNTER 0
129 #  define DH6OPT_AUTHRECONFIG_KEY 1
130 #  define DH6OPT_AUTHRECONFIG_HMACMD5 2
131 #define DH6OPT_UNICAST 12
132 #define DH6OPT_STATUS_CODE 13
133 #  define DH6OPT_STCODE_SUCCESS 0
134 #  define DH6OPT_STCODE_UNSPECFAIL 1
135 #  define DH6OPT_STCODE_NOADDRAVAIL 2
136 #  define DH6OPT_STCODE_NOBINDING 3
137 #  define DH6OPT_STCODE_NOTONLINK 4
138 #  define DH6OPT_STCODE_USEMULTICAST 5
139 #  define DH6OPT_STCODE_NOPREFIXAVAIL 6
140 #  define DH6OPT_STCODE_UNKNOWNQUERYTYPE 7
141 #  define DH6OPT_STCODE_MALFORMEDQUERY 8
142 #  define DH6OPT_STCODE_NOTCONFIGURED 9
143 #  define DH6OPT_STCODE_NOTALLOWED 10
144 #define DH6OPT_RAPID_COMMIT 14
145 #define DH6OPT_USER_CLASS 15
146 #define DH6OPT_VENDOR_CLASS 16
147 #define DH6OPT_VENDOR_OPTS 17
148 #define DH6OPT_INTERFACE_ID 18
149 #define DH6OPT_RECONF_MSG 19
150 #define DH6OPT_RECONF_ACCEPT 20
151 #define DH6OPT_SIP_SERVER_D 21
152 #define DH6OPT_SIP_SERVER_A 22
153 #define DH6OPT_DNS 23
154 #define DH6OPT_DNSNAME 24
155 #define DH6OPT_IA_PD 25
156 #define DH6OPT_IA_PD_PREFIX 26
157 #define DH6OPT_NIS_SERVERS 27
158 #define DH6OPT_NISP_SERVERS 28
159 #define DH6OPT_NIS_NAME 29
160 #define DH6OPT_NISP_NAME 30
161 #define DH6OPT_NTP_SERVERS 31
162 #define DH6OPT_LIFETIME 32
163 #define DH6OPT_BCMCS_SERVER_D 33
164 #define DH6OPT_BCMCS_SERVER_A 34
165 #define DH6OPT_GEOCONF_CIVIC 36
166 #define DH6OPT_REMOTE_ID 37
167 #define DH6OPT_SUBSCRIBER_ID 38
168 #define DH6OPT_CLIENT_FQDN 39
169 #define DH6OPT_PANA_AGENT 40
170 #define DH6OPT_NEW_POSIX_TIMEZONE 41
171 #define DH6OPT_NEW_TZDB_TIMEZONE 42
172 #define DH6OPT_ERO 43
173 #define DH6OPT_LQ_QUERY 44
174 #define DH6OPT_CLIENT_DATA 45
175 #define DH6OPT_CLT_TIME 46
176 #define DH6OPT_LQ_RELAY_DATA 47
177 #define DH6OPT_LQ_CLIENT_LINK 48
178 
179 struct dhcp6opt {
180 	u_int16_t dh6opt_type;
181 	u_int16_t dh6opt_len;
182 	/* type-dependent data follows */
183 };
184 
185 static const char *
186 dhcp6opt_name(int type)
187 {
188 	static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */
189 
190 	if (type > 65535)
191 		return "INVALID-option";
192 
193 	switch(type) {
194 	case DH6OPT_CLIENTID:
195 		return "client-ID";
196 	case DH6OPT_SERVERID:
197 		return "server-ID";
198 	case DH6OPT_IA_NA:
199 		return "IA_NA";
200 	case DH6OPT_IA_TA:
201 		return "IA_TA";
202 	case DH6OPT_IA_ADDR:
203 		return "IA_ADDR";
204 	case DH6OPT_ORO:
205 		return "option-request";
206 	case DH6OPT_PREFERENCE:
207 		return "preference";
208 	case DH6OPT_ELAPSED_TIME:
209 		return "elapsed-time";
210 	case DH6OPT_RELAY_MSG:
211 		return "relay-message";
212 	case DH6OPT_AUTH:
213 		return "authentication";
214 	case DH6OPT_UNICAST:
215 		return "server-unicast";
216 	case DH6OPT_STATUS_CODE:
217 		return "status-code";
218 	case DH6OPT_RAPID_COMMIT:
219 		return "rapid-commit";
220 	case DH6OPT_USER_CLASS:
221 		return "user-class";
222 	case DH6OPT_VENDOR_CLASS:
223 		return "vendor-class";
224 	case DH6OPT_VENDOR_OPTS:
225 		return "vendor-specific-info";
226 	case DH6OPT_INTERFACE_ID:
227 		return "interface-ID";
228 	case DH6OPT_RECONF_MSG:
229 		return "reconfigure-message";
230 	case DH6OPT_RECONF_ACCEPT:
231 		return "reconfigure-accept";
232 	case DH6OPT_SIP_SERVER_D:
233 		return "SIP-servers-domain";
234 	case DH6OPT_SIP_SERVER_A:
235 		return "SIP-servers-address";
236 	case DH6OPT_DNS:
237 		return "DNS";
238 	case DH6OPT_DNSNAME:
239 		return "DNS-name";
240 	case DH6OPT_IA_PD:
241 		return "IA_PD";
242 	case DH6OPT_IA_PD_PREFIX:
243 		return "IA_PD-prefix";
244 	case DH6OPT_NTP_SERVERS:
245 		return "NTP-Server";
246 	case DH6OPT_LIFETIME:
247 		return "lifetime";
248 	case DH6OPT_NIS_SERVERS:
249 		return "NIS-server";
250 	case DH6OPT_NISP_SERVERS:
251 		return "NIS+-server";
252 	case DH6OPT_NIS_NAME:
253 		return "NIS-domain-name";
254 	case DH6OPT_NISP_NAME:
255 		return "NIS+-domain-name";
256 	case DH6OPT_BCMCS_SERVER_D:
257 		return "BCMCS-domain-name";
258 	case DH6OPT_BCMCS_SERVER_A:
259 		return "BCMCS-server";
260 	case DH6OPT_GEOCONF_CIVIC:
261 		return "Geoconf-Civic";
262 	case DH6OPT_REMOTE_ID:
263 		return "Remote-ID";
264 	case DH6OPT_SUBSCRIBER_ID:
265 		return "Subscriber-ID";
266 	case DH6OPT_CLIENT_FQDN:
267 		return "Client-FQDN";
268 	case DH6OPT_PANA_AGENT:
269 		return "PANA-agent";
270 	case DH6OPT_NEW_POSIX_TIMEZONE:
271 		return "POSIX-timezone";
272 	case DH6OPT_NEW_TZDB_TIMEZONE:
273 		return "POSIX-tz-database";
274 	case DH6OPT_ERO:
275 		return "Echo-request-option";
276 	case DH6OPT_LQ_QUERY:
277 		return "Lease-query";
278 	case DH6OPT_CLIENT_DATA:
279 		return "LQ-client-data";
280 	case DH6OPT_CLT_TIME:
281 		return "Clt-time";
282 	case DH6OPT_LQ_RELAY_DATA:
283 		return "LQ-relay-data";
284 	case DH6OPT_LQ_CLIENT_LINK:
285 		return "LQ-client-link";
286 	default:
287 		snprintf(genstr, sizeof(genstr), "opt_%d", type);
288 		return(genstr);
289 	}
290 }
291 
292 static const char *
293 dhcp6stcode(int code)
294 {
295 	static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */
296 
297 	if (code > 255)
298 		return "INVALID code";
299 
300 	switch(code) {
301 	case DH6OPT_STCODE_SUCCESS:
302 		return "success";
303 	case DH6OPT_STCODE_UNSPECFAIL:
304 		return "unspec failure";
305 	case DH6OPT_STCODE_NOADDRAVAIL:
306 		return "no addresses";
307 	case DH6OPT_STCODE_NOBINDING:
308 		return "no binding";
309 	case DH6OPT_STCODE_NOTONLINK:
310 		return "not on-link";
311 	case DH6OPT_STCODE_USEMULTICAST:
312 		return "use multicast";
313 	case DH6OPT_STCODE_NOPREFIXAVAIL:
314 		return "no prefixes";
315 	case DH6OPT_STCODE_UNKNOWNQUERYTYPE:
316 		return "unknown query type";
317 	case DH6OPT_STCODE_MALFORMEDQUERY:
318 		return "malformed query";
319 	case DH6OPT_STCODE_NOTCONFIGURED:
320 		return "not configured";
321 	case DH6OPT_STCODE_NOTALLOWED:
322 		return "not allowed";
323 	default:
324 		snprintf(genstr, sizeof(genstr), "code%d", code);
325 		return(genstr);
326 	}
327 }
328 
329 static void
330 dhcp6opt_print(const u_char *cp, const u_char *ep)
331 {
332 	struct dhcp6opt *dh6o;
333 	u_char *tp;
334 	size_t i;
335 	u_int16_t opttype;
336 	size_t optlen;
337 	u_int8_t auth_proto;
338 	u_int authinfolen, authrealmlen;
339 
340 	if (cp == ep)
341 		return;
342 	while (cp < ep) {
343 		if (ep < cp + sizeof(*dh6o))
344 			goto trunc;
345 		dh6o = (struct dhcp6opt *)cp;
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 + 24 + 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 + 12 + 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 + 4 + 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 + 25 + 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 		default:
721 			printf(")");
722 			break;
723 		}
724 
725 		cp += sizeof(*dh6o) + optlen;
726 	}
727 	return;
728 
729 trunc:
730 	printf("[|dhcp6ext]");
731 }
732 
733 /*
734  * Print dhcp6 packets
735  */
736 void
737 dhcp6_print(const u_char *cp, u_int length)
738 {
739 	struct dhcp6 *dh6;
740 	struct dhcp6_relay *dh6relay;
741 	const u_char *ep;
742 	u_char *extp;
743 	const char *name;
744 
745 	printf("dhcp6");
746 
747 	ep = (u_char *)snapend;
748 	if (cp + length < ep)
749 		ep = cp + length;
750 
751 	dh6 = (struct dhcp6 *)cp;
752 	dh6relay = (struct dhcp6_relay *)cp;
753 	TCHECK(dh6->dh6_xid);
754 	switch (dh6->dh6_msgtype) {
755 	case DH6_SOLICIT:
756 		name = "solicit";
757 		break;
758 	case DH6_ADVERTISE:
759 		name = "advertise";
760 		break;
761 	case DH6_REQUEST:
762 		name = "request";
763 		break;
764 	case DH6_CONFIRM:
765 		name = "confirm";
766 		break;
767 	case DH6_RENEW:
768 		name = "renew";
769 		break;
770 	case DH6_REBIND:
771 		name = "rebind";
772 		break;
773 	case DH6_REPLY:
774 		name = "reply";
775 		break;
776 	case DH6_RELEASE:
777 		name = "release";
778 		break;
779 	case DH6_DECLINE:
780 		name = "decline";
781 		break;
782 	case DH6_RECONFIGURE:
783 		name = "reconfigure";
784 		break;
785 	case DH6_INFORM_REQ:
786 		name= "inf-req";
787 		break;
788 	case DH6_RELAY_FORW:
789 		name= "relay-fwd";
790 		break;
791 	case DH6_RELAY_REPLY:
792 		name= "relay-reply";
793 		break;
794 	case DH6_LEASEQUERY:
795 		name= "leasequery";
796 		break;
797 	case DH6_LQ_REPLY:
798 		name= "leasequery-reply";
799 		break;
800 	default:
801 		name = NULL;
802 		break;
803 	}
804 
805 	if (!vflag) {
806 		if (name)
807 			printf(" %s", name);
808 		else if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
809 		    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
810 			printf(" msgtype-%u", dh6->dh6_msgtype);
811 		}
812 		return;
813 	}
814 
815 	/* XXX relay agent messages have to be handled differently */
816 
817 	if (name)
818 		printf(" %s (", name);	/*)*/
819 	else
820 		printf(" msgtype-%u (", dh6->dh6_msgtype);	/*)*/
821 	if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
822 	    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
823 		printf("xid=%x", EXTRACT_32BITS(&dh6->dh6_xid) & DH6_XIDMASK);
824 		extp = (u_char *)(dh6 + 1);
825 		dhcp6opt_print(extp, ep);
826 	} else {		/* relay messages */
827 		struct in6_addr addr6;
828 
829 		TCHECK(dh6relay->dh6relay_peeraddr);
830 
831 		memcpy(&addr6, dh6relay->dh6relay_linkaddr, sizeof (addr6));
832 		printf("linkaddr=%s", ip6addr_string(&addr6));
833 
834 		memcpy(&addr6, dh6relay->dh6relay_peeraddr, sizeof (addr6));
835 		printf(" peeraddr=%s", ip6addr_string(&addr6));
836 
837 		dhcp6opt_print((u_char *)(dh6relay + 1), ep);
838 	}
839 	/*(*/
840 	printf(")");
841 	return;
842 
843 trunc:
844 	printf("[|dhcp6]");
845 }
846