print-dhcp6.c revision 190207
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.36.2.1 2008-02-06 10:26:27 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
180struct dhcp6_ia {
181	u_int16_t dh6opt_ia_type;
182	u_int16_t dh6opt_ia_len;
183	u_int32_t dh6opt_ia_iaid;
184	u_int32_t dh6opt_ia_t1;
185	u_int32_t dh6opt_ia_t2;
186};
187
188struct dhcp6_ia_addr {
189	u_int16_t dh6opt_ia_addr_type;
190	u_int16_t dh6opt_ia_addr_len;
191	struct in6_addr dh6opt_ia_addr_addr;
192	u_int32_t dh6opt_ia_addr_pltime;
193	u_int32_t dh6opt_ia_addr_vltime;
194}  __attribute__ ((__packed__));
195
196struct dhcp6_ia_prefix {
197	u_int16_t dh6opt_ia_prefix_type;
198	u_int16_t dh6opt_ia_prefix_len;
199	u_int32_t dh6opt_ia_prefix_pltime;
200	u_int32_t dh6opt_ia_prefix_vltime;
201	u_int8_t dh6opt_ia_prefix_plen;
202	struct in6_addr dh6opt_ia_prefix_addr;
203}  __attribute__ ((__packed__));
204
205struct dhcp6_auth {
206	u_int16_t dh6opt_auth_type;
207	u_int16_t dh6opt_auth_len;
208	u_int8_t dh6opt_auth_proto;
209	u_int8_t dh6opt_auth_alg;
210	u_int8_t dh6opt_auth_rdm;
211	u_int8_t dh6opt_auth_rdinfo[8];
212	/* authentication information follows */
213} __attribute__ ((__packed__));
214
215static const char *
216dhcp6opt_name(int type)
217{
218	static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */
219
220	if (type > 65535)
221		return "INVALID option";
222
223	switch(type) {
224	case DH6OPT_CLIENTID:
225		return "client ID";
226	case DH6OPT_SERVERID:
227		return "server ID";
228	case DH6OPT_IA_NA:
229		return "IA_NA";
230	case DH6OPT_IA_TA:
231		return "IA_TA";
232	case DH6OPT_IA_ADDR:
233		return "IA_ADDR";
234	case DH6OPT_ORO:
235		return "option request";
236	case DH6OPT_PREFERENCE:
237		return "preference";
238	case DH6OPT_ELAPSED_TIME:
239		return "elapsed time";
240	case DH6OPT_RELAY_MSG:
241		return "relay message";
242	case DH6OPT_AUTH:
243		return "authentication";
244	case DH6OPT_UNICAST:
245		return "server unicast";
246	case DH6OPT_STATUS_CODE:
247		return "status code";
248	case DH6OPT_RAPID_COMMIT:
249		return "rapid commit";
250	case DH6OPT_USER_CLASS:
251		return "user class";
252	case DH6OPT_VENDOR_CLASS:
253		return "vendor class";
254	case DH6OPT_VENDOR_OPTS:
255		return "vendor-specific info";
256	case DH6OPT_INTERFACE_ID:
257		return "interface ID";
258	case DH6OPT_RECONF_MSG:
259		return "reconfigure message";
260	case DH6OPT_RECONF_ACCEPT:
261		return "reconfigure accept";
262	case DH6OPT_SIP_SERVER_D:
263		return "SIP servers domain";
264	case DH6OPT_SIP_SERVER_A:
265		return "SIP servers address";
266	case DH6OPT_DNS:
267		return "DNS";
268	case DH6OPT_DNSNAME:
269		return "DNS name";
270	case DH6OPT_IA_PD:
271		return "IA_PD";
272	case DH6OPT_IA_PD_PREFIX:
273		return "IA_PD prefix";
274	case DH6OPT_NTP_SERVERS:
275		return "NTP Server";
276	case DH6OPT_LIFETIME:
277		return "lifetime";
278	case DH6OPT_NIS_SERVERS:
279		return "NIS server";
280	case DH6OPT_NISP_SERVERS:
281		return "NIS+ server";
282	case DH6OPT_NIS_NAME:
283		return "NIS domain name";
284	case DH6OPT_NISP_NAME:
285		return "NIS+ domain name";
286	case DH6OPT_BCMCS_SERVER_D:
287		return "BCMCS domain name";
288	case DH6OPT_BCMCS_SERVER_A:
289		return "BCMCS server";
290	case DH6OPT_GEOCONF_CIVIC:
291		return "Geoconf Civic";
292	case DH6OPT_REMOTE_ID:
293		return "Remote ID";
294	case DH6OPT_SUBSCRIBER_ID:
295		return "Subscriber ID";
296	case DH6OPT_CLIENT_FQDN:
297		return "Client FQDN";
298	case DH6OPT_PANA_AGENT:
299		return "PANA agent";
300	case DH6OPT_NEW_POSIX_TIMEZONE:
301		return "POSIX timezone";
302	case DH6OPT_NEW_TZDB_TIMEZONE:
303		return "POSIX tz database";
304	case DH6OPT_ERO:
305		return "Echo request option";
306	case DH6OPT_LQ_QUERY:
307		return "Lease query";
308	case DH6OPT_CLIENT_DATA:
309		return "LQ client data";
310	case DH6OPT_CLT_TIME:
311		return "Clt time";
312	case DH6OPT_LQ_RELAY_DATA:
313		return "LQ relay data";
314	case DH6OPT_LQ_CLIENT_LINK:
315		return "LQ client link";
316	default:
317		snprintf(genstr, sizeof(genstr), "opt_%d", type);
318		return(genstr);
319	}
320}
321
322static const char *
323dhcp6stcode(int code)
324{
325	static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */
326
327	if (code > 255)
328		return "INVALID code";
329
330	switch(code) {
331	case DH6OPT_STCODE_SUCCESS:
332		return "success";
333	case DH6OPT_STCODE_UNSPECFAIL:
334		return "unspec failure";
335	case DH6OPT_STCODE_NOADDRAVAIL:
336		return "no addresses";
337	case DH6OPT_STCODE_NOBINDING:
338		return "no binding";
339	case DH6OPT_STCODE_NOTONLINK:
340		return "not on-link";
341	case DH6OPT_STCODE_USEMULTICAST:
342		return "use multicast";
343	case DH6OPT_STCODE_NOPREFIXAVAIL:
344		return "no prefixes";
345	case DH6OPT_STCODE_UNKNOWNQUERYTYPE:
346		return "unknown query type";
347	case DH6OPT_STCODE_MALFORMEDQUERY:
348		return "malformed query";
349	case DH6OPT_STCODE_NOTCONFIGURED:
350		return "not configured";
351	case DH6OPT_STCODE_NOTALLOWED:
352		return "not allowed";
353	default:
354		snprintf(genstr, sizeof(genstr), "code%d", code);
355		return(genstr);
356	}
357}
358
359static void
360dhcp6opt_print(const u_char *cp, const u_char *ep)
361{
362	struct dhcp6opt *dh6o;
363	u_char *tp;
364	size_t i;
365	u_int16_t opttype;
366	size_t optlen;
367	u_int16_t val16;
368	u_int32_t val32;
369	struct dhcp6_ia ia;
370	struct dhcp6_ia_prefix ia_prefix;
371	struct dhcp6_ia_addr ia_addr;
372	struct dhcp6_auth authopt;
373	u_int authinfolen, authrealmlen;
374
375	if (cp == ep)
376		return;
377	while (cp < ep) {
378		if (ep < cp + sizeof(*dh6o))
379			goto trunc;
380		dh6o = (struct dhcp6opt *)cp;
381		optlen = EXTRACT_16BITS(&dh6o->dh6opt_len);
382		if (ep < cp + sizeof(*dh6o) + optlen)
383			goto trunc;
384		opttype = EXTRACT_16BITS(&dh6o->dh6opt_type);
385		printf(" (%s", dhcp6opt_name(opttype));
386		switch (opttype) {
387		case DH6OPT_CLIENTID:
388		case DH6OPT_SERVERID:
389			if (optlen < 2) {
390				/*(*/
391				printf(" ?)");
392				break;
393			}
394			tp = (u_char *)(dh6o + 1);
395			switch (EXTRACT_16BITS(tp)) {
396			case 1:
397				if (optlen >= 2 + 6) {
398					printf(" hwaddr/time type %u time %u ",
399					    EXTRACT_16BITS(&tp[2]),
400					    EXTRACT_32BITS(&tp[4]));
401					for (i = 8; i < optlen; i++)
402						printf("%02x", tp[i]);
403					/*(*/
404					printf(")");
405				} else {
406					/*(*/
407					printf(" ?)");
408				}
409				break;
410			case 2:
411				if (optlen >= 2 + 8) {
412					printf(" vid ");
413					for (i = 2; i < 2 + 8; i++)
414						printf("%02x", tp[i]);
415					/*(*/
416					printf(")");
417				} else {
418					/*(*/
419					printf(" ?)");
420				}
421				break;
422			case 3:
423				if (optlen >= 2 + 2) {
424					printf(" hwaddr type %u ",
425					    EXTRACT_16BITS(&tp[2]));
426					for (i = 4; i < optlen; i++)
427						printf("%02x", tp[i]);
428					/*(*/
429					printf(")");
430				} else {
431					/*(*/
432					printf(" ?)");
433				}
434				break;
435			default:
436				printf(" type %d)", EXTRACT_16BITS(tp));
437				break;
438			}
439			break;
440		case DH6OPT_IA_ADDR:
441			if (optlen < sizeof(ia_addr) - 4) {
442				printf(" ?)");
443				break;
444			}
445			memcpy(&ia_addr, (u_char *)dh6o, sizeof(ia_addr));
446			printf(" %s",
447			    ip6addr_string(&ia_addr.dh6opt_ia_addr_addr));
448			ia_addr.dh6opt_ia_addr_pltime =
449			    ntohl(ia_addr.dh6opt_ia_addr_pltime);
450			ia_addr.dh6opt_ia_addr_vltime =
451			    ntohl(ia_addr.dh6opt_ia_addr_vltime);
452			printf(" pltime:%lu vltime:%lu",
453			    (unsigned long)ia_addr.dh6opt_ia_addr_pltime,
454			    (unsigned long)ia_addr.dh6opt_ia_addr_vltime);
455			if (optlen > sizeof(ia_addr) - 4) {
456				/* there are sub-options */
457				dhcp6opt_print((u_char *)dh6o +
458				    sizeof(ia_addr),
459				    (u_char *)(dh6o + 1) + optlen);
460			}
461			printf(")");
462			break;
463		case DH6OPT_ORO:
464		case DH6OPT_ERO:
465			if (optlen % 2) {
466				printf(" ?)");
467				break;
468			}
469			tp = (u_char *)(dh6o + 1);
470			for (i = 0; i < optlen; i += 2) {
471				u_int16_t opt;
472
473				memcpy(&opt, &tp[i], sizeof(opt));
474				printf(" %s", dhcp6opt_name(ntohs(opt)));
475			}
476			printf(")");
477			break;
478		case DH6OPT_PREFERENCE:
479			if (optlen != 1) {
480				printf(" ?)");
481				break;
482			}
483			printf(" %d)", *((u_char *)(dh6o + 1) + 1));
484			break;
485		case DH6OPT_ELAPSED_TIME:
486			if (optlen != 2) {
487				printf(" ?)");
488				break;
489			}
490			memcpy(&val16, dh6o + 1, sizeof(val16));
491			val16 = ntohs(val16);
492			printf(" %d)", (int)val16);
493			break;
494		case DH6OPT_RELAY_MSG:
495			printf(" (");
496			dhcp6_print((const u_char *)(dh6o + 1), optlen);
497			printf(")");
498			break;
499		case DH6OPT_AUTH:
500			if (optlen < sizeof(authopt) - sizeof(*dh6o)) {
501				printf(" ?)");
502				break;
503			}
504			memcpy(&authopt, dh6o, sizeof(authopt));
505			switch (authopt.dh6opt_auth_proto) {
506			case DH6OPT_AUTHPROTO_DELAYED:
507				printf(" proto: delayed");
508				break;
509			case DH6OPT_AUTHPROTO_RECONFIG:
510				printf(" proto: reconfigure");
511				break;
512			default:
513				printf(" proto: %d",
514				    authopt.dh6opt_auth_proto);
515				break;
516			}
517			switch (authopt.dh6opt_auth_alg) {
518			case DH6OPT_AUTHALG_HMACMD5:
519				/* XXX: may depend on the protocol */
520				printf(", alg: HMAC-MD5");
521				break;
522			default:
523				printf(", alg: %d", authopt.dh6opt_auth_alg);
524				break;
525			}
526			switch (authopt.dh6opt_auth_rdm) {
527			case DH6OPT_AUTHRDM_MONOCOUNTER:
528				printf(", RDM: mono");
529				break;
530			default:
531				printf(", RDM: %d", authopt.dh6opt_auth_rdm);
532				break;
533			}
534			tp = (u_char *)&authopt.dh6opt_auth_rdinfo;
535			printf(", RD:");
536			for (i = 0; i < 4; i++, tp += sizeof(val16))
537				printf(" %04x", EXTRACT_16BITS(tp));
538
539			/* protocol dependent part */
540			tp = (u_char *)dh6o + sizeof(authopt);
541			authinfolen =
542			    optlen + sizeof(*dh6o) - sizeof(authopt);
543			switch (authopt.dh6opt_auth_proto) {
544			case DH6OPT_AUTHPROTO_DELAYED:
545				if (authinfolen == 0)
546					break;
547				if (authinfolen < 20) {
548					printf(" ??");
549					break;
550				}
551				authrealmlen = authinfolen - 20;
552				if (authrealmlen > 0) {
553					printf(", realm: ");
554				}
555				for (i = 0; i < authrealmlen; i++, tp++)
556					printf("%02x", *tp);
557				printf(", key ID: %08x", EXTRACT_32BITS(tp));
558				tp += 4;
559				printf(", HMAC-MD5:");
560				for (i = 0; i < 4; i++, tp+= 4)
561					printf(" %08x", EXTRACT_32BITS(tp));
562				break;
563			case DH6OPT_AUTHPROTO_RECONFIG:
564				if (authinfolen != 17) {
565					printf(" ??");
566					break;
567				}
568				switch (*tp++) {
569				case DH6OPT_AUTHRECONFIG_KEY:
570					printf(" reconfig-key");
571					break;
572				case DH6OPT_AUTHRECONFIG_HMACMD5:
573					printf(" type: HMAC-MD5");
574					break;
575				default:
576					printf(" type: ??");
577					break;
578				}
579				printf(" value:");
580				for (i = 0; i < 4; i++, tp+= 4)
581					printf(" %08x", EXTRACT_32BITS(tp));
582				break;
583			default:
584				printf(" ??");
585				break;
586			}
587
588			printf(")");
589			break;
590		case DH6OPT_RAPID_COMMIT: /* nothing todo */
591			printf(")");
592			break;
593		case DH6OPT_INTERFACE_ID:
594		case DH6OPT_SUBSCRIBER_ID:
595			/*
596			 * Since we cannot predict the encoding, print hex dump
597			 * at most 10 characters.
598			 */
599			printf(" ");
600			for (i = 0; i < optlen && i < 10; i++)
601				printf("%02x", ((u_char *)(dh6o + 1))[i]);
602			printf("...)");
603			break;
604		case DH6OPT_RECONF_MSG:
605			tp = (u_char *)(dh6o + 1);
606			switch (*tp) {
607			case DH6_RENEW:
608				printf(" for renew)");
609				break;
610			case DH6_INFORM_REQ:
611				printf(" for inf-req)");
612				break;
613			default:
614				printf(" for ?\?\?(%02x))", *tp);
615				break;
616			}
617			break;
618		case DH6OPT_RECONF_ACCEPT: /* nothing todo */
619			printf(")");
620			break;
621		case DH6OPT_SIP_SERVER_A:
622		case DH6OPT_DNS:
623		case DH6OPT_NTP_SERVERS:
624		case DH6OPT_NIS_SERVERS:
625		case DH6OPT_NISP_SERVERS:
626		case DH6OPT_BCMCS_SERVER_A:
627		case DH6OPT_PANA_AGENT:
628		case DH6OPT_LQ_CLIENT_LINK:
629			if (optlen % 16) {
630				printf(" ?)");
631				break;
632			}
633			tp = (u_char *)(dh6o + 1);
634			for (i = 0; i < optlen; i += 16)
635				printf(" %s", ip6addr_string(&tp[i]));
636			printf(")");
637			break;
638		case DH6OPT_STATUS_CODE:
639			if (optlen < 2) {
640				printf(" ?)");
641				break;
642			}
643			memcpy(&val16, (u_char *)(dh6o + 1), sizeof(val16));
644			val16 = ntohs(val16);
645			printf(" %s)", dhcp6stcode(val16));
646			break;
647		case DH6OPT_IA_NA:
648		case DH6OPT_IA_PD:
649			if (optlen < sizeof(ia) - 4) {
650				printf(" ?)");
651				break;
652			}
653			memcpy(&ia, (u_char *)dh6o, sizeof(ia));
654			ia.dh6opt_ia_iaid = ntohl(ia.dh6opt_ia_iaid);
655			ia.dh6opt_ia_t1 = ntohl(ia.dh6opt_ia_t1);
656			ia.dh6opt_ia_t2 = ntohl(ia.dh6opt_ia_t2);
657			printf(" IAID:%lu T1:%lu T2:%lu",
658			    (unsigned long)ia.dh6opt_ia_iaid,
659			    (unsigned long)ia.dh6opt_ia_t1,
660			    (unsigned long)ia.dh6opt_ia_t2);
661			if (optlen > sizeof(ia) - 4) {
662				/* there are sub-options */
663				dhcp6opt_print((u_char *)dh6o + sizeof(ia),
664				    (u_char *)(dh6o + 1) + optlen);
665			}
666			printf(")");
667			break;
668		case DH6OPT_IA_TA:
669			if (optlen < 4) {
670				printf(" ?)");
671				break;
672			}
673			memcpy(&val32, dh6o + 1, sizeof(val32));
674			val32 = ntohl(val32);
675			printf(" IAID:%lu", (unsigned long)val32);
676			if (optlen > 4) {
677				/* there are sub-options */
678				dhcp6opt_print((u_char *)(dh6o + 1) + 4,
679				    (u_char *)(dh6o + 1) + optlen);
680			}
681			printf(")");
682			break;
683		case DH6OPT_IA_PD_PREFIX:
684			if (optlen < sizeof(ia_prefix) - 4) {
685				printf(" ?)");
686				break;
687			}
688			memcpy(&ia_prefix, (u_char *)dh6o, sizeof(ia_prefix));
689			printf(" %s/%d",
690			    ip6addr_string(&ia_prefix.dh6opt_ia_prefix_addr),
691			    ia_prefix.dh6opt_ia_prefix_plen);
692			ia_prefix.dh6opt_ia_prefix_pltime =
693			    ntohl(ia_prefix.dh6opt_ia_prefix_pltime);
694			ia_prefix.dh6opt_ia_prefix_vltime =
695			    ntohl(ia_prefix.dh6opt_ia_prefix_vltime);
696			printf(" pltime:%lu vltime:%lu",
697			    (unsigned long)ia_prefix.dh6opt_ia_prefix_pltime,
698			    (unsigned long)ia_prefix.dh6opt_ia_prefix_vltime);
699			if (optlen > sizeof(ia_prefix) - 4) {
700				/* there are sub-options */
701				dhcp6opt_print((u_char *)dh6o +
702				    sizeof(ia_prefix),
703				    (u_char *)(dh6o + 1) + optlen);
704			}
705			printf(")");
706			break;
707		case DH6OPT_LIFETIME:
708		case DH6OPT_CLT_TIME:
709			if (optlen != 4) {
710				printf(" ?)");
711				break;
712			}
713			memcpy(&val32, dh6o + 1, sizeof(val32));
714			val32 = ntohl(val32);
715			printf(" %d)", (int)val32);
716			break;
717		case DH6OPT_REMOTE_ID:
718			if (optlen < 4) {
719				printf(" ?)");
720				break;
721			}
722			tp = (u_char *)(dh6o + 1);
723			memcpy(&val32, &tp[0], sizeof(val32));
724			val32 = ntohl(val32);
725			printf(" %d ", (int)val32);
726			/*
727			 * Print hex dump first 10 characters.
728			 */
729			for (i = 4; i < optlen && i < 14; i++)
730				printf("%02x", tp[i]);
731			printf("...)");
732			break;
733		case DH6OPT_LQ_QUERY:
734			if (optlen < 17) {
735				printf(" ?)");
736				break;
737			}
738			tp = (u_char *)(dh6o + 1);
739			switch (*tp) {
740			case 1:
741				printf(" by-address");
742				break;
743			case 2:
744				printf(" by-clientID");
745				break;
746			default:
747				printf(" type_%d", (int)*tp);
748				break;
749			}
750			printf(" %s", ip6addr_string(&tp[1]));
751			if (optlen > 17) {
752				/* there are query-options */
753				dhcp6opt_print(tp + 17, tp + optlen);
754			}
755			printf(")");
756			break;
757		case DH6OPT_CLIENT_DATA:
758			if (optlen > 0) {
759				/* there are encapsulated options */
760				dhcp6opt_print((u_char *)(dh6o + 1),
761				    (u_char *)(dh6o + 1) + optlen);
762			}
763			printf(")");
764			break;
765		case DH6OPT_LQ_RELAY_DATA:
766			if (optlen < 16) {
767				printf(" ?)");
768				break;
769			}
770			tp = (u_char *)(dh6o + 1);
771			printf(" %s ", ip6addr_string(&tp[0]));
772			/*
773			 * Print hex dump first 10 characters.
774			 */
775			for (i = 16; i < optlen && i < 26; i++)
776				printf("%02x", tp[i]);
777			printf("...)");
778			break;
779		default:
780			printf(")");
781			break;
782		}
783
784		cp += sizeof(*dh6o) + optlen;
785	}
786	return;
787
788trunc:
789	printf("[|dhcp6ext]");
790}
791
792/*
793 * Print dhcp6 packets
794 */
795void
796dhcp6_print(const u_char *cp, u_int length)
797{
798	struct dhcp6 *dh6;
799	struct dhcp6_relay *dh6relay;
800	const u_char *ep;
801	u_char *extp;
802	const char *name;
803
804	printf("dhcp6");
805
806	ep = (u_char *)snapend;
807	if (cp + length < ep)
808		ep = cp + length;
809
810	dh6 = (struct dhcp6 *)cp;
811	dh6relay = (struct dhcp6_relay *)cp;
812	TCHECK(dh6->dh6_xid);
813	switch (dh6->dh6_msgtype) {
814	case DH6_SOLICIT:
815		name = "solicit";
816		break;
817	case DH6_ADVERTISE:
818		name = "advertise";
819		break;
820	case DH6_REQUEST:
821		name = "request";
822		break;
823	case DH6_CONFIRM:
824		name = "confirm";
825		break;
826	case DH6_RENEW:
827		name = "renew";
828		break;
829	case DH6_REBIND:
830		name = "rebind";
831		break;
832	case DH6_REPLY:
833		name = "reply";
834		break;
835	case DH6_RELEASE:
836		name = "release";
837		break;
838	case DH6_DECLINE:
839		name = "decline";
840		break;
841	case DH6_RECONFIGURE:
842		name = "reconfigure";
843		break;
844	case DH6_INFORM_REQ:
845		name= "inf-req";
846		break;
847	case DH6_RELAY_FORW:
848		name= "relay-fwd";
849		break;
850	case DH6_RELAY_REPLY:
851		name= "relay-reply";
852		break;
853	case DH6_LEASEQUERY:
854		name= "leasequery";
855		break;
856	case DH6_LQ_REPLY:
857		name= "leasequery-reply";
858		break;
859	default:
860		name = NULL;
861		break;
862	}
863
864	if (!vflag) {
865		if (name)
866			printf(" %s", name);
867		else if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
868		    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
869			printf(" msgtype-%u", dh6->dh6_msgtype);
870		}
871		return;
872	}
873
874	/* XXX relay agent messages have to be handled differently */
875
876	if (name)
877		printf(" %s (", name);	/*)*/
878	else
879		printf(" msgtype-%u (", dh6->dh6_msgtype);	/*)*/
880	if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
881	    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
882		printf("xid=%x", EXTRACT_32BITS(&dh6->dh6_xid) & DH6_XIDMASK);
883		extp = (u_char *)(dh6 + 1);
884		dhcp6opt_print(extp, ep);
885	} else {		/* relay messages */
886		struct in6_addr addr6;
887
888		TCHECK(dh6relay->dh6relay_peeraddr);
889
890		memcpy(&addr6, dh6relay->dh6relay_linkaddr, sizeof (addr6));
891		printf("linkaddr=%s", ip6addr_string(&addr6));
892
893		memcpy(&addr6, dh6relay->dh6relay_peeraddr, sizeof (addr6));
894		printf(" peeraddr=%s", ip6addr_string(&addr6));
895
896		dhcp6opt_print((u_char *)(dh6relay + 1), ep);
897	}
898	/*(*/
899	printf(")");
900	return;
901
902trunc:
903	printf("[|dhcp6]");
904}
905