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
31276788Sdelphij * supported DHCPv6 options:
32251158Sdelphij *  RFC3319: Session Initiation Protocol (SIP) Servers options,
33251158Sdelphij *  RFC3633: IPv6 Prefix options,
34251158Sdelphij *  RFC3646: DNS Configuration options,
35251158Sdelphij *  RFC3898: Network Information Service (NIS) Configuration options,
36251158Sdelphij *  RFC4075: Simple Network Time Protocol (SNTP) Configuration option,
37251158Sdelphij *  RFC4242: Information Refresh Time option,
38251158Sdelphij *  RFC4280: Broadcast and Multicast Control Servers options,
39276788Sdelphij *  RFC5908: Network Time Protocol (NTP) Server Option for DHCPv6
40251158Sdelphij *  RFC6334: Dual-Stack Lite option,
41111726Sfenner */
4256893Sfenner
43276788Sdelphij#define NETDISSECT_REWORKED
4456893Sfenner#ifdef HAVE_CONFIG_H
4556893Sfenner#include "config.h"
4656893Sfenner#endif
4756893Sfenner
48127668Sbms#include <tcpdump-stdinc.h>
4956893Sfenner
5056893Sfenner#include <stdio.h>
5156893Sfenner#include <string.h>
5256893Sfenner
5356893Sfenner#include "interface.h"
5456893Sfenner#include "addrtoname.h"
55127668Sbms#include "extract.h"
5656893Sfenner
57127668Sbms/* lease duration */
58276788Sdelphij#define DHCP6_DURATION_INFINITE 0xffffffff
59127668Sbms
60111726Sfenner/* Error Values */
61111726Sfenner#define DH6ERR_FAILURE		16
62111726Sfenner#define DH6ERR_AUTHFAIL		17
63111726Sfenner#define DH6ERR_POORLYFORMED	18
64111726Sfenner#define DH6ERR_UNAVAIL		19
65111726Sfenner#define DH6ERR_OPTUNAVAIL	20
6656893Sfenner
67111726Sfenner/* Message type */
68127668Sbms#define DH6_SOLICIT	1
69127668Sbms#define DH6_ADVERTISE	2
70127668Sbms#define DH6_REQUEST	3
71127668Sbms#define DH6_CONFIRM	4
72127668Sbms#define DH6_RENEW	5
73127668Sbms#define DH6_REBIND	6
74111726Sfenner#define DH6_REPLY	7
75127668Sbms#define DH6_RELEASE	8
76127668Sbms#define DH6_DECLINE	9
77127668Sbms#define DH6_RECONFIGURE	10
78111726Sfenner#define DH6_INFORM_REQ	11
79127668Sbms#define DH6_RELAY_FORW	12
80127668Sbms#define DH6_RELAY_REPLY	13
81190207Srpaulo#define DH6_LEASEQUERY	14
82190207Srpaulo#define DH6_LQ_REPLY	15
8356893Sfenner
84276788Sdelphijstatic const struct tok dh6_msgtype_str[] = {
85276788Sdelphij	{ DH6_SOLICIT,     "solicit"          },
86276788Sdelphij	{ DH6_ADVERTISE,   "advertise"        },
87276788Sdelphij	{ DH6_REQUEST,     "request"          },
88276788Sdelphij	{ DH6_CONFIRM,     "confirm"          },
89276788Sdelphij	{ DH6_RENEW,       "renew"            },
90276788Sdelphij	{ DH6_REBIND,      "rebind"           },
91276788Sdelphij	{ DH6_REPLY,       "reply"            },
92276788Sdelphij	{ DH6_RELEASE,     "release"          },
93276788Sdelphij	{ DH6_DECLINE,     "decline"          },
94276788Sdelphij	{ DH6_RECONFIGURE, "reconfigure"      },
95276788Sdelphij	{ DH6_INFORM_REQ,  "inf-req"          },
96276788Sdelphij	{ DH6_RELAY_FORW,  "relay-fwd"        },
97276788Sdelphij	{ DH6_RELAY_REPLY, "relay-reply"      },
98276788Sdelphij	{ DH6_LEASEQUERY,  "leasequery"       },
99276788Sdelphij	{ DH6_LQ_REPLY,    "leasequery-reply" },
100276788Sdelphij	{ 0, NULL }
101276788Sdelphij};
102276788Sdelphij
103111726Sfenner/* DHCP6 base packet format */
104111726Sfennerstruct dhcp6 {
105111726Sfenner	union {
106276788Sdelphij		uint8_t m;
107276788Sdelphij		uint32_t x;
108111726Sfenner	} dh6_msgtypexid;
109111726Sfenner	/* options follow */
110127668Sbms};
111111726Sfenner#define dh6_msgtype	dh6_msgtypexid.m
112111726Sfenner#define dh6_xid		dh6_msgtypexid.x
113111726Sfenner#define DH6_XIDMASK	0x00ffffff
11456893Sfenner
115127668Sbms/* DHCPv6 relay messages */
116127668Sbmsstruct dhcp6_relay {
117276788Sdelphij	uint8_t dh6relay_msgtype;
118276788Sdelphij	uint8_t dh6relay_hcnt;
119276788Sdelphij	uint8_t dh6relay_linkaddr[16];	/* XXX: badly aligned */
120276788Sdelphij	uint8_t dh6relay_peeraddr[16];
121127668Sbms	/* options follow */
122127668Sbms};
123127668Sbms
124127668Sbms/* options */
125127668Sbms#define DH6OPT_CLIENTID	1
126127668Sbms#define DH6OPT_SERVERID	2
127127668Sbms#define DH6OPT_IA_NA 3
128172683Smlaier#define DH6OPT_IA_TA 4
129172683Smlaier#define DH6OPT_IA_ADDR 5
130127668Sbms#define DH6OPT_ORO 6
131127668Sbms#define DH6OPT_PREFERENCE 7
132127668Sbms#  define DH6OPT_PREF_MAX 255
133127668Sbms#define DH6OPT_ELAPSED_TIME 8
134127668Sbms#define DH6OPT_RELAY_MSG 9
135127668Sbms/*#define DH6OPT_SERVER_MSG 10 deprecated */
136127668Sbms#define DH6OPT_AUTH 11
137146773Ssam#  define DH6OPT_AUTHPROTO_DELAYED 2
138146773Ssam#  define DH6OPT_AUTHPROTO_RECONFIG 3
139146773Ssam#  define DH6OPT_AUTHALG_HMACMD5 1
140146773Ssam#  define DH6OPT_AUTHRDM_MONOCOUNTER 0
141146773Ssam#  define DH6OPT_AUTHRECONFIG_KEY 1
142146773Ssam#  define DH6OPT_AUTHRECONFIG_HMACMD5 2
143127668Sbms#define DH6OPT_UNICAST 12
144127668Sbms#define DH6OPT_STATUS_CODE 13
145127668Sbms#  define DH6OPT_STCODE_SUCCESS 0
146127668Sbms#  define DH6OPT_STCODE_UNSPECFAIL 1
147127668Sbms#  define DH6OPT_STCODE_NOADDRAVAIL 2
148127668Sbms#  define DH6OPT_STCODE_NOBINDING 3
149127668Sbms#  define DH6OPT_STCODE_NOTONLINK 4
150127668Sbms#  define DH6OPT_STCODE_USEMULTICAST 5
151127668Sbms#  define DH6OPT_STCODE_NOPREFIXAVAIL 6
152190207Srpaulo#  define DH6OPT_STCODE_UNKNOWNQUERYTYPE 7
153190207Srpaulo#  define DH6OPT_STCODE_MALFORMEDQUERY 8
154190207Srpaulo#  define DH6OPT_STCODE_NOTCONFIGURED 9
155190207Srpaulo#  define DH6OPT_STCODE_NOTALLOWED 10
156127668Sbms#define DH6OPT_RAPID_COMMIT 14
157127668Sbms#define DH6OPT_USER_CLASS 15
158127668Sbms#define DH6OPT_VENDOR_CLASS 16
159127668Sbms#define DH6OPT_VENDOR_OPTS 17
160127668Sbms#define DH6OPT_INTERFACE_ID 18
161127668Sbms#define DH6OPT_RECONF_MSG 19
162127668Sbms#define DH6OPT_RECONF_ACCEPT 20
163127668Sbms#define DH6OPT_SIP_SERVER_D 21
164127668Sbms#define DH6OPT_SIP_SERVER_A 22
165276788Sdelphij#define DH6OPT_DNS_SERVERS 23
166276788Sdelphij#define DH6OPT_DOMAIN_LIST 24
167146773Ssam#define DH6OPT_IA_PD 25
168146773Ssam#define DH6OPT_IA_PD_PREFIX 26
169172683Smlaier#define DH6OPT_NIS_SERVERS 27
170172683Smlaier#define DH6OPT_NISP_SERVERS 28
171172683Smlaier#define DH6OPT_NIS_NAME 29
172172683Smlaier#define DH6OPT_NISP_NAME 30
173276788Sdelphij#define DH6OPT_SNTP_SERVERS 31
174172683Smlaier#define DH6OPT_LIFETIME 32
175172683Smlaier#define DH6OPT_BCMCS_SERVER_D 33
176172683Smlaier#define DH6OPT_BCMCS_SERVER_A 34
177172683Smlaier#define DH6OPT_GEOCONF_CIVIC 36
178172683Smlaier#define DH6OPT_REMOTE_ID 37
179172683Smlaier#define DH6OPT_SUBSCRIBER_ID 38
180172683Smlaier#define DH6OPT_CLIENT_FQDN 39
181190207Srpaulo#define DH6OPT_PANA_AGENT 40
182190207Srpaulo#define DH6OPT_NEW_POSIX_TIMEZONE 41
183190207Srpaulo#define DH6OPT_NEW_TZDB_TIMEZONE 42
184190207Srpaulo#define DH6OPT_ERO 43
185190207Srpaulo#define DH6OPT_LQ_QUERY 44
186190207Srpaulo#define DH6OPT_CLIENT_DATA 45
187190207Srpaulo#define DH6OPT_CLT_TIME 46
188190207Srpaulo#define DH6OPT_LQ_RELAY_DATA 47
189190207Srpaulo#define DH6OPT_LQ_CLIENT_LINK 48
190276788Sdelphij#define DH6OPT_NTP_SERVER 56
191276788Sdelphij#  define DH6OPT_NTP_SUBOPTION_SRV_ADDR 1
192276788Sdelphij#  define DH6OPT_NTP_SUBOPTION_MC_ADDR 2
193276788Sdelphij#  define DH6OPT_NTP_SUBOPTION_SRV_FQDN 3
194251158Sdelphij#define DH6OPT_AFTR_NAME 64
195127668Sbms
196276788Sdelphijstatic const struct tok dh6opt_str[] = {
197276788Sdelphij	{ DH6OPT_CLIENTID,           "client-ID"            },
198276788Sdelphij	{ DH6OPT_SERVERID,           "server-ID"            },
199276788Sdelphij	{ DH6OPT_IA_NA,              "IA_NA"                },
200276788Sdelphij	{ DH6OPT_IA_TA,              "IA_TA"                },
201276788Sdelphij	{ DH6OPT_IA_ADDR,            "IA_ADDR"              },
202276788Sdelphij	{ DH6OPT_ORO,                "option-request"       },
203276788Sdelphij	{ DH6OPT_PREFERENCE,         "preference"           },
204276788Sdelphij	{ DH6OPT_ELAPSED_TIME,       "elapsed-time"         },
205276788Sdelphij	{ DH6OPT_RELAY_MSG,          "relay-message"        },
206276788Sdelphij	{ DH6OPT_AUTH,               "authentication"       },
207276788Sdelphij	{ DH6OPT_UNICAST,            "server-unicast"       },
208276788Sdelphij	{ DH6OPT_STATUS_CODE,        "status-code"          },
209276788Sdelphij	{ DH6OPT_RAPID_COMMIT,       "rapid-commit"         },
210276788Sdelphij	{ DH6OPT_USER_CLASS,         "user-class"           },
211276788Sdelphij	{ DH6OPT_VENDOR_CLASS,       "vendor-class"         },
212276788Sdelphij	{ DH6OPT_VENDOR_OPTS,        "vendor-specific-info" },
213276788Sdelphij	{ DH6OPT_INTERFACE_ID,       "interface-ID"         },
214276788Sdelphij	{ DH6OPT_RECONF_MSG,         "reconfigure-message"  },
215276788Sdelphij	{ DH6OPT_RECONF_ACCEPT,      "reconfigure-accept"   },
216276788Sdelphij	{ DH6OPT_SIP_SERVER_D,       "SIP-servers-domain"   },
217276788Sdelphij	{ DH6OPT_SIP_SERVER_A,       "SIP-servers-address"  },
218276788Sdelphij	{ DH6OPT_DNS_SERVERS,        "DNS-server"           },
219276788Sdelphij	{ DH6OPT_DOMAIN_LIST,        "DNS-search-list"      },
220276788Sdelphij	{ DH6OPT_IA_PD,              "IA_PD"                },
221276788Sdelphij	{ DH6OPT_IA_PD_PREFIX,       "IA_PD-prefix"         },
222276788Sdelphij	{ DH6OPT_SNTP_SERVERS,       "SNTP-servers"         },
223276788Sdelphij	{ DH6OPT_LIFETIME,           "lifetime"             },
224276788Sdelphij	{ DH6OPT_NIS_SERVERS,        "NIS-server"           },
225276788Sdelphij	{ DH6OPT_NISP_SERVERS,       "NIS+-server"          },
226276788Sdelphij	{ DH6OPT_NIS_NAME,           "NIS-domain-name"      },
227276788Sdelphij	{ DH6OPT_NISP_NAME,          "NIS+-domain-name"     },
228276788Sdelphij	{ DH6OPT_BCMCS_SERVER_D,     "BCMCS-domain-name"    },
229276788Sdelphij	{ DH6OPT_BCMCS_SERVER_A,     "BCMCS-server"         },
230276788Sdelphij	{ DH6OPT_GEOCONF_CIVIC,      "Geoconf-Civic"        },
231276788Sdelphij	{ DH6OPT_REMOTE_ID,          "Remote-ID"            },
232276788Sdelphij	{ DH6OPT_SUBSCRIBER_ID,      "Subscriber-ID"        },
233276788Sdelphij	{ DH6OPT_CLIENT_FQDN,        "Client-FQDN"          },
234276788Sdelphij	{ DH6OPT_PANA_AGENT,         "PANA-agent"           },
235276788Sdelphij	{ DH6OPT_NEW_POSIX_TIMEZONE, "POSIX-timezone"       },
236276788Sdelphij	{ DH6OPT_NEW_TZDB_TIMEZONE,  "POSIX-tz-database"    },
237276788Sdelphij	{ DH6OPT_ERO,                "Echo-request-option"  },
238276788Sdelphij	{ DH6OPT_LQ_QUERY,           "Lease-query"          },
239276788Sdelphij	{ DH6OPT_CLIENT_DATA,        "LQ-client-data"       },
240276788Sdelphij	{ DH6OPT_CLT_TIME,           "Clt-time"             },
241276788Sdelphij	{ DH6OPT_LQ_RELAY_DATA,      "LQ-relay-data"        },
242276788Sdelphij	{ DH6OPT_LQ_CLIENT_LINK,     "LQ-client-link"       },
243276788Sdelphij	{ DH6OPT_NTP_SERVER,         "NTP-server"           },
244276788Sdelphij	{ DH6OPT_AFTR_NAME,          "AFTR-Name"            },
245276788Sdelphij	{ 0, NULL }
246276788Sdelphij};
247276788Sdelphij
248276788Sdelphijstatic const struct tok dh6opt_stcode_str[] = {
249276788Sdelphij	{ DH6OPT_STCODE_SUCCESS,          "success"            },
250276788Sdelphij	{ DH6OPT_STCODE_UNSPECFAIL,       "unspec failure"     },
251276788Sdelphij	{ DH6OPT_STCODE_NOADDRAVAIL,      "no addresses"       },
252276788Sdelphij	{ DH6OPT_STCODE_NOBINDING,        "no binding"         },
253276788Sdelphij	{ DH6OPT_STCODE_NOTONLINK,        "not on-link"        },
254276788Sdelphij	{ DH6OPT_STCODE_USEMULTICAST,     "use multicast"      },
255276788Sdelphij	{ DH6OPT_STCODE_NOPREFIXAVAIL,    "no prefixes"        },
256276788Sdelphij	{ DH6OPT_STCODE_UNKNOWNQUERYTYPE, "unknown query type" },
257276788Sdelphij	{ DH6OPT_STCODE_MALFORMEDQUERY,   "malformed query"    },
258276788Sdelphij	{ DH6OPT_STCODE_NOTCONFIGURED,    "not configured"     },
259276788Sdelphij	{ DH6OPT_STCODE_NOTALLOWED,       "not allowed"        },
260276788Sdelphij	{ 0, NULL }
261276788Sdelphij};
262276788Sdelphij
263111726Sfennerstruct dhcp6opt {
264276788Sdelphij	uint16_t dh6opt_type;
265276788Sdelphij	uint16_t dh6opt_len;
266111726Sfenner	/* type-dependent data follows */
267127668Sbms};
26856893Sfenner
269127668Sbmsstatic const char *
270276788Sdelphijdhcp6stcode(const uint16_t code)
271127668Sbms{
272276788Sdelphij	return code > 255 ? "INVALID code" : tok2str(dh6opt_stcode_str, "code%u", code);
273127668Sbms}
274127668Sbms
27556893Sfennerstatic void
276276788Sdelphijdhcp6opt_print(netdissect_options *ndo,
277276788Sdelphij               const u_char *cp, const u_char *ep)
27856893Sfenner{
279276788Sdelphij	const struct dhcp6opt *dh6o;
280276788Sdelphij	const u_char *tp;
281127668Sbms	size_t i;
282276788Sdelphij	uint16_t opttype;
283111726Sfenner	size_t optlen;
284276788Sdelphij	uint8_t auth_proto;
285146773Ssam	u_int authinfolen, authrealmlen;
286276788Sdelphij	int remain_len;  /* Length of remaining options */
287276788Sdelphij	int label_len;   /* Label length */
288276788Sdelphij	uint16_t subopt_code;
289276788Sdelphij	uint16_t subopt_len;
29056893Sfenner
29156893Sfenner	if (cp == ep)
29256893Sfenner		return;
29356893Sfenner	while (cp < ep) {
294127668Sbms		if (ep < cp + sizeof(*dh6o))
295111726Sfenner			goto trunc;
296111726Sfenner		dh6o = (struct dhcp6opt *)cp;
297276788Sdelphij		ND_TCHECK(*dh6o);
298127668Sbms		optlen = EXTRACT_16BITS(&dh6o->dh6opt_len);
299127668Sbms		if (ep < cp + sizeof(*dh6o) + optlen)
300111726Sfenner			goto trunc;
301127668Sbms		opttype = EXTRACT_16BITS(&dh6o->dh6opt_type);
302276788Sdelphij		ND_PRINT((ndo, " (%s", tok2str(dh6opt_str, "opt_%u", opttype)));
303127668Sbms		switch (opttype) {
304127668Sbms		case DH6OPT_CLIENTID:
305127668Sbms		case DH6OPT_SERVERID:
306111726Sfenner			if (optlen < 2) {
307111726Sfenner				/*(*/
308276788Sdelphij				ND_PRINT((ndo, " ?)"));
309111726Sfenner				break;
310111726Sfenner			}
311111726Sfenner			tp = (u_char *)(dh6o + 1);
312127668Sbms			switch (EXTRACT_16BITS(tp)) {
313111726Sfenner			case 1:
314111726Sfenner				if (optlen >= 2 + 6) {
315276788Sdelphij					ND_PRINT((ndo, " hwaddr/time type %u time %u ",
316127668Sbms					    EXTRACT_16BITS(&tp[2]),
317276788Sdelphij					    EXTRACT_32BITS(&tp[4])));
318111726Sfenner					for (i = 8; i < optlen; i++)
319276788Sdelphij						ND_PRINT((ndo, "%02x", tp[i]));
320111726Sfenner					/*(*/
321276788Sdelphij					ND_PRINT((ndo, ")"));
322111726Sfenner				} else {
323111726Sfenner					/*(*/
324276788Sdelphij					ND_PRINT((ndo, " ?)"));
325111726Sfenner				}
326111726Sfenner				break;
327111726Sfenner			case 2:
328111726Sfenner				if (optlen >= 2 + 8) {
329276788Sdelphij					ND_PRINT((ndo, " vid "));
330111726Sfenner					for (i = 2; i < 2 + 8; i++)
331276788Sdelphij						ND_PRINT((ndo, "%02x", tp[i]));
332111726Sfenner					/*(*/
333276788Sdelphij					ND_PRINT((ndo, ")"));
334111726Sfenner				} else {
335111726Sfenner					/*(*/
336276788Sdelphij					ND_PRINT((ndo, " ?)"));
337111726Sfenner				}
338111726Sfenner				break;
339111726Sfenner			case 3:
340111726Sfenner				if (optlen >= 2 + 2) {
341276788Sdelphij					ND_PRINT((ndo, " hwaddr type %u ",
342276788Sdelphij					    EXTRACT_16BITS(&tp[2])));
343111726Sfenner					for (i = 4; i < optlen; i++)
344276788Sdelphij						ND_PRINT((ndo, "%02x", tp[i]));
345111726Sfenner					/*(*/
346276788Sdelphij					ND_PRINT((ndo, ")"));
347111726Sfenner				} else {
348111726Sfenner					/*(*/
349276788Sdelphij					ND_PRINT((ndo, " ?)"));
350111726Sfenner				}
351127668Sbms				break;
352127668Sbms			default:
353276788Sdelphij				ND_PRINT((ndo, " type %d)", EXTRACT_16BITS(tp)));
354127668Sbms				break;
355111726Sfenner			}
35675115Sfenner			break;
357172683Smlaier		case DH6OPT_IA_ADDR:
358214478Srpaulo			if (optlen < 24) {
359214478Srpaulo				/*(*/
360276788Sdelphij				ND_PRINT((ndo, " ?)"));
361172683Smlaier				break;
362172683Smlaier			}
363214478Srpaulo			tp = (u_char *)(dh6o + 1);
364276788Sdelphij			ND_PRINT((ndo, " %s", ip6addr_string(ndo, &tp[0])));
365276788Sdelphij			ND_PRINT((ndo, " pltime:%u vltime:%u",
366214478Srpaulo			    EXTRACT_32BITS(&tp[16]),
367276788Sdelphij			    EXTRACT_32BITS(&tp[20])));
368214478Srpaulo			if (optlen > 24) {
369172683Smlaier				/* there are sub-options */
370276788Sdelphij				dhcp6opt_print(ndo, tp + 24, tp + optlen);
371172683Smlaier			}
372276788Sdelphij			ND_PRINT((ndo, ")"));
373172683Smlaier			break;
374127668Sbms		case DH6OPT_ORO:
375190207Srpaulo		case DH6OPT_ERO:
376127668Sbms			if (optlen % 2) {
377276788Sdelphij				ND_PRINT((ndo, " ?)"));
378127668Sbms				break;
379127668Sbms			}
380127668Sbms			tp = (u_char *)(dh6o + 1);
381127668Sbms			for (i = 0; i < optlen; i += 2) {
382276788Sdelphij				ND_PRINT((ndo, " %s",
383276788Sdelphij				    tok2str(dh6opt_str, "opt_%u", EXTRACT_16BITS(&tp[i]))));
384127668Sbms			}
385276788Sdelphij			ND_PRINT((ndo, ")"));
386127668Sbms			break;
387127668Sbms		case DH6OPT_PREFERENCE:
388127668Sbms			if (optlen != 1) {
389276788Sdelphij				ND_PRINT((ndo, " ?)"));
390127668Sbms				break;
391127668Sbms			}
392214478Srpaulo			tp = (u_char *)(dh6o + 1);
393276788Sdelphij			ND_PRINT((ndo, " %d)", *tp));
394127668Sbms			break;
395127668Sbms		case DH6OPT_ELAPSED_TIME:
396127668Sbms			if (optlen != 2) {
397276788Sdelphij				ND_PRINT((ndo, " ?)"));
398127668Sbms				break;
399127668Sbms			}
400214478Srpaulo			tp = (u_char *)(dh6o + 1);
401276788Sdelphij			ND_PRINT((ndo, " %d)", EXTRACT_16BITS(tp)));
402127668Sbms			break;
403127668Sbms		case DH6OPT_RELAY_MSG:
404276788Sdelphij			ND_PRINT((ndo, " ("));
405214478Srpaulo			tp = (u_char *)(dh6o + 1);
406276788Sdelphij			dhcp6_print(ndo, tp, optlen);
407276788Sdelphij			ND_PRINT((ndo, ")"));
408127668Sbms			break;
409146773Ssam		case DH6OPT_AUTH:
410214478Srpaulo			if (optlen < 11) {
411276788Sdelphij				ND_PRINT((ndo, " ?)"));
412146773Ssam				break;
413146773Ssam			}
414214478Srpaulo			tp = (u_char *)(dh6o + 1);
415214478Srpaulo			auth_proto = *tp;
416214478Srpaulo			switch (auth_proto) {
417146773Ssam			case DH6OPT_AUTHPROTO_DELAYED:
418276788Sdelphij				ND_PRINT((ndo, " proto: delayed"));
419146773Ssam				break;
420146773Ssam			case DH6OPT_AUTHPROTO_RECONFIG:
421276788Sdelphij				ND_PRINT((ndo, " proto: reconfigure"));
422146773Ssam				break;
423146773Ssam			default:
424276788Sdelphij				ND_PRINT((ndo, " proto: %d", auth_proto));
425146773Ssam				break;
426146773Ssam			}
427214478Srpaulo			tp++;
428214478Srpaulo			switch (*tp) {
429146773Ssam			case DH6OPT_AUTHALG_HMACMD5:
430146773Ssam				/* XXX: may depend on the protocol */
431276788Sdelphij				ND_PRINT((ndo, ", alg: HMAC-MD5"));
432146773Ssam				break;
433146773Ssam			default:
434276788Sdelphij				ND_PRINT((ndo, ", alg: %d", *tp));
435146773Ssam				break;
436146773Ssam			}
437214478Srpaulo			tp++;
438214478Srpaulo			switch (*tp) {
439146773Ssam			case DH6OPT_AUTHRDM_MONOCOUNTER:
440276788Sdelphij				ND_PRINT((ndo, ", RDM: mono"));
441146773Ssam				break;
442146773Ssam			default:
443276788Sdelphij				ND_PRINT((ndo, ", RDM: %d", *tp));
444146773Ssam				break;
445146773Ssam			}
446214478Srpaulo			tp++;
447276788Sdelphij			ND_PRINT((ndo, ", RD:"));
448214478Srpaulo			for (i = 0; i < 4; i++, tp += 2)
449276788Sdelphij				ND_PRINT((ndo, " %04x", EXTRACT_16BITS(tp)));
450146773Ssam
451146773Ssam			/* protocol dependent part */
452214478Srpaulo			authinfolen = optlen - 11;
453214478Srpaulo			switch (auth_proto) {
454146773Ssam			case DH6OPT_AUTHPROTO_DELAYED:
455146773Ssam				if (authinfolen == 0)
456146773Ssam					break;
457146773Ssam				if (authinfolen < 20) {
458276788Sdelphij					ND_PRINT((ndo, " ??"));
459146773Ssam					break;
460146773Ssam				}
461146773Ssam				authrealmlen = authinfolen - 20;
462146773Ssam				if (authrealmlen > 0) {
463276788Sdelphij					ND_PRINT((ndo, ", realm: "));
464146773Ssam				}
465146773Ssam				for (i = 0; i < authrealmlen; i++, tp++)
466276788Sdelphij					ND_PRINT((ndo, "%02x", *tp));
467276788Sdelphij				ND_PRINT((ndo, ", key ID: %08x", EXTRACT_32BITS(tp)));
468146773Ssam				tp += 4;
469276788Sdelphij				ND_PRINT((ndo, ", HMAC-MD5:"));
470146773Ssam				for (i = 0; i < 4; i++, tp+= 4)
471276788Sdelphij					ND_PRINT((ndo, " %08x", EXTRACT_32BITS(tp)));
472146773Ssam				break;
473146773Ssam			case DH6OPT_AUTHPROTO_RECONFIG:
474146773Ssam				if (authinfolen != 17) {
475276788Sdelphij					ND_PRINT((ndo, " ??"));
476146773Ssam					break;
477146773Ssam				}
478146773Ssam				switch (*tp++) {
479146773Ssam				case DH6OPT_AUTHRECONFIG_KEY:
480276788Sdelphij					ND_PRINT((ndo, " reconfig-key"));
481146773Ssam					break;
482146773Ssam				case DH6OPT_AUTHRECONFIG_HMACMD5:
483276788Sdelphij					ND_PRINT((ndo, " type: HMAC-MD5"));
484146773Ssam					break;
485146773Ssam				default:
486276788Sdelphij					ND_PRINT((ndo, " type: ??"));
487146773Ssam					break;
488146773Ssam				}
489276788Sdelphij				ND_PRINT((ndo, " value:"));
490146773Ssam				for (i = 0; i < 4; i++, tp+= 4)
491276788Sdelphij					ND_PRINT((ndo, " %08x", EXTRACT_32BITS(tp)));
492146773Ssam				break;
493146773Ssam			default:
494276788Sdelphij				ND_PRINT((ndo, " ??"));
495146773Ssam				break;
496146773Ssam			}
497146773Ssam
498276788Sdelphij			ND_PRINT((ndo, ")"));
499146773Ssam			break;
500127668Sbms		case DH6OPT_RAPID_COMMIT: /* nothing todo */
501276788Sdelphij			ND_PRINT((ndo, ")"));
502127668Sbms			break;
503127668Sbms		case DH6OPT_INTERFACE_ID:
504190207Srpaulo		case DH6OPT_SUBSCRIBER_ID:
505127668Sbms			/*
506127668Sbms			 * Since we cannot predict the encoding, print hex dump
507127668Sbms			 * at most 10 characters.
508127668Sbms			 */
509214478Srpaulo			tp = (u_char *)(dh6o + 1);
510276788Sdelphij			ND_PRINT((ndo, " "));
511127668Sbms			for (i = 0; i < optlen && i < 10; i++)
512276788Sdelphij				ND_PRINT((ndo, "%02x", tp[i]));
513276788Sdelphij			ND_PRINT((ndo, "...)"));
514127668Sbms			break;
515127668Sbms		case DH6OPT_RECONF_MSG:
516127668Sbms			tp = (u_char *)(dh6o + 1);
517127668Sbms			switch (*tp) {
518127668Sbms			case DH6_RENEW:
519276788Sdelphij				ND_PRINT((ndo, " for renew)"));
520127668Sbms				break;
521127668Sbms			case DH6_INFORM_REQ:
522276788Sdelphij				ND_PRINT((ndo, " for inf-req)"));
523127668Sbms				break;
524127668Sbms			default:
525276788Sdelphij				ND_PRINT((ndo, " for ?\?\?(%02x))", *tp));
526127668Sbms				break;
527127668Sbms			}
528127668Sbms			break;
529127668Sbms		case DH6OPT_RECONF_ACCEPT: /* nothing todo */
530276788Sdelphij			ND_PRINT((ndo, ")"));
531127668Sbms			break;
532127668Sbms		case DH6OPT_SIP_SERVER_A:
533276788Sdelphij		case DH6OPT_DNS_SERVERS:
534276788Sdelphij		case DH6OPT_SNTP_SERVERS:
535172683Smlaier		case DH6OPT_NIS_SERVERS:
536172683Smlaier		case DH6OPT_NISP_SERVERS:
537172683Smlaier		case DH6OPT_BCMCS_SERVER_A:
538190207Srpaulo		case DH6OPT_PANA_AGENT:
539190207Srpaulo		case DH6OPT_LQ_CLIENT_LINK:
540111726Sfenner			if (optlen % 16) {
541276788Sdelphij				ND_PRINT((ndo, " ?)"));
542111726Sfenner				break;
543111726Sfenner			}
544111726Sfenner			tp = (u_char *)(dh6o + 1);
545111726Sfenner			for (i = 0; i < optlen; i += 16)
546276788Sdelphij				ND_PRINT((ndo, " %s", ip6addr_string(ndo, &tp[i])));
547276788Sdelphij			ND_PRINT((ndo, ")"));
548127668Sbms			break;
549276788Sdelphij		case DH6OPT_SIP_SERVER_D:
550276788Sdelphij		case DH6OPT_DOMAIN_LIST:
551276788Sdelphij			tp = (u_char *)(dh6o + 1);
552276788Sdelphij			while (tp < cp + sizeof(*dh6o) + optlen) {
553276788Sdelphij				ND_PRINT((ndo, " "));
554276788Sdelphij				if ((tp = ns_nprint(ndo, tp, cp + sizeof(*dh6o) + optlen)) == NULL)
555276788Sdelphij					goto trunc;
556276788Sdelphij			}
557276788Sdelphij			ND_PRINT((ndo, ")"));
558276788Sdelphij			break;
559127668Sbms		case DH6OPT_STATUS_CODE:
560127668Sbms			if (optlen < 2) {
561276788Sdelphij				ND_PRINT((ndo, " ?)"));
562127668Sbms				break;
563127668Sbms			}
564214478Srpaulo			tp = (u_char *)(dh6o + 1);
565276788Sdelphij			ND_PRINT((ndo, " %s)", dhcp6stcode(EXTRACT_16BITS(&tp[0]))));
566127668Sbms			break;
567127668Sbms		case DH6OPT_IA_NA:
568127668Sbms		case DH6OPT_IA_PD:
569214478Srpaulo			if (optlen < 12) {
570276788Sdelphij				ND_PRINT((ndo, " ?)"));
571127668Sbms				break;
572127668Sbms			}
573214478Srpaulo			tp = (u_char *)(dh6o + 1);
574276788Sdelphij			ND_PRINT((ndo, " IAID:%u T1:%u T2:%u",
575214478Srpaulo			    EXTRACT_32BITS(&tp[0]),
576214478Srpaulo			    EXTRACT_32BITS(&tp[4]),
577276788Sdelphij			    EXTRACT_32BITS(&tp[8])));
578214478Srpaulo			if (optlen > 12) {
579127668Sbms				/* there are sub-options */
580276788Sdelphij				dhcp6opt_print(ndo, tp + 12, tp + optlen);
581127668Sbms			}
582276788Sdelphij			ND_PRINT((ndo, ")"));
583127668Sbms			break;
584190207Srpaulo		case DH6OPT_IA_TA:
585190207Srpaulo			if (optlen < 4) {
586276788Sdelphij				ND_PRINT((ndo, " ?)"));
587190207Srpaulo				break;
588190207Srpaulo			}
589214478Srpaulo			tp = (u_char *)(dh6o + 1);
590276788Sdelphij			ND_PRINT((ndo, " IAID:%u", EXTRACT_32BITS(tp)));
591190207Srpaulo			if (optlen > 4) {
592190207Srpaulo				/* there are sub-options */
593276788Sdelphij				dhcp6opt_print(ndo, tp + 4, tp + optlen);
594190207Srpaulo			}
595276788Sdelphij			ND_PRINT((ndo, ")"));
596190207Srpaulo			break;
597127668Sbms		case DH6OPT_IA_PD_PREFIX:
598214478Srpaulo			if (optlen < 25) {
599276788Sdelphij				ND_PRINT((ndo, " ?)"));
600127668Sbms				break;
601127668Sbms			}
602214478Srpaulo			tp = (u_char *)(dh6o + 1);
603276788Sdelphij			ND_PRINT((ndo, " %s/%d", ip6addr_string(ndo, &tp[9]), tp[8]));
604276788Sdelphij			ND_PRINT((ndo, " pltime:%u vltime:%u",
605214478Srpaulo			    EXTRACT_32BITS(&tp[0]),
606276788Sdelphij			    EXTRACT_32BITS(&tp[4])));
607214478Srpaulo			if (optlen > 25) {
608127668Sbms				/* there are sub-options */
609276788Sdelphij				dhcp6opt_print(ndo, tp + 25, tp + optlen);
610127668Sbms			}
611276788Sdelphij			ND_PRINT((ndo, ")"));
612127668Sbms			break;
613146773Ssam		case DH6OPT_LIFETIME:
614190207Srpaulo		case DH6OPT_CLT_TIME:
615146773Ssam			if (optlen != 4) {
616276788Sdelphij				ND_PRINT((ndo, " ?)"));
617146773Ssam				break;
618146773Ssam			}
619214478Srpaulo			tp = (u_char *)(dh6o + 1);
620276788Sdelphij			ND_PRINT((ndo, " %d)", EXTRACT_32BITS(tp)));
621146773Ssam			break;
622190207Srpaulo		case DH6OPT_REMOTE_ID:
623190207Srpaulo			if (optlen < 4) {
624276788Sdelphij				ND_PRINT((ndo, " ?)"));
625190207Srpaulo				break;
626190207Srpaulo			}
627190207Srpaulo			tp = (u_char *)(dh6o + 1);
628276788Sdelphij			ND_PRINT((ndo, " %d ", EXTRACT_32BITS(tp)));
629190207Srpaulo			/*
630190207Srpaulo			 * Print hex dump first 10 characters.
631190207Srpaulo			 */
632190207Srpaulo			for (i = 4; i < optlen && i < 14; i++)
633276788Sdelphij				ND_PRINT((ndo, "%02x", tp[i]));
634276788Sdelphij			ND_PRINT((ndo, "...)"));
635190207Srpaulo			break;
636190207Srpaulo		case DH6OPT_LQ_QUERY:
637190207Srpaulo			if (optlen < 17) {
638276788Sdelphij				ND_PRINT((ndo, " ?)"));
639190207Srpaulo				break;
640190207Srpaulo			}
641190207Srpaulo			tp = (u_char *)(dh6o + 1);
642190207Srpaulo			switch (*tp) {
643190207Srpaulo			case 1:
644276788Sdelphij				ND_PRINT((ndo, " by-address"));
645190207Srpaulo				break;
646190207Srpaulo			case 2:
647276788Sdelphij				ND_PRINT((ndo, " by-clientID"));
648190207Srpaulo				break;
649190207Srpaulo			default:
650276788Sdelphij				ND_PRINT((ndo, " type_%d", (int)*tp));
651190207Srpaulo				break;
652190207Srpaulo			}
653276788Sdelphij			ND_PRINT((ndo, " %s", ip6addr_string(ndo, &tp[1])));
654190207Srpaulo			if (optlen > 17) {
655190207Srpaulo				/* there are query-options */
656276788Sdelphij				dhcp6opt_print(ndo, tp + 17, tp + optlen);
657190207Srpaulo			}
658276788Sdelphij			ND_PRINT((ndo, ")"));
659190207Srpaulo			break;
660190207Srpaulo		case DH6OPT_CLIENT_DATA:
661214478Srpaulo			tp = (u_char *)(dh6o + 1);
662190207Srpaulo			if (optlen > 0) {
663190207Srpaulo				/* there are encapsulated options */
664276788Sdelphij				dhcp6opt_print(ndo, tp, tp + optlen);
665190207Srpaulo			}
666276788Sdelphij			ND_PRINT((ndo, ")"));
667190207Srpaulo			break;
668190207Srpaulo		case DH6OPT_LQ_RELAY_DATA:
669190207Srpaulo			if (optlen < 16) {
670276788Sdelphij				ND_PRINT((ndo, " ?)"));
671190207Srpaulo				break;
672190207Srpaulo			}
673190207Srpaulo			tp = (u_char *)(dh6o + 1);
674276788Sdelphij			ND_PRINT((ndo, " %s ", ip6addr_string(ndo, &tp[0])));
675190207Srpaulo			/*
676190207Srpaulo			 * Print hex dump first 10 characters.
677190207Srpaulo			 */
678190207Srpaulo			for (i = 16; i < optlen && i < 26; i++)
679276788Sdelphij				ND_PRINT((ndo, "%02x", tp[i]));
680276788Sdelphij			ND_PRINT((ndo, "...)"));
681190207Srpaulo			break;
682276788Sdelphij		case DH6OPT_NTP_SERVER:
683276788Sdelphij			if (optlen < 4) {
684276788Sdelphij				ND_PRINT((ndo, " ?)"));
685276788Sdelphij				break;
686276788Sdelphij			}
687276788Sdelphij			tp = (u_char *)(dh6o + 1);
688276788Sdelphij			while (tp < cp + sizeof(*dh6o) + optlen - 4) {
689276788Sdelphij				subopt_code = EXTRACT_16BITS(tp);
690276788Sdelphij				tp += 2;
691276788Sdelphij				subopt_len = EXTRACT_16BITS(tp);
692276788Sdelphij				tp += 2;
693276788Sdelphij				if (tp + subopt_len > cp + sizeof(*dh6o) + optlen)
694276788Sdelphij					goto trunc;
695276788Sdelphij				ND_PRINT((ndo, " subopt:%d", subopt_code));
696276788Sdelphij				switch (subopt_code) {
697276788Sdelphij				case DH6OPT_NTP_SUBOPTION_SRV_ADDR:
698276788Sdelphij				case DH6OPT_NTP_SUBOPTION_MC_ADDR:
699276788Sdelphij					if (subopt_len != 16) {
700276788Sdelphij						ND_PRINT((ndo, " ?"));
701276788Sdelphij						break;
702276788Sdelphij					}
703276788Sdelphij					ND_PRINT((ndo, " %s", ip6addr_string(ndo, &tp[0])));
704276788Sdelphij					break;
705276788Sdelphij				case DH6OPT_NTP_SUBOPTION_SRV_FQDN:
706276788Sdelphij					ND_PRINT((ndo, " "));
707276788Sdelphij					if (ns_nprint(ndo, tp, tp + subopt_len) == NULL)
708276788Sdelphij						goto trunc;
709276788Sdelphij					break;
710276788Sdelphij				default:
711276788Sdelphij					ND_PRINT((ndo, " ?"));
712276788Sdelphij					break;
713276788Sdelphij				}
714276788Sdelphij				tp += subopt_len;
715276788Sdelphij			}
716276788Sdelphij			ND_PRINT((ndo, ")"));
717276788Sdelphij			break;
718251158Sdelphij		case DH6OPT_AFTR_NAME:
719251158Sdelphij			if (optlen < 3) {
720276788Sdelphij				ND_PRINT((ndo, " ?)"));
721251158Sdelphij				break;
722251158Sdelphij			}
723251158Sdelphij			tp = (u_char *)(dh6o + 1);
724276788Sdelphij			remain_len = optlen;
725276788Sdelphij			ND_PRINT((ndo, " "));
726251158Sdelphij			/* Encoding is described in section 3.1 of RFC 1035 */
727251158Sdelphij			while (remain_len && *tp) {
728251158Sdelphij				label_len =  *tp++;
729251158Sdelphij				if (label_len < remain_len - 1) {
730276788Sdelphij					ND_PRINT((ndo, "%.*s", label_len, tp));
731251158Sdelphij					tp += label_len;
732251158Sdelphij					remain_len -= (label_len + 1);
733276788Sdelphij					if(*tp) ND_PRINT((ndo, "."));
734251158Sdelphij				} else {
735276788Sdelphij					ND_PRINT((ndo, " ?"));
736251158Sdelphij					break;
737251158Sdelphij				}
738251158Sdelphij			}
739276788Sdelphij			ND_PRINT((ndo, ")"));
740251158Sdelphij			break;
74156893Sfenner		default:
742276788Sdelphij			ND_PRINT((ndo, ")"));
74356893Sfenner			break;
74456893Sfenner		}
74556893Sfenner
746111726Sfenner		cp += sizeof(*dh6o) + optlen;
74756893Sfenner	}
74856893Sfenner	return;
74956893Sfenner
75056893Sfennertrunc:
751276788Sdelphij	ND_PRINT((ndo, "[|dhcp6ext]"));
75256893Sfenner}
75356893Sfenner
75456893Sfenner/*
755111726Sfenner * Print dhcp6 packets
75656893Sfenner */
75756893Sfennervoid
758276788Sdelphijdhcp6_print(netdissect_options *ndo,
759276788Sdelphij            const u_char *cp, u_int length)
76056893Sfenner{
761111726Sfenner	struct dhcp6 *dh6;
762127668Sbms	struct dhcp6_relay *dh6relay;
763127668Sbms	const u_char *ep;
76456893Sfenner	u_char *extp;
765111726Sfenner	const char *name;
76656893Sfenner
767276788Sdelphij	ND_PRINT((ndo, "dhcp6"));
76856893Sfenner
769276788Sdelphij	ep = (u_char *)ndo->ndo_snapend;
770127668Sbms	if (cp + length < ep)
771127668Sbms		ep = cp + length;
77256893Sfenner
773111726Sfenner	dh6 = (struct dhcp6 *)cp;
774127668Sbms	dh6relay = (struct dhcp6_relay *)cp;
775276788Sdelphij	ND_TCHECK(dh6->dh6_xid);
776276788Sdelphij	name = tok2str(dh6_msgtype_str, "msgtype-%u", dh6->dh6_msgtype);
777111726Sfenner
778276788Sdelphij	if (!ndo->ndo_vflag) {
779276788Sdelphij		ND_PRINT((ndo, " %s", name));
780111726Sfenner		return;
781111726Sfenner	}
782111726Sfenner
783111726Sfenner	/* XXX relay agent messages have to be handled differently */
784111726Sfenner
785276788Sdelphij	ND_PRINT((ndo, " %s (", name));	/*)*/
786127668Sbms	if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
787127668Sbms	    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
788276788Sdelphij		ND_PRINT((ndo, "xid=%x", EXTRACT_32BITS(&dh6->dh6_xid) & DH6_XIDMASK));
789127668Sbms		extp = (u_char *)(dh6 + 1);
790276788Sdelphij		dhcp6opt_print(ndo, extp, ep);
791127668Sbms	} else {		/* relay messages */
792127668Sbms		struct in6_addr addr6;
793127668Sbms
794276788Sdelphij		ND_TCHECK(dh6relay->dh6relay_peeraddr);
795127668Sbms
796127668Sbms		memcpy(&addr6, dh6relay->dh6relay_linkaddr, sizeof (addr6));
797276788Sdelphij		ND_PRINT((ndo, "linkaddr=%s", ip6addr_string(ndo, &addr6)));
798127668Sbms
799127668Sbms		memcpy(&addr6, dh6relay->dh6relay_peeraddr, sizeof (addr6));
800276788Sdelphij		ND_PRINT((ndo, " peeraddr=%s", ip6addr_string(ndo, &addr6)));
801127668Sbms
802276788Sdelphij		dhcp6opt_print(ndo, (u_char *)(dh6relay + 1), ep);
803127668Sbms	}
804111726Sfenner	/*(*/
805276788Sdelphij	ND_PRINT((ndo, ")"));
80656893Sfenner	return;
80756893Sfenner
80856893Sfennertrunc:
809276788Sdelphij	ND_PRINT((ndo, "[|dhcp6]"));
81056893Sfenner}
811