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
44static 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$");
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 */
92struct 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 */
104struct 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
179struct dhcp6opt {
180	u_int16_t dh6opt_type;
181	u_int16_t dh6opt_len;
182	/* type-dependent data follows */
183};
184
185static const char *
186dhcp6opt_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
292static const char *
293dhcp6stcode(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
329static void
330dhcp6opt_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
729trunc:
730	printf("[|dhcp6ext]");
731}
732
733/*
734 * Print dhcp6 packets
735 */
736void
737dhcp6_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
843trunc:
844	printf("[|dhcp6]");
845}
846