print-dhcp6.c revision 127668
156893Sfenner/*
256893Sfenner * Copyright (C) 1998 and 1999 WIDE Project.
356893Sfenner * All rights reserved.
4127668Sbms *
556893Sfenner * Redistribution and use in source and binary forms, with or without
656893Sfenner * modification, are permitted provided that the following conditions
756893Sfenner * are met:
856893Sfenner * 1. Redistributions of source code must retain the above copyright
956893Sfenner *    notice, this list of conditions and the following disclaimer.
1056893Sfenner * 2. Redistributions in binary form must reproduce the above copyright
1156893Sfenner *    notice, this list of conditions and the following disclaimer in the
1256893Sfenner *    documentation and/or other materials provided with the distribution.
1356893Sfenner * 3. Neither the name of the project nor the names of its contributors
1456893Sfenner *    may be used to endorse or promote products derived from this software
1556893Sfenner *    without specific prior written permission.
16127668Sbms *
1756893Sfenner * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1856893Sfenner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1956893Sfenner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2056893Sfenner * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2156893Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2256893Sfenner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2356893Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2456893Sfenner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2556893Sfenner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2656893Sfenner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2756893Sfenner * SUCH DAMAGE.
2856893Sfenner */
29111726Sfenner/*
30127668Sbms * RFC3315: DHCPv6
31127668Sbms * supported DHCPv6 options:
32127668Sbms *  RFC3319,
33127668Sbms *  draft-ietf-dhc-dhcpv6-opt-dnsconfig-04.txt,
34127668Sbms *  draft-ietf-dhc-dhcpv6-opt-prefix-delegation-05.txt
35127668Sbms *  draft-ietf-dhc-dhcpv6-opt-timeconfig-02.txt,
36111726Sfenner */
3756893Sfenner
3856893Sfenner#ifndef lint
39127668Sbmsstatic const char rcsid[] _U_ =
40127668Sbms    "@(#) $Header: /tcpdump/master/tcpdump/print-dhcp6.c,v 1.27.2.4 2003/11/18 23:26:14 guy Exp $";
4156893Sfenner#endif
4256893Sfenner
4356893Sfenner#ifdef HAVE_CONFIG_H
4456893Sfenner#include "config.h"
4556893Sfenner#endif
4656893Sfenner
47127668Sbms#include <tcpdump-stdinc.h>
4856893Sfenner
4956893Sfenner#include <stdio.h>
5056893Sfenner#include <string.h>
5156893Sfenner
5256893Sfenner#include "interface.h"
5356893Sfenner#include "addrtoname.h"
54127668Sbms#include "extract.h"
5556893Sfenner
56127668Sbms/* lease duration */
57127668Sbms#define DHCP6_DURATITION_INFINITE 0xffffffff
58127668Sbms
59111726Sfenner/* Error Values */
60111726Sfenner#define DH6ERR_FAILURE		16
61111726Sfenner#define DH6ERR_AUTHFAIL		17
62111726Sfenner#define DH6ERR_POORLYFORMED	18
63111726Sfenner#define DH6ERR_UNAVAIL		19
64111726Sfenner#define DH6ERR_OPTUNAVAIL	20
6556893Sfenner
66111726Sfenner/* Message type */
67127668Sbms#define DH6_SOLICIT	1
68127668Sbms#define DH6_ADVERTISE	2
69127668Sbms#define DH6_REQUEST	3
70127668Sbms#define DH6_CONFIRM	4
71127668Sbms#define DH6_RENEW	5
72127668Sbms#define DH6_REBIND	6
73111726Sfenner#define DH6_REPLY	7
74127668Sbms#define DH6_RELEASE	8
75127668Sbms#define DH6_DECLINE	9
76127668Sbms#define DH6_RECONFIGURE	10
77111726Sfenner#define DH6_INFORM_REQ	11
78127668Sbms#define DH6_RELAY_FORW	12
79127668Sbms#define DH6_RELAY_REPLY	13
8056893Sfenner
81111726Sfenner/* DHCP6 base packet format */
82111726Sfennerstruct dhcp6 {
83111726Sfenner	union {
84111726Sfenner		u_int8_t m;
85111726Sfenner		u_int32_t x;
86111726Sfenner	} dh6_msgtypexid;
87111726Sfenner	/* options follow */
88127668Sbms};
89111726Sfenner#define dh6_msgtype	dh6_msgtypexid.m
90111726Sfenner#define dh6_xid		dh6_msgtypexid.x
91111726Sfenner#define DH6_XIDMASK	0x00ffffff
9256893Sfenner
93127668Sbms/* DHCPv6 relay messages */
94127668Sbmsstruct dhcp6_relay {
95127668Sbms	u_int8_t dh6relay_msgtype;
96127668Sbms	u_int8_t dh6relay_hcnt;
97127668Sbms	u_int8_t dh6relay_linkaddr[16];	/* XXX: badly aligned */
98127668Sbms	u_int8_t dh6relay_peeraddr[16];
99127668Sbms	/* options follow */
100127668Sbms};
101127668Sbms
102127668Sbms/* options */
103127668Sbms#define DH6OPT_CLIENTID	1
104127668Sbms#define DH6OPT_SERVERID	2
105127668Sbms#define DH6OPT_IA_NA 3
106127668Sbms#define DH6OPT_IA_TMP 4
107127668Sbms#define DH6OPT_IADDR 5
108127668Sbms#define DH6OPT_ORO 6
109127668Sbms#define DH6OPT_PREFERENCE 7
110127668Sbms#  define DH6OPT_PREF_UNDEF -1
111127668Sbms#  define DH6OPT_PREF_MAX 255
112127668Sbms#define DH6OPT_ELAPSED_TIME 8
113127668Sbms#define DH6OPT_RELAY_MSG 9
114127668Sbms/*#define DH6OPT_SERVER_MSG 10 deprecated */
115127668Sbms#define DH6OPT_AUTH 11
116127668Sbms#define DH6OPT_UNICAST 12
117127668Sbms#define DH6OPT_STATUS_CODE 13
118127668Sbms#  define DH6OPT_STCODE_SUCCESS 0
119127668Sbms#  define DH6OPT_STCODE_UNSPECFAIL 1
120127668Sbms#  define DH6OPT_STCODE_NOADDRAVAIL 2
121127668Sbms#  define DH6OPT_STCODE_NOBINDING 3
122127668Sbms#  define DH6OPT_STCODE_NOTONLINK 4
123127668Sbms#  define DH6OPT_STCODE_USEMULTICAST 5
124127668Sbms#  define DH6OPT_STCODE_NOPREFIXAVAIL 6
125127668Sbms#define DH6OPT_RAPID_COMMIT 14
126127668Sbms#define DH6OPT_USER_CLASS 15
127127668Sbms#define DH6OPT_VENDOR_CLASS 16
128127668Sbms#define DH6OPT_VENDOR_OPTS 17
129127668Sbms#define DH6OPT_INTERFACE_ID 18
130127668Sbms#define DH6OPT_RECONF_MSG 19
131127668Sbms#define DH6OPT_RECONF_ACCEPT 20
132127668Sbms#define DH6OPT_SIP_SERVER_D 21
133127668Sbms#define DH6OPT_SIP_SERVER_A 22
134127668Sbms#define DH6OPT_DNS 23
135127668Sbms#define DH6OPT_DNSNAME 24
136127668Sbms
137127668Sbms/*
138127668Sbms * The option type has not been assigned for the following options.
139127668Sbms * We temporarily adopt values used in the service specification document
140127668Sbms * (200206xx version) by NTT Communications.
141127668Sbms * Note that we'll change the following definitions if different type values
142127668Sbms * are officially assigned.
143127668Sbms */
144127668Sbms#define DH6OPT_PREFIX_DELEGATION 30
145127668Sbms#define DH6OPT_PREFIX_INFORMATION 31
146127668Sbms#define DH6OPT_PREFIX_REQUEST 32
147127668Sbms
148127668Sbms/*
149127668Sbms * The followings are also unassigned numbers.
150127668Sbms * We temporarily use values as of KAME snap 20031013.
151127668Sbms */
152127668Sbms#define DH6OPT_IA_PD 33
153127668Sbms#define DH6OPT_IA_PD_PREFIX 34
154127668Sbms#define DH6OPT_NTP_SERVERS 35
155127668Sbms
156111726Sfennerstruct dhcp6opt {
157111726Sfenner	u_int16_t dh6opt_type;
158111726Sfenner	u_int16_t dh6opt_len;
159111726Sfenner	/* type-dependent data follows */
160127668Sbms};
16156893Sfenner
162127668Sbmsstruct dhcp6_ia {
163127668Sbms	u_int16_t dh6opt_ia_type;
164127668Sbms	u_int16_t dh6opt_ia_len;
165127668Sbms	u_int32_t dh6opt_ia_iaid;
166127668Sbms	u_int32_t dh6opt_ia_t1;
167127668Sbms	u_int32_t dh6opt_ia_t2;
168127668Sbms};
169127668Sbms
170127668Sbmsstruct dhcp6_ia_prefix {
171127668Sbms	u_int16_t dh6opt_ia_prefix_type;
172127668Sbms	u_int16_t dh6opt_ia_prefix_len;
173127668Sbms	u_int32_t dh6opt_ia_prefix_pltime;
174127668Sbms	u_int32_t dh6opt_ia_prefix_vltime;
175127668Sbms	u_int8_t dh6opt_ia_prefix_plen;
176127668Sbms	struct in6_addr dh6opt_ia_prefix_addr;
177127668Sbms}  __attribute__ ((__packed__));
178127668Sbms
179127668Sbmsstatic const char *
180127668Sbmsdhcp6opt_name(int type)
181127668Sbms{
182127668Sbms	static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */
183127668Sbms
184127668Sbms	if (type > 65535)
185127668Sbms		return "INVALID option";
186127668Sbms
187127668Sbms	switch(type) {
188127668Sbms	case DH6OPT_CLIENTID:
189127668Sbms		return "client ID";
190127668Sbms	case DH6OPT_SERVERID:
191127668Sbms		return "server ID";
192127668Sbms	case DH6OPT_IA_NA:
193127668Sbms		return "IA_NA";
194127668Sbms	case DH6OPT_ORO:
195127668Sbms		return "option request";
196127668Sbms	case DH6OPT_PREFERENCE:
197127668Sbms		return "preference";
198127668Sbms	case DH6OPT_ELAPSED_TIME:
199127668Sbms		return "elapsed time";
200127668Sbms	case DH6OPT_RELAY_MSG:
201127668Sbms		return "relay message";
202127668Sbms	case DH6OPT_STATUS_CODE:
203127668Sbms		return "status code";
204127668Sbms	case DH6OPT_RAPID_COMMIT:
205127668Sbms		return "rapid commit";
206127668Sbms	case DH6OPT_INTERFACE_ID:
207127668Sbms		return "interface ID";
208127668Sbms	case DH6OPT_RECONF_MSG:
209127668Sbms		return "reconfigure message";
210127668Sbms	case DH6OPT_RECONF_ACCEPT:
211127668Sbms		return "reconfigure accept";
212127668Sbms	case DH6OPT_SIP_SERVER_D:
213127668Sbms		return "SIP Servers Domain";
214127668Sbms	case DH6OPT_SIP_SERVER_A:
215127668Sbms		return "SIP Servers Address";
216127668Sbms	case DH6OPT_DNS:
217127668Sbms		return "DNS";
218127668Sbms	case DH6OPT_PREFIX_DELEGATION:
219127668Sbms		return "prefix delegation";
220127668Sbms	case DH6OPT_PREFIX_INFORMATION:
221127668Sbms		return "prefix information";
222127668Sbms	case DH6OPT_IA_PD:
223127668Sbms		return "IA_PD";
224127668Sbms	case DH6OPT_IA_PD_PREFIX:
225127668Sbms		return "IA_PD prefix";
226127668Sbms	case DH6OPT_NTP_SERVERS:
227127668Sbms		return "NTP Server";
228127668Sbms	default:
229127668Sbms		snprintf(genstr, sizeof(genstr), "opt_%d", type);
230127668Sbms		return(genstr);
231127668Sbms	}
232127668Sbms}
233127668Sbms
234127668Sbmsstatic const char *
235127668Sbmsdhcp6stcode(int code)
236127668Sbms{
237127668Sbms	static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */
238127668Sbms
239127668Sbms	if (code > 255)
240127668Sbms		return "INVALID code";
241127668Sbms
242127668Sbms	switch(code) {
243127668Sbms	case DH6OPT_STCODE_SUCCESS:
244127668Sbms		return "success";
245127668Sbms	case DH6OPT_STCODE_UNSPECFAIL:
246127668Sbms		return "unspec failure";
247127668Sbms	case DH6OPT_STCODE_NOADDRAVAIL:
248127668Sbms		return "no addresses";
249127668Sbms	case DH6OPT_STCODE_NOBINDING:
250127668Sbms		return "no binding";
251127668Sbms	case DH6OPT_STCODE_NOTONLINK:
252127668Sbms		return "not on-link";
253127668Sbms	case DH6OPT_STCODE_USEMULTICAST:
254127668Sbms		return "use multicast";
255127668Sbms	case DH6OPT_STCODE_NOPREFIXAVAIL:
256127668Sbms		return "no prefixes";
257127668Sbms	default:
258127668Sbms		snprintf(genstr, sizeof(genstr), "code%d", code);
259127668Sbms		return(genstr);
260127668Sbms	}
261127668Sbms}
262127668Sbms
26356893Sfennerstatic void
264127668Sbmsdhcp6opt_print(const u_char *cp, const u_char *ep)
26556893Sfenner{
266111726Sfenner	struct dhcp6opt *dh6o;
267111726Sfenner	u_char *tp;
268127668Sbms	size_t i;
269127668Sbms	u_int16_t opttype;
270111726Sfenner	size_t optlen;
271127668Sbms	u_int16_t val16;
272127668Sbms	u_int32_t val32;
273127668Sbms	struct in6_addr addr6;
274127668Sbms	struct dhcp6_ia ia;
275127668Sbms	struct dhcp6_ia_prefix ia_prefix;
27656893Sfenner
27756893Sfenner	if (cp == ep)
27856893Sfenner		return;
27956893Sfenner	while (cp < ep) {
280127668Sbms		if (ep < cp + sizeof(*dh6o))
281111726Sfenner			goto trunc;
282111726Sfenner		dh6o = (struct dhcp6opt *)cp;
283127668Sbms		optlen = EXTRACT_16BITS(&dh6o->dh6opt_len);
284127668Sbms		if (ep < cp + sizeof(*dh6o) + optlen)
285111726Sfenner			goto trunc;
286127668Sbms		opttype = EXTRACT_16BITS(&dh6o->dh6opt_type);
287127668Sbms		printf(" (%s", dhcp6opt_name(opttype));
288127668Sbms		switch (opttype) {
289127668Sbms		case DH6OPT_CLIENTID:
290127668Sbms		case DH6OPT_SERVERID:
291111726Sfenner			if (optlen < 2) {
292111726Sfenner				/*(*/
293127668Sbms				printf(" ?)");
294111726Sfenner				break;
295111726Sfenner			}
296111726Sfenner			tp = (u_char *)(dh6o + 1);
297127668Sbms			switch (EXTRACT_16BITS(tp)) {
298111726Sfenner			case 1:
299111726Sfenner				if (optlen >= 2 + 6) {
300127668Sbms					printf(" hwaddr/time type %u time %u ",
301127668Sbms					    EXTRACT_16BITS(&tp[2]),
302127668Sbms					    EXTRACT_32BITS(&tp[4]));
303111726Sfenner					for (i = 8; i < optlen; i++)
304111726Sfenner						printf("%02x", tp[i]);
305111726Sfenner					/*(*/
306111726Sfenner					printf(")");
307111726Sfenner				} else {
308111726Sfenner					/*(*/
309127668Sbms					printf(" ?)");
310111726Sfenner				}
311111726Sfenner				break;
312111726Sfenner			case 2:
313111726Sfenner				if (optlen >= 2 + 8) {
314111726Sfenner					printf(" vid ");
315111726Sfenner					for (i = 2; i < 2 + 8; i++)
316111726Sfenner						printf("%02x", tp[i]);
317111726Sfenner					/*(*/
318111726Sfenner					printf(")");
319111726Sfenner				} else {
320111726Sfenner					/*(*/
321127668Sbms					printf(" ?)");
322111726Sfenner				}
323111726Sfenner				break;
324111726Sfenner			case 3:
325111726Sfenner				if (optlen >= 2 + 2) {
326111726Sfenner					printf(" hwaddr type %u ",
327127668Sbms					    EXTRACT_16BITS(&tp[2]));
328111726Sfenner					for (i = 4; i < optlen; i++)
329111726Sfenner						printf("%02x", tp[i]);
330111726Sfenner					/*(*/
331111726Sfenner					printf(")");
332111726Sfenner				} else {
333111726Sfenner					/*(*/
334127668Sbms					printf(" ?)");
335111726Sfenner				}
336127668Sbms				break;
337127668Sbms			default:
338127668Sbms				printf(" type %d)", EXTRACT_16BITS(tp));
339127668Sbms				break;
340111726Sfenner			}
34175115Sfenner			break;
342127668Sbms		case DH6OPT_ORO:
343127668Sbms			if (optlen % 2) {
344127668Sbms				printf(" ?)");
345127668Sbms				break;
346127668Sbms			}
347127668Sbms			tp = (u_char *)(dh6o + 1);
348127668Sbms			for (i = 0; i < optlen; i += 2) {
349127668Sbms				u_int16_t opt;
350127668Sbms
351127668Sbms				memcpy(&opt, &tp[i], sizeof(opt));
352127668Sbms				printf(" %s", dhcp6opt_name(ntohs(opt)));
353127668Sbms			}
354127668Sbms			printf(")");
355127668Sbms			break;
356127668Sbms		case DH6OPT_PREFERENCE:
357127668Sbms			if (optlen != 1) {
358127668Sbms				printf(" ?)");
359127668Sbms				break;
360127668Sbms			}
361127668Sbms			printf(" %d)", *((u_char *)(dh6o + 1) + 1));
362127668Sbms			break;
363127668Sbms		case DH6OPT_ELAPSED_TIME:
364127668Sbms			if (optlen != 2) {
365127668Sbms				printf(" ?)");
366127668Sbms				break;
367127668Sbms			}
368127668Sbms			memcpy(&val16, dh6o + 1, sizeof(val16));
369127668Sbms			val16 = ntohs(val16);
370127668Sbms			printf(" %d)", (int)val16);
371127668Sbms			break;
372127668Sbms		case DH6OPT_RELAY_MSG:
373127668Sbms			printf(" (");
374127668Sbms			dhcp6_print((const u_char *)(dh6o + 1), optlen);
375127668Sbms			printf(")");
376127668Sbms			break;
377127668Sbms		case DH6OPT_RAPID_COMMIT: /* nothing todo */
378127668Sbms			printf(")");
379127668Sbms			break;
380127668Sbms		case DH6OPT_INTERFACE_ID:
381127668Sbms			/*
382127668Sbms			 * Since we cannot predict the encoding, print hex dump
383127668Sbms			 * at most 10 characters.
384127668Sbms			 */
385127668Sbms			for (i = 0; i < optlen && i < 10; i++)
386127668Sbms				printf("%02x", ((u_char *)(dh6o + 1))[i]);
387127668Sbms			break;
388127668Sbms		case DH6OPT_RECONF_MSG:
389127668Sbms			tp = (u_char *)(dh6o + 1);
390127668Sbms			switch (*tp) {
391127668Sbms			case DH6_RENEW:
392127668Sbms				printf(" for renew)");
393127668Sbms				break;
394127668Sbms			case DH6_INFORM_REQ:
395127668Sbms				printf(" for inf-req)");
396127668Sbms				break;
397127668Sbms			default:
398127668Sbms				printf(" for ?\?\?(%02x))", *tp);
399127668Sbms				break;
400127668Sbms			}
401127668Sbms			break;
402127668Sbms		case DH6OPT_RECONF_ACCEPT: /* nothing todo */
403127668Sbms			printf(")");
404127668Sbms			break;
405127668Sbms		case DH6OPT_SIP_SERVER_A:
406111726Sfenner		case DH6OPT_DNS:
407127668Sbms		case DH6OPT_NTP_SERVERS:
408111726Sfenner			if (optlen % 16) {
409127668Sbms				printf(" ?)");
410111726Sfenner				break;
411111726Sfenner			}
412111726Sfenner			tp = (u_char *)(dh6o + 1);
413111726Sfenner			for (i = 0; i < optlen; i += 16)
414111726Sfenner				printf(" %s", ip6addr_string(&tp[i]));
415111726Sfenner			printf(")");
416127668Sbms			break;
417127668Sbms		case DH6OPT_PREFIX_DELEGATION:
418127668Sbms			dhcp6opt_print((u_char *)(dh6o + 1),
419127668Sbms			    (u_char *)(dh6o + 1) + optlen);
420127668Sbms			printf(")");
421127668Sbms			break;
422127668Sbms		case DH6OPT_PREFIX_INFORMATION:
423127668Sbms			if (optlen % 21)
424127668Sbms				printf(" ?)");
425127668Sbms			memcpy(&addr6, (u_char *)(dh6o + 1) + 5,
426127668Sbms			    sizeof(addr6));
427127668Sbms			printf(" %s/%d", ip6addr_string(&addr6),
428127668Sbms			    (int)*((u_char *)(dh6o + 1) + 4));
429127668Sbms			memcpy(&val32, dh6o + 1, sizeof(val32));
430127668Sbms			val32 = ntohl(val32);
431127668Sbms			if (val32 == DHCP6_DURATITION_INFINITE)
432127668Sbms				printf(" lease-duration: infinite)");
433127668Sbms			else
434127668Sbms				printf(" lease-duration: %u)", val32);
435127668Sbms			break;
436127668Sbms		case DH6OPT_STATUS_CODE:
437127668Sbms			if (optlen < 2) {
438127668Sbms				printf(" ?)");
439127668Sbms				break;
440127668Sbms			}
441127668Sbms			memcpy(&val16, (u_char *)(dh6o + 1), sizeof(val16));
442127668Sbms			val16 = ntohs(val16);
443127668Sbms			printf(" %s)", dhcp6stcode(val16));
444127668Sbms			break;
445127668Sbms		case DH6OPT_IA_NA:
446127668Sbms		case DH6OPT_IA_PD:
447127668Sbms			if (optlen < sizeof(ia) - 4) {
448127668Sbms				printf(" ?)");
449127668Sbms				break;
450127668Sbms			}
451127668Sbms			memcpy(&ia, (u_char *)dh6o, sizeof(ia));
452127668Sbms			ia.dh6opt_ia_iaid = ntohl(ia.dh6opt_ia_iaid);
453127668Sbms			ia.dh6opt_ia_t1 = ntohl(ia.dh6opt_ia_t1);
454127668Sbms			ia.dh6opt_ia_t2 = ntohl(ia.dh6opt_ia_t2);
455127668Sbms			printf(" IAID:%lu T1:%lu T2:%lu",
456127668Sbms			    (unsigned long)ia.dh6opt_ia_iaid,
457127668Sbms			    (unsigned long)ia.dh6opt_ia_t1,
458127668Sbms			    (unsigned long)ia.dh6opt_ia_t2);
459127668Sbms			if (optlen > sizeof(ia) - 4) {
460127668Sbms				/* there are sub-options */
461127668Sbms				dhcp6opt_print((u_char *)dh6o + sizeof(ia),
462127668Sbms				    (u_char *)(dh6o + 1) + optlen);
463127668Sbms			}
464127668Sbms			printf(")");
465127668Sbms			break;
466127668Sbms		case DH6OPT_IA_PD_PREFIX:
467127668Sbms			if (optlen < sizeof(ia_prefix) - 4) {
468127668Sbms				printf(" ?)");
469127668Sbms				break;
470127668Sbms			}
471127668Sbms			memcpy(&ia_prefix, (u_char *)dh6o, sizeof(ia_prefix));
472127668Sbms			printf(" %s/%d",
473127668Sbms			    ip6addr_string(&ia_prefix.dh6opt_ia_prefix_addr),
474127668Sbms			    ia_prefix.dh6opt_ia_prefix_plen);
475127668Sbms			ia_prefix.dh6opt_ia_prefix_pltime =
476127668Sbms			    ntohl(ia_prefix.dh6opt_ia_prefix_pltime);
477127668Sbms			ia_prefix.dh6opt_ia_prefix_vltime =
478127668Sbms			    ntohl(ia_prefix.dh6opt_ia_prefix_vltime);
479127668Sbms			printf(" pltime:%lu vltime:%lu",
480127668Sbms			    (unsigned long)ia_prefix.dh6opt_ia_prefix_pltime,
481127668Sbms			    (unsigned long)ia_prefix.dh6opt_ia_prefix_vltime);
482127668Sbms			if (optlen > sizeof(ia_prefix) - 4) {
483127668Sbms				/* there are sub-options */
484127668Sbms				dhcp6opt_print((u_char *)dh6o +
485127668Sbms				    sizeof(ia_prefix),
486127668Sbms				    (u_char *)(dh6o + 1) + optlen);
487127668Sbms			}
488127668Sbms			printf(")");
489127668Sbms			break;
49056893Sfenner		default:
491127668Sbms			printf(")");
49256893Sfenner			break;
49356893Sfenner		}
49456893Sfenner
495111726Sfenner		cp += sizeof(*dh6o) + optlen;
49656893Sfenner	}
49756893Sfenner	return;
49856893Sfenner
49956893Sfennertrunc:
50056893Sfenner	printf("[|dhcp6ext]");
50156893Sfenner}
50256893Sfenner
50356893Sfenner/*
504111726Sfenner * Print dhcp6 packets
50556893Sfenner */
50656893Sfennervoid
507127668Sbmsdhcp6_print(const u_char *cp, u_int length)
50856893Sfenner{
509111726Sfenner	struct dhcp6 *dh6;
510127668Sbms	struct dhcp6_relay *dh6relay;
511127668Sbms	const u_char *ep;
51256893Sfenner	u_char *extp;
513111726Sfenner	const char *name;
51456893Sfenner
51556893Sfenner	printf("dhcp6");
51656893Sfenner
51756893Sfenner	ep = (u_char *)snapend;
518127668Sbms	if (cp + length < ep)
519127668Sbms		ep = cp + length;
52056893Sfenner
521111726Sfenner	dh6 = (struct dhcp6 *)cp;
522127668Sbms	dh6relay = (struct dhcp6_relay *)cp;
523127668Sbms	TCHECK(dh6->dh6_xid);
52456893Sfenner	switch (dh6->dh6_msgtype) {
525127668Sbms	case DH6_SOLICIT:
526127668Sbms		name = "solicit";
527127668Sbms		break;
528127668Sbms	case DH6_ADVERTISE:
529127668Sbms		name = "advertise";
530127668Sbms		break;
531127668Sbms	case DH6_REQUEST:
532127668Sbms		name = "request";
533127668Sbms		break;
534127668Sbms	case DH6_CONFIRM:
535127668Sbms		name = "confirm";
536127668Sbms		break;
537127668Sbms	case DH6_RENEW:
538127668Sbms		name = "renew";
539127668Sbms		break;
540127668Sbms	case DH6_REBIND:
541127668Sbms		name = "rebind";
542127668Sbms		break;
54356893Sfenner	case DH6_REPLY:
544111726Sfenner		name = "reply";
54556893Sfenner		break;
546127668Sbms	case DH6_RELEASE:
547127668Sbms		name = "release";
548127668Sbms		break;
549127668Sbms	case DH6_DECLINE:
550127668Sbms		name = "decline";
551127668Sbms		break;
552127668Sbms	case DH6_RECONFIGURE:
553127668Sbms		name = "reconfigure";
554127668Sbms		break;
555111726Sfenner	case DH6_INFORM_REQ:
556111726Sfenner		name= "inf-req";
55756893Sfenner		break;
558127668Sbms	case DH6_RELAY_FORW:
559127668Sbms		name= "relay-fwd";
560127668Sbms		break;
561127668Sbms	case DH6_RELAY_REPLY:
562127668Sbms		name= "relay-reply";
563127668Sbms		break;
564111726Sfenner	default:
565111726Sfenner		name = NULL;
56656893Sfenner		break;
56756893Sfenner	}
568111726Sfenner
569111726Sfenner	if (!vflag) {
570111726Sfenner		if (name)
571111726Sfenner			printf(" %s", name);
572127668Sbms		else if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
573127668Sbms		    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
574111726Sfenner			printf(" msgtype-%u", dh6->dh6_msgtype);
575127668Sbms		}
576111726Sfenner		return;
577111726Sfenner	}
578111726Sfenner
579111726Sfenner	/* XXX relay agent messages have to be handled differently */
580111726Sfenner
581111726Sfenner	if (name)
582111726Sfenner		printf(" %s (", name);	/*)*/
583111726Sfenner	else
584111726Sfenner		printf(" msgtype-%u (", dh6->dh6_msgtype);	/*)*/
585127668Sbms	if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
586127668Sbms	    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
587127668Sbms		printf("xid=%x", EXTRACT_32BITS(&dh6->dh6_xid) & DH6_XIDMASK);
588127668Sbms		extp = (u_char *)(dh6 + 1);
589127668Sbms		dhcp6opt_print(extp, ep);
590127668Sbms	} else {		/* relay messages */
591127668Sbms		struct in6_addr addr6;
592127668Sbms
593127668Sbms		TCHECK(dh6relay->dh6relay_peeraddr);
594127668Sbms
595127668Sbms		memcpy(&addr6, dh6relay->dh6relay_linkaddr, sizeof (addr6));
596127668Sbms		printf("linkaddr=%s", ip6addr_string(&addr6));
597127668Sbms
598127668Sbms		memcpy(&addr6, dh6relay->dh6relay_peeraddr, sizeof (addr6));
599127668Sbms		printf(" peeraddr=%s", ip6addr_string(&addr6));
600127668Sbms
601127668Sbms		dhcp6opt_print((u_char *)(dh6relay + 1), ep);
602127668Sbms	}
603111726Sfenner	/*(*/
604111726Sfenner	printf(")");
60556893Sfenner	return;
60656893Sfenner
60756893Sfennertrunc:
608111726Sfenner	printf("[|dhcp6]");
60956893Sfenner}
610