xref: /freebsd/contrib/tcpdump/print-dhcp6.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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.35.2.1 2006/10/25 22:04:36 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 
84 /* DHCP6 base packet format */
85 struct dhcp6 {
86 	union {
87 		u_int8_t m;
88 		u_int32_t x;
89 	} dh6_msgtypexid;
90 	/* options follow */
91 };
92 #define dh6_msgtype	dh6_msgtypexid.m
93 #define dh6_xid		dh6_msgtypexid.x
94 #define DH6_XIDMASK	0x00ffffff
95 
96 /* DHCPv6 relay messages */
97 struct dhcp6_relay {
98 	u_int8_t dh6relay_msgtype;
99 	u_int8_t dh6relay_hcnt;
100 	u_int8_t dh6relay_linkaddr[16];	/* XXX: badly aligned */
101 	u_int8_t dh6relay_peeraddr[16];
102 	/* options follow */
103 };
104 
105 /* options */
106 #define DH6OPT_CLIENTID	1
107 #define DH6OPT_SERVERID	2
108 #define DH6OPT_IA_NA 3
109 #define DH6OPT_IA_TA 4
110 #define DH6OPT_IA_ADDR 5
111 #define DH6OPT_ORO 6
112 #define DH6OPT_PREFERENCE 7
113 #  define DH6OPT_PREF_MAX 255
114 #define DH6OPT_ELAPSED_TIME 8
115 #define DH6OPT_RELAY_MSG 9
116 /*#define DH6OPT_SERVER_MSG 10 deprecated */
117 #define DH6OPT_AUTH 11
118 #  define DH6OPT_AUTHPROTO_DELAYED 2
119 #  define DH6OPT_AUTHPROTO_RECONFIG 3
120 #  define DH6OPT_AUTHALG_HMACMD5 1
121 #  define DH6OPT_AUTHRDM_MONOCOUNTER 0
122 #  define DH6OPT_AUTHRECONFIG_KEY 1
123 #  define DH6OPT_AUTHRECONFIG_HMACMD5 2
124 #define DH6OPT_UNICAST 12
125 #define DH6OPT_STATUS_CODE 13
126 #  define DH6OPT_STCODE_SUCCESS 0
127 #  define DH6OPT_STCODE_UNSPECFAIL 1
128 #  define DH6OPT_STCODE_NOADDRAVAIL 2
129 #  define DH6OPT_STCODE_NOBINDING 3
130 #  define DH6OPT_STCODE_NOTONLINK 4
131 #  define DH6OPT_STCODE_USEMULTICAST 5
132 #  define DH6OPT_STCODE_NOPREFIXAVAIL 6
133 #define DH6OPT_RAPID_COMMIT 14
134 #define DH6OPT_USER_CLASS 15
135 #define DH6OPT_VENDOR_CLASS 16
136 #define DH6OPT_VENDOR_OPTS 17
137 #define DH6OPT_INTERFACE_ID 18
138 #define DH6OPT_RECONF_MSG 19
139 #define DH6OPT_RECONF_ACCEPT 20
140 #define DH6OPT_SIP_SERVER_D 21
141 #define DH6OPT_SIP_SERVER_A 22
142 #define DH6OPT_DNS 23
143 #define DH6OPT_DNSNAME 24
144 #define DH6OPT_IA_PD 25
145 #define DH6OPT_IA_PD_PREFIX 26
146 #define DH6OPT_NIS_SERVERS 27
147 #define DH6OPT_NISP_SERVERS 28
148 #define DH6OPT_NIS_NAME 29
149 #define DH6OPT_NISP_NAME 30
150 #define DH6OPT_NTP_SERVERS 31
151 #define DH6OPT_LIFETIME 32
152 #define DH6OPT_BCMCS_SERVER_D 33
153 #define DH6OPT_BCMCS_SERVER_A 34
154 #define DH6OPT_GEOCONF_CIVIC 36
155 #define DH6OPT_REMOTE_ID 37
156 #define DH6OPT_SUBSCRIBER_ID 38
157 #define DH6OPT_CLIENT_FQDN 39
158 
159 struct dhcp6opt {
160 	u_int16_t dh6opt_type;
161 	u_int16_t dh6opt_len;
162 	/* type-dependent data follows */
163 };
164 
165 struct dhcp6_ia {
166 	u_int16_t dh6opt_ia_type;
167 	u_int16_t dh6opt_ia_len;
168 	u_int32_t dh6opt_ia_iaid;
169 	u_int32_t dh6opt_ia_t1;
170 	u_int32_t dh6opt_ia_t2;
171 };
172 
173 struct dhcp6_ia_addr {
174 	u_int16_t dh6opt_ia_addr_type;
175 	u_int16_t dh6opt_ia_addr_len;
176 	struct in6_addr dh6opt_ia_addr_addr;
177 	u_int32_t dh6opt_ia_addr_pltime;
178 	u_int32_t dh6opt_ia_addr_vltime;
179 }  __attribute__ ((__packed__));
180 
181 struct dhcp6_ia_prefix {
182 	u_int16_t dh6opt_ia_prefix_type;
183 	u_int16_t dh6opt_ia_prefix_len;
184 	u_int32_t dh6opt_ia_prefix_pltime;
185 	u_int32_t dh6opt_ia_prefix_vltime;
186 	u_int8_t dh6opt_ia_prefix_plen;
187 	struct in6_addr dh6opt_ia_prefix_addr;
188 }  __attribute__ ((__packed__));
189 
190 struct dhcp6_auth {
191 	u_int16_t dh6opt_auth_type;
192 	u_int16_t dh6opt_auth_len;
193 	u_int8_t dh6opt_auth_proto;
194 	u_int8_t dh6opt_auth_alg;
195 	u_int8_t dh6opt_auth_rdm;
196 	u_int8_t dh6opt_auth_rdinfo[8];
197 	/* authentication information follows */
198 } __attribute__ ((__packed__));
199 
200 static const char *
201 dhcp6opt_name(int type)
202 {
203 	static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */
204 
205 	if (type > 65535)
206 		return "INVALID option";
207 
208 	switch(type) {
209 	case DH6OPT_CLIENTID:
210 		return "client ID";
211 	case DH6OPT_SERVERID:
212 		return "server ID";
213 	case DH6OPT_IA_NA:
214 		return "IA_NA";
215 	case DH6OPT_IA_TA:
216 		return "IA_TA";
217 	case DH6OPT_IA_ADDR:
218 		return "IA_ADDR";
219 	case DH6OPT_ORO:
220 		return "option request";
221 	case DH6OPT_PREFERENCE:
222 		return "preference";
223 	case DH6OPT_ELAPSED_TIME:
224 		return "elapsed time";
225 	case DH6OPT_RELAY_MSG:
226 		return "relay message";
227 	case DH6OPT_AUTH:
228 		return "authentication";
229 	case DH6OPT_UNICAST:
230 		return "server unicast";
231 	case DH6OPT_STATUS_CODE:
232 		return "status code";
233 	case DH6OPT_RAPID_COMMIT:
234 		return "rapid commit";
235 	case DH6OPT_USER_CLASS:
236 		return "user class";
237 	case DH6OPT_VENDOR_CLASS:
238 		return "vendor class";
239 	case DH6OPT_VENDOR_OPTS:
240 		return "vendor-specific info";
241 	case DH6OPT_INTERFACE_ID:
242 		return "interface ID";
243 	case DH6OPT_RECONF_MSG:
244 		return "reconfigure message";
245 	case DH6OPT_RECONF_ACCEPT:
246 		return "reconfigure accept";
247 	case DH6OPT_SIP_SERVER_D:
248 		return "SIP servers domain";
249 	case DH6OPT_SIP_SERVER_A:
250 		return "SIP servers address";
251 	case DH6OPT_DNS:
252 		return "DNS";
253 	case DH6OPT_DNSNAME:
254 		return "DNS name";
255 	case DH6OPT_IA_PD:
256 		return "IA_PD";
257 	case DH6OPT_IA_PD_PREFIX:
258 		return "IA_PD prefix";
259 	case DH6OPT_NTP_SERVERS:
260 		return "NTP Server";
261 	case DH6OPT_LIFETIME:
262 		return "lifetime";
263 	case DH6OPT_NIS_SERVERS:
264 		return "NIS server";
265 	case DH6OPT_NISP_SERVERS:
266 		return "NIS+ server";
267 	case DH6OPT_NIS_NAME:
268 		return "NIS domain name";
269 	case DH6OPT_NISP_NAME:
270 		return "NIS+ domain name";
271 	case DH6OPT_BCMCS_SERVER_D:
272 		return "BCMCS domain name";
273 	case DH6OPT_BCMCS_SERVER_A:
274 		return "BCMCS server";
275 	case DH6OPT_GEOCONF_CIVIC:
276 		return "Geoconf Civic";
277 	case DH6OPT_REMOTE_ID:
278 		return "Remote ID";
279 	case DH6OPT_SUBSCRIBER_ID:
280 		return "Subscriber ID";
281 	case DH6OPT_CLIENT_FQDN:
282 		return "Client FQDN";
283 	default:
284 		snprintf(genstr, sizeof(genstr), "opt_%d", type);
285 		return(genstr);
286 	}
287 }
288 
289 static const char *
290 dhcp6stcode(int code)
291 {
292 	static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */
293 
294 	if (code > 255)
295 		return "INVALID code";
296 
297 	switch(code) {
298 	case DH6OPT_STCODE_SUCCESS:
299 		return "success";
300 	case DH6OPT_STCODE_UNSPECFAIL:
301 		return "unspec failure";
302 	case DH6OPT_STCODE_NOADDRAVAIL:
303 		return "no addresses";
304 	case DH6OPT_STCODE_NOBINDING:
305 		return "no binding";
306 	case DH6OPT_STCODE_NOTONLINK:
307 		return "not on-link";
308 	case DH6OPT_STCODE_USEMULTICAST:
309 		return "use multicast";
310 	case DH6OPT_STCODE_NOPREFIXAVAIL:
311 		return "no prefixes";
312 	default:
313 		snprintf(genstr, sizeof(genstr), "code%d", code);
314 		return(genstr);
315 	}
316 }
317 
318 static void
319 dhcp6opt_print(const u_char *cp, const u_char *ep)
320 {
321 	struct dhcp6opt *dh6o;
322 	u_char *tp;
323 	size_t i;
324 	u_int16_t opttype;
325 	size_t optlen;
326 	u_int16_t val16;
327 	u_int32_t val32;
328 	struct dhcp6_ia ia;
329 	struct dhcp6_ia_prefix ia_prefix;
330 	struct dhcp6_ia_addr ia_addr;
331 	struct dhcp6_auth authopt;
332 	u_int authinfolen, authrealmlen;
333 
334 	if (cp == ep)
335 		return;
336 	while (cp < ep) {
337 		if (ep < cp + sizeof(*dh6o))
338 			goto trunc;
339 		dh6o = (struct dhcp6opt *)cp;
340 		optlen = EXTRACT_16BITS(&dh6o->dh6opt_len);
341 		if (ep < cp + sizeof(*dh6o) + optlen)
342 			goto trunc;
343 		opttype = EXTRACT_16BITS(&dh6o->dh6opt_type);
344 		printf(" (%s", dhcp6opt_name(opttype));
345 		switch (opttype) {
346 		case DH6OPT_CLIENTID:
347 		case DH6OPT_SERVERID:
348 			if (optlen < 2) {
349 				/*(*/
350 				printf(" ?)");
351 				break;
352 			}
353 			tp = (u_char *)(dh6o + 1);
354 			switch (EXTRACT_16BITS(tp)) {
355 			case 1:
356 				if (optlen >= 2 + 6) {
357 					printf(" hwaddr/time type %u time %u ",
358 					    EXTRACT_16BITS(&tp[2]),
359 					    EXTRACT_32BITS(&tp[4]));
360 					for (i = 8; i < optlen; i++)
361 						printf("%02x", tp[i]);
362 					/*(*/
363 					printf(")");
364 				} else {
365 					/*(*/
366 					printf(" ?)");
367 				}
368 				break;
369 			case 2:
370 				if (optlen >= 2 + 8) {
371 					printf(" vid ");
372 					for (i = 2; i < 2 + 8; i++)
373 						printf("%02x", tp[i]);
374 					/*(*/
375 					printf(")");
376 				} else {
377 					/*(*/
378 					printf(" ?)");
379 				}
380 				break;
381 			case 3:
382 				if (optlen >= 2 + 2) {
383 					printf(" hwaddr type %u ",
384 					    EXTRACT_16BITS(&tp[2]));
385 					for (i = 4; i < optlen; i++)
386 						printf("%02x", tp[i]);
387 					/*(*/
388 					printf(")");
389 				} else {
390 					/*(*/
391 					printf(" ?)");
392 				}
393 				break;
394 			default:
395 				printf(" type %d)", EXTRACT_16BITS(tp));
396 				break;
397 			}
398 			break;
399 		case DH6OPT_IA_ADDR:
400 			if (optlen < sizeof(ia_addr) - 4) {
401 				printf(" ?)");
402 				break;
403 			}
404 			memcpy(&ia_addr, (u_char *)dh6o, sizeof(ia_addr));
405 			printf(" %s",
406 			    ip6addr_string(&ia_addr.dh6opt_ia_addr_addr));
407 			ia_addr.dh6opt_ia_addr_pltime =
408 			    ntohl(ia_addr.dh6opt_ia_addr_pltime);
409 			ia_addr.dh6opt_ia_addr_vltime =
410 			    ntohl(ia_addr.dh6opt_ia_addr_vltime);
411 			printf(" pltime:%lu vltime:%lu",
412 			    (unsigned long)ia_addr.dh6opt_ia_addr_pltime,
413 			    (unsigned long)ia_addr.dh6opt_ia_addr_vltime);
414 			if (optlen > sizeof(ia_addr) - 4) {
415 				/* there are sub-options */
416 				dhcp6opt_print((u_char *)dh6o +
417 				    sizeof(ia_addr),
418 				    (u_char *)(dh6o + 1) + optlen);
419 			}
420 			printf(")");
421 			break;
422 		case DH6OPT_ORO:
423 			if (optlen % 2) {
424 				printf(" ?)");
425 				break;
426 			}
427 			tp = (u_char *)(dh6o + 1);
428 			for (i = 0; i < optlen; i += 2) {
429 				u_int16_t opt;
430 
431 				memcpy(&opt, &tp[i], sizeof(opt));
432 				printf(" %s", dhcp6opt_name(ntohs(opt)));
433 			}
434 			printf(")");
435 			break;
436 		case DH6OPT_PREFERENCE:
437 			if (optlen != 1) {
438 				printf(" ?)");
439 				break;
440 			}
441 			printf(" %d)", *((u_char *)(dh6o + 1) + 1));
442 			break;
443 		case DH6OPT_ELAPSED_TIME:
444 			if (optlen != 2) {
445 				printf(" ?)");
446 				break;
447 			}
448 			memcpy(&val16, dh6o + 1, sizeof(val16));
449 			val16 = ntohs(val16);
450 			printf(" %d)", (int)val16);
451 			break;
452 		case DH6OPT_RELAY_MSG:
453 			printf(" (");
454 			dhcp6_print((const u_char *)(dh6o + 1), optlen);
455 			printf(")");
456 			break;
457 		case DH6OPT_AUTH:
458 			if (optlen < sizeof(authopt) - sizeof(*dh6o)) {
459 				printf(" ?)");
460 				break;
461 			}
462 			memcpy(&authopt, dh6o, sizeof(authopt));
463 			switch (authopt.dh6opt_auth_proto) {
464 			case DH6OPT_AUTHPROTO_DELAYED:
465 				printf(" proto: delayed");
466 				break;
467 			case DH6OPT_AUTHPROTO_RECONFIG:
468 				printf(" proto: reconfigure");
469 				break;
470 			default:
471 				printf(" proto: %d",
472 				    authopt.dh6opt_auth_proto);
473 				break;
474 			}
475 			switch (authopt.dh6opt_auth_alg) {
476 			case DH6OPT_AUTHALG_HMACMD5:
477 				/* XXX: may depend on the protocol */
478 				printf(", alg: HMAC-MD5");
479 				break;
480 			default:
481 				printf(", alg: %d", authopt.dh6opt_auth_alg);
482 				break;
483 			}
484 			switch (authopt.dh6opt_auth_rdm) {
485 			case DH6OPT_AUTHRDM_MONOCOUNTER:
486 				printf(", RDM: mono");
487 				break;
488 			default:
489 				printf(", RDM: %d", authopt.dh6opt_auth_rdm);
490 				break;
491 			}
492 			tp = (u_char *)&authopt.dh6opt_auth_rdinfo;
493 			printf(", RD:");
494 			for (i = 0; i < 4; i++, tp += sizeof(val16))
495 				printf(" %04x", EXTRACT_16BITS(tp));
496 
497 			/* protocol dependent part */
498 			tp = (u_char *)dh6o + sizeof(authopt);
499 			authinfolen =
500 			    optlen + sizeof(*dh6o) - sizeof(authopt);
501 			switch (authopt.dh6opt_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 			/*
553 			 * Since we cannot predict the encoding, print hex dump
554 			 * at most 10 characters.
555 			 */
556 			for (i = 0; i < optlen && i < 10; i++)
557 				printf("%02x", ((u_char *)(dh6o + 1))[i]);
558 			break;
559 		case DH6OPT_RECONF_MSG:
560 			tp = (u_char *)(dh6o + 1);
561 			switch (*tp) {
562 			case DH6_RENEW:
563 				printf(" for renew)");
564 				break;
565 			case DH6_INFORM_REQ:
566 				printf(" for inf-req)");
567 				break;
568 			default:
569 				printf(" for ?\?\?(%02x))", *tp);
570 				break;
571 			}
572 			break;
573 		case DH6OPT_RECONF_ACCEPT: /* nothing todo */
574 			printf(")");
575 			break;
576 		case DH6OPT_SIP_SERVER_A:
577 		case DH6OPT_DNS:
578 		case DH6OPT_NTP_SERVERS:
579 		case DH6OPT_NIS_SERVERS:
580 		case DH6OPT_NISP_SERVERS:
581 		case DH6OPT_BCMCS_SERVER_A:
582 			if (optlen % 16) {
583 				printf(" ?)");
584 				break;
585 			}
586 			tp = (u_char *)(dh6o + 1);
587 			for (i = 0; i < optlen; i += 16)
588 				printf(" %s", ip6addr_string(&tp[i]));
589 			printf(")");
590 			break;
591 		case DH6OPT_STATUS_CODE:
592 			if (optlen < 2) {
593 				printf(" ?)");
594 				break;
595 			}
596 			memcpy(&val16, (u_char *)(dh6o + 1), sizeof(val16));
597 			val16 = ntohs(val16);
598 			printf(" %s)", dhcp6stcode(val16));
599 			break;
600 		case DH6OPT_IA_NA:
601 		case DH6OPT_IA_PD:
602 			if (optlen < sizeof(ia) - 4) {
603 				printf(" ?)");
604 				break;
605 			}
606 			memcpy(&ia, (u_char *)dh6o, sizeof(ia));
607 			ia.dh6opt_ia_iaid = ntohl(ia.dh6opt_ia_iaid);
608 			ia.dh6opt_ia_t1 = ntohl(ia.dh6opt_ia_t1);
609 			ia.dh6opt_ia_t2 = ntohl(ia.dh6opt_ia_t2);
610 			printf(" IAID:%lu T1:%lu T2:%lu",
611 			    (unsigned long)ia.dh6opt_ia_iaid,
612 			    (unsigned long)ia.dh6opt_ia_t1,
613 			    (unsigned long)ia.dh6opt_ia_t2);
614 			if (optlen > sizeof(ia) - 4) {
615 				/* there are sub-options */
616 				dhcp6opt_print((u_char *)dh6o + sizeof(ia),
617 				    (u_char *)(dh6o + 1) + optlen);
618 			}
619 			printf(")");
620 			break;
621 		case DH6OPT_IA_PD_PREFIX:
622 			if (optlen < sizeof(ia_prefix) - 4) {
623 				printf(" ?)");
624 				break;
625 			}
626 			memcpy(&ia_prefix, (u_char *)dh6o, sizeof(ia_prefix));
627 			printf(" %s/%d",
628 			    ip6addr_string(&ia_prefix.dh6opt_ia_prefix_addr),
629 			    ia_prefix.dh6opt_ia_prefix_plen);
630 			ia_prefix.dh6opt_ia_prefix_pltime =
631 			    ntohl(ia_prefix.dh6opt_ia_prefix_pltime);
632 			ia_prefix.dh6opt_ia_prefix_vltime =
633 			    ntohl(ia_prefix.dh6opt_ia_prefix_vltime);
634 			printf(" pltime:%lu vltime:%lu",
635 			    (unsigned long)ia_prefix.dh6opt_ia_prefix_pltime,
636 			    (unsigned long)ia_prefix.dh6opt_ia_prefix_vltime);
637 			if (optlen > sizeof(ia_prefix) - 4) {
638 				/* there are sub-options */
639 				dhcp6opt_print((u_char *)dh6o +
640 				    sizeof(ia_prefix),
641 				    (u_char *)(dh6o + 1) + optlen);
642 			}
643 			printf(")");
644 			break;
645 		case DH6OPT_LIFETIME:
646 			if (optlen != 4) {
647 				printf(" ?)");
648 				break;
649 			}
650 			memcpy(&val32, dh6o + 1, sizeof(val32));
651 			val32 = ntohl(val32);
652 			printf(" %d)", (int)val32);
653 			break;
654 		default:
655 			printf(")");
656 			break;
657 		}
658 
659 		cp += sizeof(*dh6o) + optlen;
660 	}
661 	return;
662 
663 trunc:
664 	printf("[|dhcp6ext]");
665 }
666 
667 /*
668  * Print dhcp6 packets
669  */
670 void
671 dhcp6_print(const u_char *cp, u_int length)
672 {
673 	struct dhcp6 *dh6;
674 	struct dhcp6_relay *dh6relay;
675 	const u_char *ep;
676 	u_char *extp;
677 	const char *name;
678 
679 	printf("dhcp6");
680 
681 	ep = (u_char *)snapend;
682 	if (cp + length < ep)
683 		ep = cp + length;
684 
685 	dh6 = (struct dhcp6 *)cp;
686 	dh6relay = (struct dhcp6_relay *)cp;
687 	TCHECK(dh6->dh6_xid);
688 	switch (dh6->dh6_msgtype) {
689 	case DH6_SOLICIT:
690 		name = "solicit";
691 		break;
692 	case DH6_ADVERTISE:
693 		name = "advertise";
694 		break;
695 	case DH6_REQUEST:
696 		name = "request";
697 		break;
698 	case DH6_CONFIRM:
699 		name = "confirm";
700 		break;
701 	case DH6_RENEW:
702 		name = "renew";
703 		break;
704 	case DH6_REBIND:
705 		name = "rebind";
706 		break;
707 	case DH6_REPLY:
708 		name = "reply";
709 		break;
710 	case DH6_RELEASE:
711 		name = "release";
712 		break;
713 	case DH6_DECLINE:
714 		name = "decline";
715 		break;
716 	case DH6_RECONFIGURE:
717 		name = "reconfigure";
718 		break;
719 	case DH6_INFORM_REQ:
720 		name= "inf-req";
721 		break;
722 	case DH6_RELAY_FORW:
723 		name= "relay-fwd";
724 		break;
725 	case DH6_RELAY_REPLY:
726 		name= "relay-reply";
727 		break;
728 	default:
729 		name = NULL;
730 		break;
731 	}
732 
733 	if (!vflag) {
734 		if (name)
735 			printf(" %s", name);
736 		else if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
737 		    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
738 			printf(" msgtype-%u", dh6->dh6_msgtype);
739 		}
740 		return;
741 	}
742 
743 	/* XXX relay agent messages have to be handled differently */
744 
745 	if (name)
746 		printf(" %s (", name);	/*)*/
747 	else
748 		printf(" msgtype-%u (", dh6->dh6_msgtype);	/*)*/
749 	if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
750 	    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
751 		printf("xid=%x", EXTRACT_32BITS(&dh6->dh6_xid) & DH6_XIDMASK);
752 		extp = (u_char *)(dh6 + 1);
753 		dhcp6opt_print(extp, ep);
754 	} else {		/* relay messages */
755 		struct in6_addr addr6;
756 
757 		TCHECK(dh6relay->dh6relay_peeraddr);
758 
759 		memcpy(&addr6, dh6relay->dh6relay_linkaddr, sizeof (addr6));
760 		printf("linkaddr=%s", ip6addr_string(&addr6));
761 
762 		memcpy(&addr6, dh6relay->dh6relay_peeraddr, sizeof (addr6));
763 		printf(" peeraddr=%s", ip6addr_string(&addr6));
764 
765 		dhcp6opt_print((u_char *)(dh6relay + 1), ep);
766 	}
767 	/*(*/
768 	printf(")");
769 	return;
770 
771 trunc:
772 	printf("[|dhcp6]");
773 }
774