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
43static 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 */
88struct 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 */
100struct 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
176struct dhcp6opt {
177	u_int16_t dh6opt_type;
178	u_int16_t dh6opt_len;
179	/* type-dependent data follows */
180};
181
182static const char *
183dhcp6opt_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
291static const char *
292dhcp6stcode(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
328static void
329dhcp6opt_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
753trunc:
754	printf("[|dhcp6ext]");
755}
756
757/*
758 * Print dhcp6 packets
759 */
760void
761dhcp6_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
867trunc:
868	printf("[|dhcp6]");
869}
870