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:
32252283Sdelphij *  RFC3319: Session Initiation Protocol (SIP) Servers options,
33252283Sdelphij *  RFC3633: IPv6 Prefix options,
34252283Sdelphij *  RFC3646: DNS Configuration options,
35252283Sdelphij *  RFC3898: Network Information Service (NIS) Configuration options,
36252283Sdelphij *  RFC4075: Simple Network Time Protocol (SNTP) Configuration option,
37252283Sdelphij *  RFC4242: Information Refresh Time option,
38252283Sdelphij *  RFC4280: Broadcast and Multicast Control Servers options,
39252283Sdelphij *  RFC6334: Dual-Stack Lite option,
40111726Sfenner */
4156893Sfenner
4256893Sfenner#ifndef lint
43127668Sbmsstatic const char rcsid[] _U_ =
44214478Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-dhcp6.c,v 1.37 2008-02-06 10:26:09 guy Exp $";
4556893Sfenner#endif
4656893Sfenner
4756893Sfenner#ifdef HAVE_CONFIG_H
4856893Sfenner#include "config.h"
4956893Sfenner#endif
5056893Sfenner
51127668Sbms#include <tcpdump-stdinc.h>
5256893Sfenner
5356893Sfenner#include <stdio.h>
5456893Sfenner#include <string.h>
5556893Sfenner
5656893Sfenner#include "interface.h"
5756893Sfenner#include "addrtoname.h"
58127668Sbms#include "extract.h"
5956893Sfenner
60127668Sbms/* lease duration */
61127668Sbms#define DHCP6_DURATITION_INFINITE 0xffffffff
62127668Sbms
63111726Sfenner/* Error Values */
64111726Sfenner#define DH6ERR_FAILURE		16
65111726Sfenner#define DH6ERR_AUTHFAIL		17
66111726Sfenner#define DH6ERR_POORLYFORMED	18
67111726Sfenner#define DH6ERR_UNAVAIL		19
68111726Sfenner#define DH6ERR_OPTUNAVAIL	20
6956893Sfenner
70111726Sfenner/* Message type */
71127668Sbms#define DH6_SOLICIT	1
72127668Sbms#define DH6_ADVERTISE	2
73127668Sbms#define DH6_REQUEST	3
74127668Sbms#define DH6_CONFIRM	4
75127668Sbms#define DH6_RENEW	5
76127668Sbms#define DH6_REBIND	6
77111726Sfenner#define DH6_REPLY	7
78127668Sbms#define DH6_RELEASE	8
79127668Sbms#define DH6_DECLINE	9
80127668Sbms#define DH6_RECONFIGURE	10
81111726Sfenner#define DH6_INFORM_REQ	11
82127668Sbms#define DH6_RELAY_FORW	12
83127668Sbms#define DH6_RELAY_REPLY	13
84190207Srpaulo#define DH6_LEASEQUERY	14
85190207Srpaulo#define DH6_LQ_REPLY	15
8656893Sfenner
87111726Sfenner/* DHCP6 base packet format */
88111726Sfennerstruct dhcp6 {
89111726Sfenner	union {
90111726Sfenner		u_int8_t m;
91111726Sfenner		u_int32_t x;
92111726Sfenner	} dh6_msgtypexid;
93111726Sfenner	/* options follow */
94127668Sbms};
95111726Sfenner#define dh6_msgtype	dh6_msgtypexid.m
96111726Sfenner#define dh6_xid		dh6_msgtypexid.x
97111726Sfenner#define DH6_XIDMASK	0x00ffffff
9856893Sfenner
99127668Sbms/* DHCPv6 relay messages */
100127668Sbmsstruct dhcp6_relay {
101127668Sbms	u_int8_t dh6relay_msgtype;
102127668Sbms	u_int8_t dh6relay_hcnt;
103127668Sbms	u_int8_t dh6relay_linkaddr[16];	/* XXX: badly aligned */
104127668Sbms	u_int8_t dh6relay_peeraddr[16];
105127668Sbms	/* options follow */
106127668Sbms};
107127668Sbms
108127668Sbms/* options */
109127668Sbms#define DH6OPT_CLIENTID	1
110127668Sbms#define DH6OPT_SERVERID	2
111127668Sbms#define DH6OPT_IA_NA 3
112172683Smlaier#define DH6OPT_IA_TA 4
113172683Smlaier#define DH6OPT_IA_ADDR 5
114127668Sbms#define DH6OPT_ORO 6
115127668Sbms#define DH6OPT_PREFERENCE 7
116127668Sbms#  define DH6OPT_PREF_MAX 255
117127668Sbms#define DH6OPT_ELAPSED_TIME 8
118127668Sbms#define DH6OPT_RELAY_MSG 9
119127668Sbms/*#define DH6OPT_SERVER_MSG 10 deprecated */
120127668Sbms#define DH6OPT_AUTH 11
121146773Ssam#  define DH6OPT_AUTHPROTO_DELAYED 2
122146773Ssam#  define DH6OPT_AUTHPROTO_RECONFIG 3
123146773Ssam#  define DH6OPT_AUTHALG_HMACMD5 1
124146773Ssam#  define DH6OPT_AUTHRDM_MONOCOUNTER 0
125146773Ssam#  define DH6OPT_AUTHRECONFIG_KEY 1
126146773Ssam#  define DH6OPT_AUTHRECONFIG_HMACMD5 2
127127668Sbms#define DH6OPT_UNICAST 12
128127668Sbms#define DH6OPT_STATUS_CODE 13
129127668Sbms#  define DH6OPT_STCODE_SUCCESS 0
130127668Sbms#  define DH6OPT_STCODE_UNSPECFAIL 1
131127668Sbms#  define DH6OPT_STCODE_NOADDRAVAIL 2
132127668Sbms#  define DH6OPT_STCODE_NOBINDING 3
133127668Sbms#  define DH6OPT_STCODE_NOTONLINK 4
134127668Sbms#  define DH6OPT_STCODE_USEMULTICAST 5
135127668Sbms#  define DH6OPT_STCODE_NOPREFIXAVAIL 6
136190207Srpaulo#  define DH6OPT_STCODE_UNKNOWNQUERYTYPE 7
137190207Srpaulo#  define DH6OPT_STCODE_MALFORMEDQUERY 8
138190207Srpaulo#  define DH6OPT_STCODE_NOTCONFIGURED 9
139190207Srpaulo#  define DH6OPT_STCODE_NOTALLOWED 10
140127668Sbms#define DH6OPT_RAPID_COMMIT 14
141127668Sbms#define DH6OPT_USER_CLASS 15
142127668Sbms#define DH6OPT_VENDOR_CLASS 16
143127668Sbms#define DH6OPT_VENDOR_OPTS 17
144127668Sbms#define DH6OPT_INTERFACE_ID 18
145127668Sbms#define DH6OPT_RECONF_MSG 19
146127668Sbms#define DH6OPT_RECONF_ACCEPT 20
147127668Sbms#define DH6OPT_SIP_SERVER_D 21
148127668Sbms#define DH6OPT_SIP_SERVER_A 22
149127668Sbms#define DH6OPT_DNS 23
150127668Sbms#define DH6OPT_DNSNAME 24
151146773Ssam#define DH6OPT_IA_PD 25
152146773Ssam#define DH6OPT_IA_PD_PREFIX 26
153172683Smlaier#define DH6OPT_NIS_SERVERS 27
154172683Smlaier#define DH6OPT_NISP_SERVERS 28
155172683Smlaier#define DH6OPT_NIS_NAME 29
156172683Smlaier#define DH6OPT_NISP_NAME 30
157172683Smlaier#define DH6OPT_NTP_SERVERS 31
158172683Smlaier#define DH6OPT_LIFETIME 32
159172683Smlaier#define DH6OPT_BCMCS_SERVER_D 33
160172683Smlaier#define DH6OPT_BCMCS_SERVER_A 34
161172683Smlaier#define DH6OPT_GEOCONF_CIVIC 36
162172683Smlaier#define DH6OPT_REMOTE_ID 37
163172683Smlaier#define DH6OPT_SUBSCRIBER_ID 38
164172683Smlaier#define DH6OPT_CLIENT_FQDN 39
165190207Srpaulo#define DH6OPT_PANA_AGENT 40
166190207Srpaulo#define DH6OPT_NEW_POSIX_TIMEZONE 41
167190207Srpaulo#define DH6OPT_NEW_TZDB_TIMEZONE 42
168190207Srpaulo#define DH6OPT_ERO 43
169190207Srpaulo#define DH6OPT_LQ_QUERY 44
170190207Srpaulo#define DH6OPT_CLIENT_DATA 45
171190207Srpaulo#define DH6OPT_CLT_TIME 46
172190207Srpaulo#define DH6OPT_LQ_RELAY_DATA 47
173190207Srpaulo#define DH6OPT_LQ_CLIENT_LINK 48
174252283Sdelphij#define DH6OPT_AFTR_NAME 64
175127668Sbms
176111726Sfennerstruct dhcp6opt {
177111726Sfenner	u_int16_t dh6opt_type;
178111726Sfenner	u_int16_t dh6opt_len;
179111726Sfenner	/* type-dependent data follows */
180127668Sbms};
18156893Sfenner
182127668Sbmsstatic const char *
183127668Sbmsdhcp6opt_name(int type)
184127668Sbms{
185127668Sbms	static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */
186127668Sbms
187127668Sbms	if (type > 65535)
188214478Srpaulo		return "INVALID-option";
189127668Sbms
190127668Sbms	switch(type) {
191127668Sbms	case DH6OPT_CLIENTID:
192214478Srpaulo		return "client-ID";
193127668Sbms	case DH6OPT_SERVERID:
194214478Srpaulo		return "server-ID";
195127668Sbms	case DH6OPT_IA_NA:
196127668Sbms		return "IA_NA";
197172683Smlaier	case DH6OPT_IA_TA:
198172683Smlaier		return "IA_TA";
199172683Smlaier	case DH6OPT_IA_ADDR:
200172683Smlaier		return "IA_ADDR";
201127668Sbms	case DH6OPT_ORO:
202214478Srpaulo		return "option-request";
203127668Sbms	case DH6OPT_PREFERENCE:
204127668Sbms		return "preference";
205127668Sbms	case DH6OPT_ELAPSED_TIME:
206214478Srpaulo		return "elapsed-time";
207127668Sbms	case DH6OPT_RELAY_MSG:
208214478Srpaulo		return "relay-message";
209146773Ssam	case DH6OPT_AUTH:
210146773Ssam		return "authentication";
211146773Ssam	case DH6OPT_UNICAST:
212214478Srpaulo		return "server-unicast";
213127668Sbms	case DH6OPT_STATUS_CODE:
214214478Srpaulo		return "status-code";
215127668Sbms	case DH6OPT_RAPID_COMMIT:
216214478Srpaulo		return "rapid-commit";
217146773Ssam	case DH6OPT_USER_CLASS:
218214478Srpaulo		return "user-class";
219146773Ssam	case DH6OPT_VENDOR_CLASS:
220214478Srpaulo		return "vendor-class";
221146773Ssam	case DH6OPT_VENDOR_OPTS:
222214478Srpaulo		return "vendor-specific-info";
223127668Sbms	case DH6OPT_INTERFACE_ID:
224214478Srpaulo		return "interface-ID";
225127668Sbms	case DH6OPT_RECONF_MSG:
226214478Srpaulo		return "reconfigure-message";
227127668Sbms	case DH6OPT_RECONF_ACCEPT:
228214478Srpaulo		return "reconfigure-accept";
229127668Sbms	case DH6OPT_SIP_SERVER_D:
230214478Srpaulo		return "SIP-servers-domain";
231127668Sbms	case DH6OPT_SIP_SERVER_A:
232214478Srpaulo		return "SIP-servers-address";
233127668Sbms	case DH6OPT_DNS:
234236192Sdelphij		return "DNS-server";
235146773Ssam	case DH6OPT_DNSNAME:
236236192Sdelphij		return "DNS-search-list";
237127668Sbms	case DH6OPT_IA_PD:
238127668Sbms		return "IA_PD";
239127668Sbms	case DH6OPT_IA_PD_PREFIX:
240214478Srpaulo		return "IA_PD-prefix";
241127668Sbms	case DH6OPT_NTP_SERVERS:
242236192Sdelphij		return "NTP-server";
243146773Ssam	case DH6OPT_LIFETIME:
244146773Ssam		return "lifetime";
245172683Smlaier	case DH6OPT_NIS_SERVERS:
246214478Srpaulo		return "NIS-server";
247172683Smlaier	case DH6OPT_NISP_SERVERS:
248214478Srpaulo		return "NIS+-server";
249172683Smlaier	case DH6OPT_NIS_NAME:
250214478Srpaulo		return "NIS-domain-name";
251172683Smlaier	case DH6OPT_NISP_NAME:
252214478Srpaulo		return "NIS+-domain-name";
253172683Smlaier	case DH6OPT_BCMCS_SERVER_D:
254214478Srpaulo		return "BCMCS-domain-name";
255172683Smlaier	case DH6OPT_BCMCS_SERVER_A:
256214478Srpaulo		return "BCMCS-server";
257172683Smlaier	case DH6OPT_GEOCONF_CIVIC:
258214478Srpaulo		return "Geoconf-Civic";
259172683Smlaier	case DH6OPT_REMOTE_ID:
260214478Srpaulo		return "Remote-ID";
261172683Smlaier	case DH6OPT_SUBSCRIBER_ID:
262214478Srpaulo		return "Subscriber-ID";
263172683Smlaier	case DH6OPT_CLIENT_FQDN:
264214478Srpaulo		return "Client-FQDN";
265190207Srpaulo	case DH6OPT_PANA_AGENT:
266214478Srpaulo		return "PANA-agent";
267190207Srpaulo	case DH6OPT_NEW_POSIX_TIMEZONE:
268214478Srpaulo		return "POSIX-timezone";
269190207Srpaulo	case DH6OPT_NEW_TZDB_TIMEZONE:
270214478Srpaulo		return "POSIX-tz-database";
271190207Srpaulo	case DH6OPT_ERO:
272214478Srpaulo		return "Echo-request-option";
273190207Srpaulo	case DH6OPT_LQ_QUERY:
274214478Srpaulo		return "Lease-query";
275190207Srpaulo	case DH6OPT_CLIENT_DATA:
276214478Srpaulo		return "LQ-client-data";
277190207Srpaulo	case DH6OPT_CLT_TIME:
278214478Srpaulo		return "Clt-time";
279190207Srpaulo	case DH6OPT_LQ_RELAY_DATA:
280214478Srpaulo		return "LQ-relay-data";
281190207Srpaulo	case DH6OPT_LQ_CLIENT_LINK:
282214478Srpaulo		return "LQ-client-link";
283252283Sdelphij	case DH6OPT_AFTR_NAME:
284252283Sdelphij		return "AFTR-Name";
285127668Sbms	default:
286127668Sbms		snprintf(genstr, sizeof(genstr), "opt_%d", type);
287127668Sbms		return(genstr);
288127668Sbms	}
289127668Sbms}
290127668Sbms
291127668Sbmsstatic const char *
292127668Sbmsdhcp6stcode(int code)
293127668Sbms{
294127668Sbms	static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */
295127668Sbms
296127668Sbms	if (code > 255)
297127668Sbms		return "INVALID code";
298127668Sbms
299127668Sbms	switch(code) {
300127668Sbms	case DH6OPT_STCODE_SUCCESS:
301127668Sbms		return "success";
302127668Sbms	case DH6OPT_STCODE_UNSPECFAIL:
303127668Sbms		return "unspec failure";
304127668Sbms	case DH6OPT_STCODE_NOADDRAVAIL:
305127668Sbms		return "no addresses";
306127668Sbms	case DH6OPT_STCODE_NOBINDING:
307127668Sbms		return "no binding";
308127668Sbms	case DH6OPT_STCODE_NOTONLINK:
309127668Sbms		return "not on-link";
310127668Sbms	case DH6OPT_STCODE_USEMULTICAST:
311127668Sbms		return "use multicast";
312127668Sbms	case DH6OPT_STCODE_NOPREFIXAVAIL:
313127668Sbms		return "no prefixes";
314190207Srpaulo	case DH6OPT_STCODE_UNKNOWNQUERYTYPE:
315190207Srpaulo		return "unknown query type";
316190207Srpaulo	case DH6OPT_STCODE_MALFORMEDQUERY:
317190207Srpaulo		return "malformed query";
318190207Srpaulo	case DH6OPT_STCODE_NOTCONFIGURED:
319190207Srpaulo		return "not configured";
320190207Srpaulo	case DH6OPT_STCODE_NOTALLOWED:
321190207Srpaulo		return "not allowed";
322127668Sbms	default:
323127668Sbms		snprintf(genstr, sizeof(genstr), "code%d", code);
324127668Sbms		return(genstr);
325127668Sbms	}
326127668Sbms}
327127668Sbms
32856893Sfennerstatic void
329127668Sbmsdhcp6opt_print(const u_char *cp, const u_char *ep)
33056893Sfenner{
331111726Sfenner	struct dhcp6opt *dh6o;
332111726Sfenner	u_char *tp;
333127668Sbms	size_t i;
334127668Sbms	u_int16_t opttype;
335111726Sfenner	size_t optlen;
336214478Srpaulo	u_int8_t auth_proto;
337146773Ssam	u_int authinfolen, authrealmlen;
33856893Sfenner
33956893Sfenner	if (cp == ep)
34056893Sfenner		return;
34156893Sfenner	while (cp < ep) {
342127668Sbms		if (ep < cp + sizeof(*dh6o))
343111726Sfenner			goto trunc;
344111726Sfenner		dh6o = (struct dhcp6opt *)cp;
345252283Sdelphij		TCHECK(*dh6o);
346127668Sbms		optlen = EXTRACT_16BITS(&dh6o->dh6opt_len);
347127668Sbms		if (ep < cp + sizeof(*dh6o) + optlen)
348111726Sfenner			goto trunc;
349127668Sbms		opttype = EXTRACT_16BITS(&dh6o->dh6opt_type);
350127668Sbms		printf(" (%s", dhcp6opt_name(opttype));
351127668Sbms		switch (opttype) {
352127668Sbms		case DH6OPT_CLIENTID:
353127668Sbms		case DH6OPT_SERVERID:
354111726Sfenner			if (optlen < 2) {
355111726Sfenner				/*(*/
356127668Sbms				printf(" ?)");
357111726Sfenner				break;
358111726Sfenner			}
359111726Sfenner			tp = (u_char *)(dh6o + 1);
360127668Sbms			switch (EXTRACT_16BITS(tp)) {
361111726Sfenner			case 1:
362111726Sfenner				if (optlen >= 2 + 6) {
363127668Sbms					printf(" hwaddr/time type %u time %u ",
364127668Sbms					    EXTRACT_16BITS(&tp[2]),
365127668Sbms					    EXTRACT_32BITS(&tp[4]));
366111726Sfenner					for (i = 8; i < optlen; i++)
367111726Sfenner						printf("%02x", tp[i]);
368111726Sfenner					/*(*/
369111726Sfenner					printf(")");
370111726Sfenner				} else {
371111726Sfenner					/*(*/
372127668Sbms					printf(" ?)");
373111726Sfenner				}
374111726Sfenner				break;
375111726Sfenner			case 2:
376111726Sfenner				if (optlen >= 2 + 8) {
377111726Sfenner					printf(" vid ");
378111726Sfenner					for (i = 2; i < 2 + 8; i++)
379111726Sfenner						printf("%02x", tp[i]);
380111726Sfenner					/*(*/
381111726Sfenner					printf(")");
382111726Sfenner				} else {
383111726Sfenner					/*(*/
384127668Sbms					printf(" ?)");
385111726Sfenner				}
386111726Sfenner				break;
387111726Sfenner			case 3:
388111726Sfenner				if (optlen >= 2 + 2) {
389111726Sfenner					printf(" hwaddr type %u ",
390127668Sbms					    EXTRACT_16BITS(&tp[2]));
391111726Sfenner					for (i = 4; i < optlen; i++)
392111726Sfenner						printf("%02x", tp[i]);
393111726Sfenner					/*(*/
394111726Sfenner					printf(")");
395111726Sfenner				} else {
396111726Sfenner					/*(*/
397127668Sbms					printf(" ?)");
398111726Sfenner				}
399127668Sbms				break;
400127668Sbms			default:
401127668Sbms				printf(" type %d)", EXTRACT_16BITS(tp));
402127668Sbms				break;
403111726Sfenner			}
40475115Sfenner			break;
405172683Smlaier		case DH6OPT_IA_ADDR:
406214478Srpaulo			if (optlen < 24) {
407214478Srpaulo				/*(*/
408172683Smlaier				printf(" ?)");
409172683Smlaier				break;
410172683Smlaier			}
411214478Srpaulo			tp = (u_char *)(dh6o + 1);
412214478Srpaulo			printf(" %s", ip6addr_string(&tp[0]));
413214478Srpaulo			printf(" pltime:%u vltime:%u",
414214478Srpaulo			    EXTRACT_32BITS(&tp[16]),
415214478Srpaulo			    EXTRACT_32BITS(&tp[20]));
416214478Srpaulo			if (optlen > 24) {
417172683Smlaier				/* there are sub-options */
418252283Sdelphij				dhcp6opt_print(tp + 24, tp + optlen);
419172683Smlaier			}
420172683Smlaier			printf(")");
421172683Smlaier			break;
422127668Sbms		case DH6OPT_ORO:
423190207Srpaulo		case DH6OPT_ERO:
424127668Sbms			if (optlen % 2) {
425127668Sbms				printf(" ?)");
426127668Sbms				break;
427127668Sbms			}
428127668Sbms			tp = (u_char *)(dh6o + 1);
429127668Sbms			for (i = 0; i < optlen; i += 2) {
430214478Srpaulo				printf(" %s",
431214478Srpaulo				    dhcp6opt_name(EXTRACT_16BITS(&tp[i])));
432127668Sbms			}
433127668Sbms			printf(")");
434127668Sbms			break;
435127668Sbms		case DH6OPT_PREFERENCE:
436127668Sbms			if (optlen != 1) {
437127668Sbms				printf(" ?)");
438127668Sbms				break;
439127668Sbms			}
440214478Srpaulo			tp = (u_char *)(dh6o + 1);
441214478Srpaulo			printf(" %d)", *tp);
442127668Sbms			break;
443127668Sbms		case DH6OPT_ELAPSED_TIME:
444127668Sbms			if (optlen != 2) {
445127668Sbms				printf(" ?)");
446127668Sbms				break;
447127668Sbms			}
448214478Srpaulo			tp = (u_char *)(dh6o + 1);
449214478Srpaulo			printf(" %d)", EXTRACT_16BITS(tp));
450127668Sbms			break;
451127668Sbms		case DH6OPT_RELAY_MSG:
452127668Sbms			printf(" (");
453214478Srpaulo			tp = (u_char *)(dh6o + 1);
454214478Srpaulo			dhcp6_print(tp, optlen);
455127668Sbms			printf(")");
456127668Sbms			break;
457146773Ssam		case DH6OPT_AUTH:
458214478Srpaulo			if (optlen < 11) {
459146773Ssam				printf(" ?)");
460146773Ssam				break;
461146773Ssam			}
462214478Srpaulo			tp = (u_char *)(dh6o + 1);
463214478Srpaulo			auth_proto = *tp;
464214478Srpaulo			switch (auth_proto) {
465146773Ssam			case DH6OPT_AUTHPROTO_DELAYED:
466146773Ssam				printf(" proto: delayed");
467146773Ssam				break;
468146773Ssam			case DH6OPT_AUTHPROTO_RECONFIG:
469146773Ssam				printf(" proto: reconfigure");
470146773Ssam				break;
471146773Ssam			default:
472214478Srpaulo				printf(" proto: %d", auth_proto);
473146773Ssam				break;
474146773Ssam			}
475214478Srpaulo			tp++;
476214478Srpaulo			switch (*tp) {
477146773Ssam			case DH6OPT_AUTHALG_HMACMD5:
478146773Ssam				/* XXX: may depend on the protocol */
479146773Ssam				printf(", alg: HMAC-MD5");
480146773Ssam				break;
481146773Ssam			default:
482214478Srpaulo				printf(", alg: %d", *tp);
483146773Ssam				break;
484146773Ssam			}
485214478Srpaulo			tp++;
486214478Srpaulo			switch (*tp) {
487146773Ssam			case DH6OPT_AUTHRDM_MONOCOUNTER:
488146773Ssam				printf(", RDM: mono");
489146773Ssam				break;
490146773Ssam			default:
491214478Srpaulo				printf(", RDM: %d", *tp);
492146773Ssam				break;
493146773Ssam			}
494214478Srpaulo			tp++;
495146773Ssam			printf(", RD:");
496214478Srpaulo			for (i = 0; i < 4; i++, tp += 2)
497146773Ssam				printf(" %04x", EXTRACT_16BITS(tp));
498146773Ssam
499146773Ssam			/* protocol dependent part */
500214478Srpaulo			authinfolen = optlen - 11;
501214478Srpaulo			switch (auth_proto) {
502146773Ssam			case DH6OPT_AUTHPROTO_DELAYED:
503146773Ssam				if (authinfolen == 0)
504146773Ssam					break;
505146773Ssam				if (authinfolen < 20) {
506146773Ssam					printf(" ??");
507146773Ssam					break;
508146773Ssam				}
509146773Ssam				authrealmlen = authinfolen - 20;
510146773Ssam				if (authrealmlen > 0) {
511146773Ssam					printf(", realm: ");
512146773Ssam				}
513146773Ssam				for (i = 0; i < authrealmlen; i++, tp++)
514146773Ssam					printf("%02x", *tp);
515146773Ssam				printf(", key ID: %08x", EXTRACT_32BITS(tp));
516146773Ssam				tp += 4;
517146773Ssam				printf(", HMAC-MD5:");
518146773Ssam				for (i = 0; i < 4; i++, tp+= 4)
519146773Ssam					printf(" %08x", EXTRACT_32BITS(tp));
520146773Ssam				break;
521146773Ssam			case DH6OPT_AUTHPROTO_RECONFIG:
522146773Ssam				if (authinfolen != 17) {
523146773Ssam					printf(" ??");
524146773Ssam					break;
525146773Ssam				}
526146773Ssam				switch (*tp++) {
527146773Ssam				case DH6OPT_AUTHRECONFIG_KEY:
528146773Ssam					printf(" reconfig-key");
529146773Ssam					break;
530146773Ssam				case DH6OPT_AUTHRECONFIG_HMACMD5:
531146773Ssam					printf(" type: HMAC-MD5");
532146773Ssam					break;
533146773Ssam				default:
534146773Ssam					printf(" type: ??");
535146773Ssam					break;
536146773Ssam				}
537146773Ssam				printf(" value:");
538146773Ssam				for (i = 0; i < 4; i++, tp+= 4)
539146773Ssam					printf(" %08x", EXTRACT_32BITS(tp));
540146773Ssam				break;
541146773Ssam			default:
542146773Ssam				printf(" ??");
543146773Ssam				break;
544146773Ssam			}
545146773Ssam
546146773Ssam			printf(")");
547146773Ssam			break;
548127668Sbms		case DH6OPT_RAPID_COMMIT: /* nothing todo */
549127668Sbms			printf(")");
550127668Sbms			break;
551127668Sbms		case DH6OPT_INTERFACE_ID:
552190207Srpaulo		case DH6OPT_SUBSCRIBER_ID:
553127668Sbms			/*
554127668Sbms			 * Since we cannot predict the encoding, print hex dump
555127668Sbms			 * at most 10 characters.
556127668Sbms			 */
557214478Srpaulo			tp = (u_char *)(dh6o + 1);
558190207Srpaulo			printf(" ");
559127668Sbms			for (i = 0; i < optlen && i < 10; i++)
560214478Srpaulo				printf("%02x", tp[i]);
561190207Srpaulo			printf("...)");
562127668Sbms			break;
563127668Sbms		case DH6OPT_RECONF_MSG:
564127668Sbms			tp = (u_char *)(dh6o + 1);
565127668Sbms			switch (*tp) {
566127668Sbms			case DH6_RENEW:
567127668Sbms				printf(" for renew)");
568127668Sbms				break;
569127668Sbms			case DH6_INFORM_REQ:
570127668Sbms				printf(" for inf-req)");
571127668Sbms				break;
572127668Sbms			default:
573127668Sbms				printf(" for ?\?\?(%02x))", *tp);
574127668Sbms				break;
575127668Sbms			}
576127668Sbms			break;
577127668Sbms		case DH6OPT_RECONF_ACCEPT: /* nothing todo */
578127668Sbms			printf(")");
579127668Sbms			break;
580127668Sbms		case DH6OPT_SIP_SERVER_A:
581111726Sfenner		case DH6OPT_DNS:
582127668Sbms		case DH6OPT_NTP_SERVERS:
583172683Smlaier		case DH6OPT_NIS_SERVERS:
584172683Smlaier		case DH6OPT_NISP_SERVERS:
585172683Smlaier		case DH6OPT_BCMCS_SERVER_A:
586190207Srpaulo		case DH6OPT_PANA_AGENT:
587190207Srpaulo		case DH6OPT_LQ_CLIENT_LINK:
588111726Sfenner			if (optlen % 16) {
589127668Sbms				printf(" ?)");
590111726Sfenner				break;
591111726Sfenner			}
592111726Sfenner			tp = (u_char *)(dh6o + 1);
593111726Sfenner			for (i = 0; i < optlen; i += 16)
594111726Sfenner				printf(" %s", ip6addr_string(&tp[i]));
595111726Sfenner			printf(")");
596127668Sbms			break;
597127668Sbms		case DH6OPT_STATUS_CODE:
598127668Sbms			if (optlen < 2) {
599127668Sbms				printf(" ?)");
600127668Sbms				break;
601127668Sbms			}
602214478Srpaulo			tp = (u_char *)(dh6o + 1);
603214478Srpaulo			printf(" %s)", dhcp6stcode(EXTRACT_16BITS(&tp[0])));
604127668Sbms			break;
605127668Sbms		case DH6OPT_IA_NA:
606127668Sbms		case DH6OPT_IA_PD:
607214478Srpaulo			if (optlen < 12) {
608127668Sbms				printf(" ?)");
609127668Sbms				break;
610127668Sbms			}
611214478Srpaulo			tp = (u_char *)(dh6o + 1);
612214478Srpaulo			printf(" IAID:%u T1:%u T2:%u",
613214478Srpaulo			    EXTRACT_32BITS(&tp[0]),
614214478Srpaulo			    EXTRACT_32BITS(&tp[4]),
615214478Srpaulo			    EXTRACT_32BITS(&tp[8]));
616214478Srpaulo			if (optlen > 12) {
617127668Sbms				/* there are sub-options */
618252283Sdelphij				dhcp6opt_print(tp + 12, tp + optlen);
619127668Sbms			}
620127668Sbms			printf(")");
621127668Sbms			break;
622190207Srpaulo		case DH6OPT_IA_TA:
623190207Srpaulo			if (optlen < 4) {
624190207Srpaulo				printf(" ?)");
625190207Srpaulo				break;
626190207Srpaulo			}
627214478Srpaulo			tp = (u_char *)(dh6o + 1);
628214478Srpaulo			printf(" IAID:%u", EXTRACT_32BITS(tp));
629190207Srpaulo			if (optlen > 4) {
630190207Srpaulo				/* there are sub-options */
631252283Sdelphij				dhcp6opt_print(tp + 4, tp + optlen);
632190207Srpaulo			}
633190207Srpaulo			printf(")");
634190207Srpaulo			break;
635127668Sbms		case DH6OPT_IA_PD_PREFIX:
636214478Srpaulo			if (optlen < 25) {
637127668Sbms				printf(" ?)");
638127668Sbms				break;
639127668Sbms			}
640214478Srpaulo			tp = (u_char *)(dh6o + 1);
641214478Srpaulo			printf(" %s/%d", ip6addr_string(&tp[9]), tp[8]);
642214478Srpaulo			printf(" pltime:%u vltime:%u",
643214478Srpaulo			    EXTRACT_32BITS(&tp[0]),
644214478Srpaulo			    EXTRACT_32BITS(&tp[4]));
645214478Srpaulo			if (optlen > 25) {
646127668Sbms				/* there are sub-options */
647252283Sdelphij				dhcp6opt_print(tp + 25, tp + optlen);
648127668Sbms			}
649127668Sbms			printf(")");
650127668Sbms			break;
651146773Ssam		case DH6OPT_LIFETIME:
652190207Srpaulo		case DH6OPT_CLT_TIME:
653146773Ssam			if (optlen != 4) {
654146773Ssam				printf(" ?)");
655146773Ssam				break;
656146773Ssam			}
657214478Srpaulo			tp = (u_char *)(dh6o + 1);
658214478Srpaulo			printf(" %d)", EXTRACT_32BITS(tp));
659146773Ssam			break;
660190207Srpaulo		case DH6OPT_REMOTE_ID:
661190207Srpaulo			if (optlen < 4) {
662190207Srpaulo				printf(" ?)");
663190207Srpaulo				break;
664190207Srpaulo			}
665190207Srpaulo			tp = (u_char *)(dh6o + 1);
666214478Srpaulo			printf(" %d ", EXTRACT_32BITS(tp));
667190207Srpaulo			/*
668190207Srpaulo			 * Print hex dump first 10 characters.
669190207Srpaulo			 */
670190207Srpaulo			for (i = 4; i < optlen && i < 14; i++)
671190207Srpaulo				printf("%02x", tp[i]);
672190207Srpaulo			printf("...)");
673190207Srpaulo			break;
674190207Srpaulo		case DH6OPT_LQ_QUERY:
675190207Srpaulo			if (optlen < 17) {
676190207Srpaulo				printf(" ?)");
677190207Srpaulo				break;
678190207Srpaulo			}
679190207Srpaulo			tp = (u_char *)(dh6o + 1);
680190207Srpaulo			switch (*tp) {
681190207Srpaulo			case 1:
682190207Srpaulo				printf(" by-address");
683190207Srpaulo				break;
684190207Srpaulo			case 2:
685190207Srpaulo				printf(" by-clientID");
686190207Srpaulo				break;
687190207Srpaulo			default:
688190207Srpaulo				printf(" type_%d", (int)*tp);
689190207Srpaulo				break;
690190207Srpaulo			}
691190207Srpaulo			printf(" %s", ip6addr_string(&tp[1]));
692190207Srpaulo			if (optlen > 17) {
693190207Srpaulo				/* there are query-options */
694190207Srpaulo				dhcp6opt_print(tp + 17, tp + optlen);
695190207Srpaulo			}
696190207Srpaulo			printf(")");
697190207Srpaulo			break;
698190207Srpaulo		case DH6OPT_CLIENT_DATA:
699214478Srpaulo			tp = (u_char *)(dh6o + 1);
700190207Srpaulo			if (optlen > 0) {
701190207Srpaulo				/* there are encapsulated options */
702214478Srpaulo				dhcp6opt_print(tp, tp + optlen);
703190207Srpaulo			}
704190207Srpaulo			printf(")");
705190207Srpaulo			break;
706190207Srpaulo		case DH6OPT_LQ_RELAY_DATA:
707190207Srpaulo			if (optlen < 16) {
708190207Srpaulo				printf(" ?)");
709190207Srpaulo				break;
710190207Srpaulo			}
711190207Srpaulo			tp = (u_char *)(dh6o + 1);
712190207Srpaulo			printf(" %s ", ip6addr_string(&tp[0]));
713190207Srpaulo			/*
714190207Srpaulo			 * Print hex dump first 10 characters.
715190207Srpaulo			 */
716190207Srpaulo			for (i = 16; i < optlen && i < 26; i++)
717190207Srpaulo				printf("%02x", tp[i]);
718190207Srpaulo			printf("...)");
719190207Srpaulo			break;
720252283Sdelphij		case DH6OPT_AFTR_NAME:
721252283Sdelphij			if (optlen < 3) {
722252283Sdelphij				printf(" ?)");
723252283Sdelphij				break;
724252283Sdelphij			}
725252283Sdelphij			tp = (u_char *)(dh6o + 1);
726252283Sdelphij			int remain_len = optlen;
727252283Sdelphij			printf(" ");
728252283Sdelphij			/* Encoding is described in section 3.1 of RFC 1035 */
729252283Sdelphij			int label_len; /* Label length */
730252283Sdelphij			while (remain_len && *tp) {
731252283Sdelphij				label_len =  *tp++;
732252283Sdelphij				if (label_len < remain_len - 1) {
733252283Sdelphij					printf("%.*s", label_len, tp);
734252283Sdelphij					tp += label_len;
735252283Sdelphij					remain_len -= (label_len + 1);
736252283Sdelphij					if(*tp) printf(".");
737252283Sdelphij				} else {
738252283Sdelphij					printf(" ?");
739252283Sdelphij					break;
740252283Sdelphij				}
741252283Sdelphij			}
742252283Sdelphij			printf(")");
743252283Sdelphij			break;
74456893Sfenner		default:
745127668Sbms			printf(")");
74656893Sfenner			break;
74756893Sfenner		}
74856893Sfenner
749111726Sfenner		cp += sizeof(*dh6o) + optlen;
75056893Sfenner	}
75156893Sfenner	return;
75256893Sfenner
75356893Sfennertrunc:
75456893Sfenner	printf("[|dhcp6ext]");
75556893Sfenner}
75656893Sfenner
75756893Sfenner/*
758111726Sfenner * Print dhcp6 packets
75956893Sfenner */
76056893Sfennervoid
761127668Sbmsdhcp6_print(const u_char *cp, u_int length)
76256893Sfenner{
763111726Sfenner	struct dhcp6 *dh6;
764127668Sbms	struct dhcp6_relay *dh6relay;
765127668Sbms	const u_char *ep;
76656893Sfenner	u_char *extp;
767111726Sfenner	const char *name;
76856893Sfenner
76956893Sfenner	printf("dhcp6");
77056893Sfenner
77156893Sfenner	ep = (u_char *)snapend;
772127668Sbms	if (cp + length < ep)
773127668Sbms		ep = cp + length;
77456893Sfenner
775111726Sfenner	dh6 = (struct dhcp6 *)cp;
776127668Sbms	dh6relay = (struct dhcp6_relay *)cp;
777127668Sbms	TCHECK(dh6->dh6_xid);
77856893Sfenner	switch (dh6->dh6_msgtype) {
779127668Sbms	case DH6_SOLICIT:
780127668Sbms		name = "solicit";
781127668Sbms		break;
782127668Sbms	case DH6_ADVERTISE:
783127668Sbms		name = "advertise";
784127668Sbms		break;
785127668Sbms	case DH6_REQUEST:
786127668Sbms		name = "request";
787127668Sbms		break;
788127668Sbms	case DH6_CONFIRM:
789127668Sbms		name = "confirm";
790127668Sbms		break;
791127668Sbms	case DH6_RENEW:
792127668Sbms		name = "renew";
793127668Sbms		break;
794127668Sbms	case DH6_REBIND:
795127668Sbms		name = "rebind";
796127668Sbms		break;
79756893Sfenner	case DH6_REPLY:
798111726Sfenner		name = "reply";
79956893Sfenner		break;
800127668Sbms	case DH6_RELEASE:
801127668Sbms		name = "release";
802127668Sbms		break;
803127668Sbms	case DH6_DECLINE:
804127668Sbms		name = "decline";
805127668Sbms		break;
806127668Sbms	case DH6_RECONFIGURE:
807127668Sbms		name = "reconfigure";
808127668Sbms		break;
809111726Sfenner	case DH6_INFORM_REQ:
810111726Sfenner		name= "inf-req";
81156893Sfenner		break;
812127668Sbms	case DH6_RELAY_FORW:
813127668Sbms		name= "relay-fwd";
814127668Sbms		break;
815127668Sbms	case DH6_RELAY_REPLY:
816127668Sbms		name= "relay-reply";
817127668Sbms		break;
818190207Srpaulo	case DH6_LEASEQUERY:
819190207Srpaulo		name= "leasequery";
820190207Srpaulo		break;
821190207Srpaulo	case DH6_LQ_REPLY:
822190207Srpaulo		name= "leasequery-reply";
823190207Srpaulo		break;
824111726Sfenner	default:
825111726Sfenner		name = NULL;
82656893Sfenner		break;
82756893Sfenner	}
828111726Sfenner
829111726Sfenner	if (!vflag) {
830111726Sfenner		if (name)
831111726Sfenner			printf(" %s", name);
832127668Sbms		else if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
833127668Sbms		    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
834111726Sfenner			printf(" msgtype-%u", dh6->dh6_msgtype);
835127668Sbms		}
836111726Sfenner		return;
837111726Sfenner	}
838111726Sfenner
839111726Sfenner	/* XXX relay agent messages have to be handled differently */
840111726Sfenner
841111726Sfenner	if (name)
842111726Sfenner		printf(" %s (", name);	/*)*/
843111726Sfenner	else
844111726Sfenner		printf(" msgtype-%u (", dh6->dh6_msgtype);	/*)*/
845127668Sbms	if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
846127668Sbms	    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
847127668Sbms		printf("xid=%x", EXTRACT_32BITS(&dh6->dh6_xid) & DH6_XIDMASK);
848127668Sbms		extp = (u_char *)(dh6 + 1);
849127668Sbms		dhcp6opt_print(extp, ep);
850127668Sbms	} else {		/* relay messages */
851127668Sbms		struct in6_addr addr6;
852127668Sbms
853127668Sbms		TCHECK(dh6relay->dh6relay_peeraddr);
854127668Sbms
855127668Sbms		memcpy(&addr6, dh6relay->dh6relay_linkaddr, sizeof (addr6));
856127668Sbms		printf("linkaddr=%s", ip6addr_string(&addr6));
857127668Sbms
858127668Sbms		memcpy(&addr6, dh6relay->dh6relay_peeraddr, sizeof (addr6));
859127668Sbms		printf(" peeraddr=%s", ip6addr_string(&addr6));
860127668Sbms
861127668Sbms		dhcp6opt_print((u_char *)(dh6relay + 1), ep);
862127668Sbms	}
863111726Sfenner	/*(*/
864111726Sfenner	printf(")");
86556893Sfenner	return;
86656893Sfenner
86756893Sfennertrunc:
868111726Sfenner	printf("[|dhcp6]");
86956893Sfenner}
870