print-dhcp6.c revision 172683
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
42static 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 */
85struct 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 */
97struct 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
159struct dhcp6opt {
160	u_int16_t dh6opt_type;
161	u_int16_t dh6opt_len;
162	/* type-dependent data follows */
163};
164
165struct 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
173struct 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
181struct 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
190struct 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
200static const char *
201dhcp6opt_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
289static const char *
290dhcp6stcode(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
318static void
319dhcp6opt_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
663trunc:
664	printf("[|dhcp6ext]");
665}
666
667/*
668 * Print dhcp6 packets
669 */
670void
671dhcp6_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
771trunc:
772	printf("[|dhcp6]");
773}
774