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