Use ENC_NA as encoding for proto_tree_add_item() calls which directly reference an...
[obnox/wireshark/wip.git] / epan / dissectors / packet-dhcpv6.c
1 /* packet-dhpcv6.c
2  * Routines for DHCPv6 packet disassembly
3  * Copyright 2004, Nicolas DICHTEL - 6WIND - <nicolas.dichtel@6wind.com>
4  * Jun-ichiro itojun Hagino <itojun@iijlab.net>
5  * IItom Tsutomu MIENO <iitom@utouto.com>
6  * SHIRASAKI Yasuhiro <yasuhiro@gnome.gr.jp>
7  * Tony Lindstrom <tony.lindstrom@ericsson.com>
8  *
9  * $Id$
10  *
11  * The information used comes from:
12  * RFC3315.txt (DHCPv6)
13  * RFC3319.txt (SIP options)
14  * RFC3633.txt (Prefix options)
15  * RFC3646.txt (DNS servers/domains)
16  * RFC3898.txt (NIS options)
17  * RFC4704.txt (Client FQDN)
18  * RFC5007.txt (DHCPv6 Leasequery)
19  * RFC5417.txt (CAPWAP Access Controller DHCP Option)
20  * RFC6334.txt (Dual-Stack Lite Option)
21  * draft-ietf-dhc-dhcpv6-opt-timeconfig-03.txt
22  * draft-ietf-dhc-dhcpv6-opt-lifetime-00.txt
23  * CL-SP-CANN-DHCP-Reg-I06-110210.doc
24  *
25  * Note that protocol constants are still subject to change, based on IANA
26  * assignment decisions.
27  *
28  * Wireshark - Network traffic analyzer
29  * By Gerald Combs <gerald@wireshark.org>
30  * Copyright 1998 Gerald Combs
31  *
32  * This program is free software; you can redistribute it and/or
33  * modify it under the terms of the GNU General Public License
34  * as published by the Free Software Foundation; either version 2
35  * of the License, or (at your option) any later version.
36  *
37  * This program is distributed in the hope that it will be useful,
38  * but WITHOUT ANY WARRANTY; without even the implied warranty of
39  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
40  * GNU General Public License for more details.
41  *
42  * You should have received a copy of the GNU General Public License
43  * along with this program; if not, write to the Free Software
44  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
45  */
46
47 #ifdef HAVE_CONFIG_H
48 # include "config.h"
49 #endif
50
51 #include <glib.h>
52 #include <epan/packet.h>
53 #include <epan/sminmpec.h>
54 #include <epan/strutil.h>
55 #include <epan/arptypes.h>
56 #include "packet-arp.h"
57 #include "packet-dns.h"                         /* for get_dns_name() */
58
59 static int proto_dhcpv6 = -1;
60 static int hf_dhcpv6_msgtype = -1;
61 static int hf_clientfqdn_reserved = -1;
62 static int hf_clientfqdn_n = -1;
63 static int hf_clientfqdn_o = -1;
64 static int hf_clientfqdn_s = -1;
65 static int hf_option_type = -1;
66 static int hf_option_length = -1;
67 static int hf_option_value = -1;
68 static int hf_remoteid_enterprise = -1;
69 static int hf_vendoropts_enterprise = -1;
70 static int hf_duiden_enterprise = -1;
71 static int hf_vendorclass_enterprise = -1;
72 static int hf_dhcpv6_hopcount = -1;
73 static int hf_dhcpv6_xid = -1;
74 static int hf_dhcpv6_peeraddr = -1;
75 static int hf_dhcpv6_linkaddr = -1;
76
77 static gint ett_dhcpv6 = -1;
78 static gint ett_dhcpv6_option = -1;
79 static gint ett_dhcpv6_option_vsoption = -1;
80 static gint ett_dhcpv6_vendor_option = -1;
81 static gint ett_dhcpv6_pkt_option = -1;
82
83 #define UDP_PORT_DHCPV6_DOWNSTREAM      546
84 #define UDP_PORT_DHCPV6_UPSTREAM        547
85
86 #define DHCPV6_LEASEDURATION_INFINITY   0xffffffff
87
88 #define SOLICIT                  1
89 #define ADVERTISE                2
90 #define REQUEST                  3
91 #define CONFIRM                  4
92 #define RENEW                    5
93 #define REBIND                   6
94 #define REPLY                    7
95 #define RELEASE                  8
96 #define DECLINE                  9
97 #define RECONFIGURE             10
98 #define INFORMATION_REQUEST     11
99 #define RELAY_FORW              12
100 #define RELAY_REPLY             13
101 #define LEASEQUERY              14
102 #define LEASEQUERY_REPLY        15
103
104 #define OPTION_CLIENTID          1
105 #define OPTION_SERVERID          2
106 #define OPTION_IA_NA             3
107 #define OPTION_IA_TA             4
108 #define OPTION_IAADDR            5
109 #define OPTION_ORO               6
110 #define OPTION_PREFERENCE        7
111 #define OPTION_ELAPSED_TIME      8
112 #define OPTION_RELAY_MSG         9
113 /* #define      OPTION_SERVER_MSG       10 */
114 #define OPTION_AUTH             11
115 #define OPTION_UNICAST          12
116 #define OPTION_STATUS_CODE      13
117 #define OPTION_RAPID_COMMIT     14
118 #define OPTION_USER_CLASS       15
119 #define OPTION_VENDOR_CLASS     16
120 #define OPTION_VENDOR_OPTS      17
121 #define OPTION_INTERFACE_ID     18
122 #define OPTION_RECONF_MSG       19
123 #define OPTION_RECONF_ACCEPT    20
124 #define OPTION_SIP_SERVER_D     21
125 #define OPTION_SIP_SERVER_A     22
126 #define OPTION_DNS_SERVERS      23
127 #define OPTION_DOMAIN_LIST      24
128 #define OPTION_IA_PD            25
129 #define OPTION_IAPREFIX         26
130 #define OPTION_NIS_SERVERS      27
131 #define OPTION_NISP_SERVERS     28
132 #define OPTION_NIS_DOMAIN_NAME  29
133 #define OPTION_NISP_DOMAIN_NAME 30
134 #define OPTION_SNTP_SERVERS     31
135 #define OPTION_LIFETIME         32
136 #define OPTION_BCMCS_SERVER_D   33
137 #define OPTION_BCMCS_SERVER_A   34
138 #define OPTION_GEOCONF_CIVIC    36
139 #define OPTION_REMOTE_ID        37
140 #define OPTION_SUBSCRIBER_ID    38
141 #define OPTION_CLIENT_FQDN      39
142 #define OPTION_PANA_AGENT       40
143 #define OPTION_TIME_ZONE        41
144 #define OPTION_TZDB             42
145 #define OPTION_ERO              43
146 #define OPTION_LQ_QUERY         44
147 #define OPTION_CLIENT_DATA      45
148 #define OPTION_CLT_TIME         46
149 #define OPTION_LQ_RELAY_DATA    47
150 #define OPTION_LQ_CLIENT_LINK   48
151 #define OPTION_CAPWAP_AC_V6     52
152 #define OPTION_AFTR_NAME        64
153
154 /* temporary value until defined by IETF */
155 #define OPTION_MIP6_HA          165
156 #define OPTION_MIP6_HOA         166
157 #define OPTION_NAI              167
158
159 #define DUID_LLT                1
160 #define DUID_EN                 2
161 #define DUID_LL                 3
162 #define DUID_LL_OLD             4
163
164 static const value_string msgtype_vals[] = {
165     { SOLICIT,                 "Solicit" },
166     { ADVERTISE,               "Advertise" },
167     { REQUEST,                 "Request" },
168     { CONFIRM,                 "Confirm" },
169     { RENEW,                   "Renew" },
170     { REBIND,                  "Rebind" },
171     { REPLY,                   "Reply" },
172     { RELEASE,                 "Release" },
173     { DECLINE,                 "Decline" },
174     { RECONFIGURE,             "Reconfigure" },
175     { INFORMATION_REQUEST,     "Information-request" },
176     { RELAY_FORW,              "Relay-forw" },
177     { RELAY_REPLY,             "Relay-reply" },
178     { LEASEQUERY,              "Leasequery" },
179     { LEASEQUERY_REPLY,        "Leasequery-reply" },
180     { 0, NULL }
181 };
182
183 static const value_string opttype_vals[] = {
184     { OPTION_CLIENTID,         "Client Identifier" },
185     { OPTION_SERVERID,         "Server Identifier" },
186     { OPTION_IA_NA,            "Identity Association for Non-temporary Address" },
187     { OPTION_IA_TA,            "Identity Association for Temporary Address" },
188     { OPTION_IAADDR,           "IA Address" },
189     { OPTION_ORO,              "Option Request" },
190     { OPTION_PREFERENCE,       "Preference" },
191     { OPTION_ELAPSED_TIME,     "Elapsed time" },
192     { OPTION_RELAY_MSG,        "Relay Message" },
193 /*  { OPTION_SERVER_MSG,       "Server message" }, */
194     { OPTION_AUTH,             "Authentication" },
195     { OPTION_UNICAST,          "Server unicast" },
196     { OPTION_STATUS_CODE,      "Status code" },
197     { OPTION_RAPID_COMMIT,     "Rapid Commit" },
198     { OPTION_USER_CLASS,       "User Class" },
199     { OPTION_VENDOR_CLASS,     "Vendor Class" },
200     { OPTION_VENDOR_OPTS,      "Vendor-specific Information" },
201     { OPTION_INTERFACE_ID,     "Interface-Id" },
202     { OPTION_RECONF_MSG,       "Reconfigure Message" },
203     { OPTION_RECONF_ACCEPT,    "Reconfigure Accept" },
204     { OPTION_SIP_SERVER_D,     "SIP Server Domain Name List" },
205     { OPTION_SIP_SERVER_A,     "SIP Servers IPv6 Address List" },
206     { OPTION_DNS_SERVERS,      "DNS recursive name server" },
207     { OPTION_DOMAIN_LIST,      "Domain Search List" },
208     { OPTION_IA_PD,            "Identity Association for Prefix Delegation" },
209     { OPTION_IAPREFIX,         "IA Prefix" },
210     { OPTION_NIS_SERVERS,      "Network Information Server" },
211     { OPTION_NISP_SERVERS,     "Network Information Server V2" },
212     { OPTION_NIS_DOMAIN_NAME,  "Network Information Server Domain Name" },
213     { OPTION_NISP_DOMAIN_NAME, "Network Information Server V2 Domain Name" },
214     { OPTION_SNTP_SERVERS,     "Simple Network Time Protocol Server" },
215     { OPTION_LIFETIME,         "Lifetime" },
216     { OPTION_BCMCS_SERVER_D,   "BCMCS Server Domain" },
217     { OPTION_BCMCS_SERVER_A,   "BCMCS Servers IPv6 Address List" },
218     { OPTION_GEOCONF_CIVIC,    "Geoconf Civic Address" },
219     { OPTION_REMOTE_ID,        "Remote Identifier" },
220     { OPTION_SUBSCRIBER_ID,    "Subscriber Identifier" },
221     { OPTION_CLIENT_FQDN,      "Fully Qualified Domain Name" },
222     { OPTION_PANA_AGENT,       "PANA Agents IPv6 Address List" },
223     { OPTION_TIME_ZONE,        "Time Zone" },
224     { OPTION_TZDB,             "Time Zone Database" },
225     { OPTION_ERO,              "Echo Request Option" },
226     { OPTION_LQ_QUERY,         "Leasequery Query" },
227     { OPTION_CLIENT_DATA,      "Leasequery Client Data" },
228     { OPTION_CLT_TIME,         "Client Last Transaction Time" },
229     { OPTION_LQ_RELAY_DATA,    "Leasequery Relay Data" },
230     { OPTION_LQ_CLIENT_LINK,   "Leasequery Client Link Address List" },
231     { OPTION_CAPWAP_AC_V6,     "CAPWAP Access Controllers" },
232     { OPTION_AFTR_NAME,        "Dual-Stack Lite AFTR Name" },
233     { OPTION_MIP6_HA,          "Mobile IPv6 Home Agent" },
234     { OPTION_MIP6_HOA,         "Mobile IPv6 Home Address" },
235     { OPTION_NAI,              "Network Access Identifier" },
236     { 0,        NULL }
237 };
238
239 static const value_string statuscode_vals[] =
240 {
241     {0, "Success" },
242     {1, "UnspecFail" },
243     {2, "NoAddrAvail" },
244     {3, "NoBinding" },
245     {4, "NotOnLink" },
246     {5, "UseMulticast" },
247     {6, "NoPrefixAvail" },
248     {7, "UnknownQueryType" },
249     {8, "MalformedQuery" },
250     {9, "NotConfigured" },
251     {10, "NotAllowed" },
252     {0, NULL }
253 };
254
255 static const value_string duidtype_vals[] =
256 {
257     { DUID_LLT,    "link-layer address plus time" },
258     { DUID_EN,     "assigned by vendor based on Enterprise number" },
259     { DUID_LL,     "link-layer address" },
260     { DUID_LL_OLD, "link-layer address (old)" },
261     { 0, NULL }
262 };
263
264 static const true_false_string fqdn_n = {
265   "Server should not perform DNS updates",
266   "Server should perform DNS updates"
267 };
268
269 static const true_false_string fqdn_o = {
270   "Server has overridden client's S bit preference",
271   "Server has not overridden client's S bit preference"
272 };
273
274 static const true_false_string fqdn_s = {
275   "Server should perform forward DNS updates",
276   "Server should not perform forward DNS updates"
277 };
278
279 /* CableLabs Common Vendor Specific Options */
280 #define CL_OPTION_ORO                     0x0001 /* 1 */
281 #define CL_OPTION_DEVICE_TYPE             0x0002 /* 2 */
282 #define CL_OPTION_EMBEDDED_COMPONENT_LIST 0x0003 /* 3 */
283 #define CL_OPTION_DEVICE_SERIAL_NUMBER    0x0004 /* 4 */
284 #define CL_OPTION_HARDWARE_VERSION_NUMBER 0x0005 /* 5 */
285 #define CL_OPTION_SOFTWARE_VERSION_NUMBER 0x0006 /* 6 */
286 #define CL_OPTION_BOOT_ROM_VERSION        0x0007 /* 7 */
287 #define CL_OPTION_VENDOR_OUI              0x0008 /* 8 */
288 #define CL_OPTION_MODEL_NUMBER            0x0009 /* 9 */
289 #define CL_OPTION_VENDOR_NAME             0x000a /* 10 */
290 /* 11-32 is currently reserved */
291 #define CL_OPTION_TFTP_SERVERS            0x0020 /* 32 */
292 #define CL_OPTION_CONFIG_FILE_NAME        0x0021 /* 33 */
293 #define CL_OPTION_SYSLOG_SERVERS          0x0022 /* 34 */
294 #define CL_OPTION_TLV5                    0x0023 /* 35 */
295 #define CL_OPTION_DEVICE_ID               0x0024 /* 36 */
296 #define CL_OPTION_RFC868_SERVERS          0x0025 /* 37 */
297 #define CL_OPTION_TIME_OFFSET             0x0026 /* 38 */
298 #define CL_OPTION_IP_PREF                 0x0027 /* 39 */
299
300 /** CableLabs DOCSIS Project Vendor Specific Options */
301 #define CL_OPTION_DOCS_CMTS_CAP 0x0401  /* 1025 */
302 #define CL_CM_MAC_ADDR 0x0402 /* 1026 */
303 #define CL_EROUTER_CONTAINER_OPTION 0x403 /* 1027 */
304
305 /** CableLabs PacketCable Project Vendor Specific Options **/
306 #define CL_OPTION_CCC 0x087a  /* 2170 */
307 #define CL_OPTION_CCCV6 0x087b  /* 2171 */
308 #define CL_OPTION_CORRELATION_ID 0x087c /*2172 */
309
310 /** CableLabs TLVs for DOCS_CMTS_CAP Vendor Option **/
311 #define CL_OPTION_DOCS_CMTS_TLV_VERS_NUM 0x01 /* 1 */
312
313 static const value_string cl_vendor_subopt_values[] = {
314     /*    1 */ { CL_OPTION_ORO, "Option Request = " },
315     /*    2 */ { CL_OPTION_DEVICE_TYPE, "Device Type = " },
316     /*    3 */ { CL_OPTION_EMBEDDED_COMPONENT_LIST, "Embedded Components = " },
317     /*    4 */ { CL_OPTION_DEVICE_SERIAL_NUMBER, "Serial Number = " },
318     /*    5 */ { CL_OPTION_HARDWARE_VERSION_NUMBER, "Hardware Version = " },
319     /*    6 */ { CL_OPTION_SOFTWARE_VERSION_NUMBER, "Software Version = " },
320     /*    7 */ { CL_OPTION_BOOT_ROM_VERSION, "Boot ROM Version = " },
321     /*    8 */ { CL_OPTION_VENDOR_OUI, "Organization Unique Identifier = " },
322     /*    9 */ { CL_OPTION_MODEL_NUMBER, "Model Number = " },
323     /*   10 */ { CL_OPTION_VENDOR_NAME, "Vendor Name = " },
324     /*   32 */ { CL_OPTION_TFTP_SERVERS, "TFTP Server Addresses : " },
325     /*   33 */ { CL_OPTION_CONFIG_FILE_NAME, "Configuration File Name = " },
326     /*   34 */ { CL_OPTION_SYSLOG_SERVERS, "Syslog Servers : " },
327     /*   35 */ { CL_OPTION_TLV5, "TLV5 = " },
328     /*   36 */ { CL_OPTION_DEVICE_ID, "Device Identifier = " },
329     /*   37 */ { CL_OPTION_RFC868_SERVERS, "Time Protocol Servers : " },
330     /*   38 */ { CL_OPTION_TIME_OFFSET, "Time Offset = " },
331     /*   39 */ { CL_OPTION_IP_PREF, "IP preference : " },
332     /* 1025 */ { CL_OPTION_DOCS_CMTS_CAP, "CMTS Capabilities Option : " },
333     /* 1026 */ { CL_CM_MAC_ADDR, "CM MAC Address Option = " },
334     /* 1027 */ { CL_EROUTER_CONTAINER_OPTION, "eRouter Container Option : " },
335     /* 2170 */ { CL_OPTION_CCC, "CableLabs Client Configuration : " },
336     /* 2171 */ { CL_OPTION_CCCV6, "CableLabs Client Configuration IPv6 : " },
337     /* 2172 */ { CL_OPTION_CORRELATION_ID, "CableLabs Correlation ID = " },
338     { 0, NULL }
339 };
340
341 #define PKT_CCC_PRI_DHCP       0x0001
342 #define PKT_CCC_SEC_DHCP       0x0002
343 #define PKT_CCC_IETF_PROV_SRV  0x0003
344 #define PKT_CCC_IETF_AS_KRB    0x0004
345 #define PKT_CCC_IETF_AP_KRB    0x0005
346 #define PKT_CCC_KRB_REALM      0x0006
347 #define PKT_CCC_TGT_FLAG       0x0007
348 #define PKT_CCC_PROV_TIMER     0x0008
349 #define PKT_CCC_IETF_SEC_TKT   0x0009
350 /** 10 -255 Reserved for future extensions **/
351
352 #define PKT_CCCV6_PRI_DSS       0x0001
353 #define PKT_CCCV6_SEC_DSS       0x0002
354 #define PKT_CCCV6_IETF_PROV_SRV 0x0003
355 #define PKT_CCCV6_IETF_AS_KRB   0x0004
356 #define PKT_CCCV6_IETF_AP_KRB   0x0005
357 #define PKT_CCCV6_KRB_REALM     0x0006
358 #define PKT_CCCV6_TGT_FLAG      0x0007
359 #define PKT_CCCV6_PROV_TIMER    0x0008
360 #define PKT_CCCV6_IETF_SEC_TKT  0x0009
361 /** 10 -255 Reserved for future extensions **/
362
363 static const value_string pkt_ccc_opt_vals[] = {
364     { PKT_CCC_PRI_DHCP,      "TSP's Primary DHCP Server" },
365     { PKT_CCC_SEC_DHCP,      "TSP's Secondary DHCP Server" },
366     { PKT_CCC_IETF_PROV_SRV, "TSP's Provisioning Server" },
367     { PKT_CCC_IETF_AS_KRB,   "TSP's AS-REQ/AS-REP Backoff and Retry" },
368     { PKT_CCC_IETF_AP_KRB,   "TSP's AP-REQ/AP-REP Backoff and Retry" },
369     { PKT_CCC_KRB_REALM,     "TSP's Kerberos Realm Name" },
370     { PKT_CCC_TGT_FLAG,      "TSP's Ticket Granting Server Utilization" },
371     { PKT_CCC_PROV_TIMER,    "TSP's Provisioning Timer Value" },
372     { PKT_CCC_IETF_SEC_TKT,  "PacketCable Security Ticket Control" },
373     { 0, NULL },
374 };
375
376 static const value_string pkt_cccV6_opt_vals[] = {
377     { PKT_CCCV6_PRI_DSS,        "TSP's Primary DHCPv6 Server Selector ID" },
378     { PKT_CCCV6_SEC_DSS,        "TSP's Secondary DHCPv6 Server Selector ID " },
379     { PKT_CCCV6_IETF_PROV_SRV,  "TSP's Provisioning Server" },
380     { PKT_CCCV6_IETF_AS_KRB,    "TSP's AS-REQ/AS-REP Backoff and Retry" },
381     { PKT_CCCV6_IETF_AP_KRB,    "TSP's AP-REQ/AP-REP Backoff and Retry" },
382     { PKT_CCCV6_KRB_REALM,      "TSP's Kerberos Realm Name" },
383     { PKT_CCCV6_TGT_FLAG,       "TSP's Ticket Granting Server Utilization" },
384     { PKT_CCCV6_PROV_TIMER,     "TSP's Provisioning Timer Value" },
385     { PKT_CCCV6_IETF_SEC_TKT,   "PacketCable Security Ticket Control" },
386     { 0, NULL }
387 };
388
389 static const value_string sec_tcm_vals[] = {
390     { 1 << 0, "PacketCable Provisioning Server" },
391     { 1 << 1, "PacketCable Call Manager Servers" },
392     { 0, NULL },
393 };
394
395 /* May be called recursively */
396 static void
397 dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
398                gboolean downstream, int off, int eoff);
399
400 static int
401 dissect_packetcable_ccc_option(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
402                                int optend)
403 {
404     /** THE ENCODING OF THIS SUBOPTION HAS CHANGED FROM DHCPv4
405         the code and length fields have grown from a single octet to
406         two octets each. **/
407     int suboptoff = optoff;
408     guint16 subopt, subopt_len, sec_tcm;
409     guint8 fetch_tgt, timer_val, type;
410     proto_item *vti;
411     proto_tree *pkt_s_tree;
412     guint32 ipv4_address;
413     guchar kr_name;       /** A character in the kerberos realm name option */
414     guint8 kr_value;      /* The integer value of the character currently being tested */
415     int kr_fail_flag = 0; /* Flag indicating an invalid character was found */
416     int kr_pos = 0;       /* The position of the first invalid character */
417     int i = 0;
418     char bit_fld[24];
419
420     subopt = tvb_get_ntohs(tvb, optoff);
421     suboptoff += 2;
422
423     subopt_len = tvb_get_ntohs(tvb, suboptoff);
424     suboptoff += 2;
425
426     /* There must be at least five octets left to be a valid sub element */
427     if (optend <= 0) {
428         proto_tree_add_text(v_tree, tvb, optoff, 1,
429                             "Sub element %d: no room left in option for suboption length",
430                             subopt);
431         return (optend);
432     }
433     /* g_print("dissect packetcable ccc option subopt_len=%d optend=%d\n\n", subopt_len, optend); */
434
435     vti = proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 4,
436                               "Sub element %u: %s: ", subopt,
437                               val_to_str(subopt, pkt_ccc_opt_vals, "unknown/reserved") );
438
439     switch (subopt) {
440     case PKT_CCC_PRI_DHCP:      /* IPv4 address values */
441     case PKT_CCC_SEC_DHCP:
442         if (subopt_len == 4) {
443             ipv4_address = tvb_get_ipv4(tvb, suboptoff);
444             proto_item_append_text(vti, "%s (%u byte%s%s)",
445                                    ip_to_str((guint8 *)&ipv4_address), subopt_len,
446                                    plurality(subopt_len, "", "s"),
447                                    subopt_len != 4 ? " [Invalid]" : "");
448         }
449         else {
450             proto_tree_add_text(vti, tvb, suboptoff, subopt_len,
451                                 "Bogus length: %d", subopt_len);
452
453         }
454
455         suboptoff += subopt_len;
456         break;
457     case PKT_CCC_IETF_PROV_SRV :
458         type = tvb_get_guint8(tvb, suboptoff);
459         /** Type 0 is FQDN **/
460         if (type == 0) {
461             proto_item_append_text(vti, "%s (%u byte%s)",
462                                    tvb_format_stringzpad(tvb, suboptoff+1, subopt_len-1),
463                                    subopt_len,
464                                    plurality(subopt_len-1, "", "s") );
465         }
466         /** Type 0 is IPv4 **/
467         else if (type == 1) {
468             if (subopt_len == 5) {
469                 ipv4_address = tvb_get_ipv4(tvb, suboptoff+1);
470                 proto_item_append_text(vti, "%s (%u byte%s%s)",
471                                        ip_to_str((guint8 *)&ipv4_address), subopt_len,
472                                        plurality(subopt_len, "", "s"),
473                                        subopt_len != 5 ? " [Invalid]" : "");
474             }
475             else {
476                 proto_item_append_text(vti, "Bogus length: %d", subopt_len);
477             }
478         }
479         else {
480             proto_item_append_text(vti, "Invalid type: %u (%u byte%s)",
481                                    type, subopt_len, plurality(subopt_len, "", "s"));
482         }
483         suboptoff += subopt_len;
484         break;
485
486     case PKT_CCC_IETF_AS_KRB :
487     case PKT_CCC_IETF_AP_KRB :
488         if (subopt_len == 12) {
489             pkt_s_tree = proto_item_add_subtree(vti, ett_dhcpv6_pkt_option);
490             proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
491                                 "Nominal Timeout : %u", tvb_get_ntohl(tvb, suboptoff));
492             proto_tree_add_text(pkt_s_tree, tvb, suboptoff+4, 4,
493                                 "Maximum Timeout : %u", tvb_get_ntohl(tvb, suboptoff+4));
494             proto_tree_add_text(pkt_s_tree, tvb, suboptoff+8, 4,
495                                 "Maximum Retry Count : %u", tvb_get_ntohl(tvb, suboptoff+8));
496
497         }
498         else {
499             proto_item_append_text(vti, "Bogus length: %d", subopt_len);
500         }
501         suboptoff += subopt_len;
502         break;
503     case PKT_CCC_KRB_REALM:
504         if (subopt_len > 0) {
505             /** The only allowable characters are
506                 A-Z (upper case only) 65-90
507                 '.', 46
508                 '/', 47
509                 '\', 92
510                 '=', 61
511                 '"', 34
512                 ',', 44
513                 and
514                 ':' 58
515                 so loop through and
516                 make sure it conforms to the expected syntax.
517             **/
518             for (i=0; i < subopt_len; i++) {
519                 kr_name = tvb_get_guint8(tvb, suboptoff + i);
520                 kr_value = (int)kr_name;
521                 if ((kr_value >= 65 && kr_value <= 90) ||
522                     kr_value == 34 ||
523                     kr_value == 44 ||
524                     kr_value == 46 ||
525                     kr_value == 47 ||
526                     kr_value == 58 ||
527                     kr_value == 61 ||
528                     kr_value == 92)   {
529                 }
530                 else if (!kr_fail_flag) {
531                     kr_pos = i;
532                     kr_fail_flag = 1;
533                 }
534                 proto_item_append_text(vti, "%c", kr_name);
535             }
536
537             if (kr_fail_flag) {
538                 proto_item_append_text(vti, " (%u byte%s [Invalid at byte=%d]) ",
539                                        subopt_len,
540                                        plurality(subopt_len, "", "s"),
541                                        kr_pos);
542             }
543             else {
544                 proto_item_append_text(vti, " (%u byte%s%s) ",
545                                        subopt_len,
546                                        plurality(subopt_len, "", "s"),
547                                        kr_fail_flag != 0 ? " [Invalid]" : "");
548             }
549         }
550         suboptoff += subopt_len;
551         break;
552
553     case PKT_CCC_TGT_FLAG:
554         fetch_tgt = tvb_get_guint8(tvb, suboptoff);
555         proto_item_append_text(vti, "%s (%u byte%s%s)",
556                                fetch_tgt == 1 ? "True" : "False",
557                                subopt_len,
558                                plurality(subopt_len, "", "s"),
559                                subopt_len != 1 ? " [Invalid]" : "");
560         suboptoff += subopt_len;
561         break;
562
563     case PKT_CCC_PROV_TIMER:
564         timer_val = tvb_get_guint8(tvb, suboptoff);
565         /* proto_item_append_text(vti, "%u%s (%u byte%s%s)", timer_val,
566            timer_val > 30 ? " [Invalid]" : "", */
567         proto_item_append_text(vti, "%u (%u byte%s%s)", timer_val,
568                                subopt_len,
569                                plurality(subopt_len, "", "s"),
570                                subopt_len != 1 ? " [Invalid]" : "");
571         suboptoff += subopt_len;
572         break;
573
574     case PKT_CCC_IETF_SEC_TKT :
575         sec_tcm = tvb_get_ntohs(tvb, suboptoff);
576         proto_item_append_text(vti, "0x%04x (%u byte%s%s)",
577                                sec_tcm, subopt_len, plurality(subopt_len, "", "s"),
578                                subopt_len != 2 ? " [Invalid]" : "");
579
580         if (subopt_len == 2) {
581             pkt_s_tree = proto_item_add_subtree(vti, ett_dhcpv6_pkt_option);
582             for (i=0; i< 2; i++) {
583                 if (sec_tcm & sec_tcm_vals[i].value) {
584                     decode_bitfield_value(bit_fld, sec_tcm, sec_tcm_vals[i].value, 16);
585                     proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 2, "%s %s",
586                                         bit_fld, sec_tcm_vals[i].strptr);
587                 }
588             }
589         }
590         suboptoff += subopt_len;
591         break;
592
593
594     default:
595         suboptoff += subopt_len;
596         break;
597
598     }
599
600     /** Return the number of bytes processed **/
601     return (suboptoff - optoff);
602 }
603
604 static int
605 dissect_packetcable_cccV6_option(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
606     int optend)
607 {
608     int suboptoff = optoff;
609     guint16 subopt, subopt_len, sec_tcm;
610     guint8 fetch_tgt, timer_val, type;
611     proto_item *vti;
612     proto_tree *pkt_s_tree;
613     guchar kr_name;         /* A character in the kerberos realm name option */
614     guint8 kr_value;        /* The integer value of the character currently being tested */
615     int kr_fail_flag = 0;   /* Flag indicating an invalid character was found */
616     int kr_pos = 0;         /* The position of the first invalid character */
617     int i = 0;
618     char bit_fld[24];
619     struct e_in6_addr in6;
620
621     subopt = tvb_get_ntohs(tvb, optoff);
622     suboptoff += 2;
623
624     subopt_len = tvb_get_ntohs(tvb, suboptoff);
625     suboptoff += 2;
626
627     /* There must be at least five octets left to be a valid sub element */
628     if (optend <= 0) {
629         proto_tree_add_text(v_tree, tvb, optoff, 1,
630             "Sub element %d: no room left in option for suboption length",
631             subopt);
632         return (optend);
633     }
634
635     vti = proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 4,
636         "Sub element %u: %s: ", subopt,
637         val_to_str(subopt, pkt_cccV6_opt_vals, "unknown/reserved") );
638
639     switch (subopt) {
640         case PKT_CCCV6_PRI_DSS:
641         case PKT_CCCV6_SEC_DSS:
642             if (subopt_len < 35) {
643                 proto_item_append_text(vti, "%s (%u byte%s)",
644                     tvb_format_stringzpad(tvb, suboptoff, subopt_len),
645                     subopt_len,
646                     plurality(subopt_len-1, "", "s") );
647             } else {
648                 proto_item_append_text(vti, "Bogus length: %d", subopt_len);
649             }
650             suboptoff += subopt_len;
651             break;
652
653         case PKT_CCCV6_IETF_PROV_SRV:
654             type = tvb_get_guint8(tvb, suboptoff);
655             /** Type 0 is FQDN **/
656             if (type == 0) {
657                 proto_item_append_text(vti, "%s (%u byte%s)",
658                     tvb_format_stringzpad(tvb, suboptoff+1, subopt_len-1),
659                     subopt_len,
660                     plurality(subopt_len-1, "", "s") );
661             /** Type 1 is IPv6 **/
662             } else if (type == 1) {
663                 if ((subopt_len % 16) == 0) {
664                     for (i = 0; i < subopt_len/16; i++) {
665                         tvb_get_ipv6(tvb, suboptoff, &in6);
666                         proto_item_append_text(vti, "IPv6 address %d: %s",
667                             i+1, ip6_to_str(&in6));
668                         suboptoff += 16;
669                     }
670                 }
671             } else {
672                 proto_item_append_text(vti, "Invalid type: %u (%u byte%s)",
673                     type, subopt_len, plurality(subopt_len, "", "s"));
674             }
675             suboptoff += subopt_len;
676             break;
677
678         case PKT_CCCV6_IETF_AS_KRB:
679         case PKT_CCCV6_IETF_AP_KRB:
680             if (subopt_len == 12) {
681                 pkt_s_tree = proto_item_add_subtree(vti, ett_dhcpv6_pkt_option);
682                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
683                     "Nominal Timeout : %u", tvb_get_ntohl(tvb, suboptoff));
684                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff+4, 4,
685                     "Maximum Timeout : %u", tvb_get_ntohl(tvb, suboptoff+4));
686                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff+8, 4,
687                     "Maximum Retry Count : %u", tvb_get_ntohl(tvb, suboptoff+8));
688             } else {
689                 proto_item_append_text(vti, "Bogus length: %d", subopt_len);
690             }
691             suboptoff += subopt_len;
692             break;
693
694         case PKT_CCCV6_KRB_REALM:
695             if (subopt_len > 0) {
696                 for (i=0; i < subopt_len; i++) {
697                     kr_name = tvb_get_guint8(tvb, suboptoff + i);
698                     kr_value = (int)kr_name;
699                     if ((kr_value >= 65 && kr_value <= 90) ||
700                         kr_value == 34 ||
701                         kr_value == 44 ||
702                         kr_value == 46 ||
703                         kr_value == 47 ||
704                         kr_value == 58 ||
705                         kr_value == 61 ||
706                         kr_value == 92) {
707                     } else if (!kr_fail_flag) {
708                         kr_pos = i;
709                         kr_fail_flag = 1;
710                     }
711                     proto_item_append_text(vti, "%c", kr_name);
712                 }
713
714                 if (kr_fail_flag) {
715                     proto_item_append_text(vti, " (%u byte%s [Invalid at byte=%d]) ",
716                         subopt_len,
717                         plurality(subopt_len, "", "s"),
718                         kr_pos);
719                 } else {
720                     proto_item_append_text(vti, " (%u byte%s%s) ",
721                         subopt_len,
722                         plurality(subopt_len, "", "s"),
723                         kr_fail_flag != 0 ? " [Invalid]" : "");
724                 }
725             }
726             suboptoff += subopt_len;
727             break;
728
729         case PKT_CCCV6_TGT_FLAG:
730             fetch_tgt = tvb_get_guint8(tvb, suboptoff);
731             proto_item_append_text(vti, "%s (%u byte%s%s)",
732                 fetch_tgt == 1 ? "True" : "False",
733                 subopt_len,
734                 plurality(subopt_len, "", "s"),
735                 subopt_len != 1 ? " [Invalid]" : "");
736             suboptoff += subopt_len;
737             break;
738
739         case PKT_CCCV6_PROV_TIMER:
740             timer_val = tvb_get_guint8(tvb, suboptoff);
741             proto_item_append_text(vti, "%u (%u byte%s%s)", timer_val,
742                 subopt_len,
743                 plurality(subopt_len, "", "s"),
744             subopt_len != 1 ? " [Invalid]" : "");
745             suboptoff += subopt_len;
746             break;
747
748         case PKT_CCCV6_IETF_SEC_TKT:
749             sec_tcm = tvb_get_ntohs(tvb, suboptoff);
750             proto_item_append_text(vti, "0x%04x (%u byte%s%s)",
751                 sec_tcm, subopt_len, plurality(subopt_len, "", "s"),
752             subopt_len != 2 ? " [Invalid]" : "");
753
754             if (subopt_len == 2) {
755                 pkt_s_tree = proto_item_add_subtree(vti, ett_dhcpv6_pkt_option);
756                 for (i=0; i< 2; i++) {
757                     if (sec_tcm & sec_tcm_vals[i].value) {
758                         decode_bitfield_value(bit_fld, sec_tcm, sec_tcm_vals[i].value, 16);
759                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 2, "%s %s",
760                         bit_fld, sec_tcm_vals[i].strptr);
761                     }
762                 }
763             }
764
765             suboptoff += subopt_len;
766             break;
767
768         default:
769             suboptoff += subopt_len;
770             break;
771     }
772
773     /** Return the number of bytes processed **/
774     return (suboptoff - optoff);
775 }
776
777 static void
778 dissect_cablelabs_specific_opts(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len)
779 {
780     guint16 type;
781     guint16 tlv_len; /* holds the number of elements in the tlv */
782     guint16 opt_len; /* holds the length of the suboption */
783     guint16 sub_value;
784     int off = voff;
785     int sub_off; /** The offset for the sub-option */
786     proto_item *ti;
787     int i;
788     int field_len; /* holds the length of one occurrence of a field */
789     int field_value;
790     proto_tree *subtree;
791     struct e_in6_addr in6;
792
793     if (len > 4) {
794         while (off - voff < len) {
795
796             /* Type */
797             type = tvb_get_ntohs(tvb, off);
798             ti = proto_tree_add_text(v_tree, tvb, off, 2,
799                                      "Suboption %d: %s", type, val_to_str(type,
800                                                                           cl_vendor_subopt_values, "unknown"));
801             /* Length */
802             tlv_len = tvb_get_ntohs(tvb, off+2);
803
804             /* Values */
805             sub_off = off + 4;
806
807             switch(type) {
808                 /* String types */
809             case CL_OPTION_DEVICE_TYPE :
810             case CL_OPTION_DEVICE_SERIAL_NUMBER :
811             case CL_OPTION_HARDWARE_VERSION_NUMBER :
812             case CL_OPTION_SOFTWARE_VERSION_NUMBER :
813             case CL_OPTION_BOOT_ROM_VERSION :
814             case CL_OPTION_MODEL_NUMBER :
815             case CL_OPTION_VENDOR_NAME :
816             case CL_OPTION_CONFIG_FILE_NAME :
817             case CL_OPTION_EMBEDDED_COMPONENT_LIST :
818                 opt_len = tlv_len;
819                 field_len = tlv_len;
820                 proto_item_append_text(ti, "\"%s\"",
821                                        tvb_format_stringzpad(tvb, sub_off, field_len));
822                 break;
823
824             case CL_OPTION_VENDOR_OUI :
825                 /* CableLabs specs treat 17.8 inconsistently
826                  * as either binary (3b) or string (6b) */
827                 opt_len = tlv_len;
828                 if (tlv_len == 3) {
829                     proto_item_append_text(ti, "%s",
830                         tvb_bytes_to_str_punct(tvb, sub_off, 3, ':'));
831                 } else if (tlv_len == 6) {
832                     proto_item_append_text(ti, "\"%s\"", tvb_format_stringzpad(tvb, sub_off, tlv_len));
833                 } else {
834                     proto_item_append_text(ti, "Suboption %d: suboption length isn't 3 or 6", type);
835                 }
836                 break;
837
838             case CL_OPTION_ORO :
839                 field_len = 2;
840                 opt_len = tlv_len;
841                 if (opt_len > 0) {
842                     for (i = 0; i < tlv_len; i += field_len) {
843                         sub_value = tvb_get_ntohs(tvb, sub_off);
844                         proto_item_append_text(ti, " %d", sub_value);
845                         sub_off += field_len;
846                     }
847                 }
848                 break;
849
850                 /* List of IPv6 Address */
851             case CL_OPTION_TFTP_SERVERS :
852             case CL_OPTION_SYSLOG_SERVERS :
853             case CL_OPTION_RFC868_SERVERS :
854                 field_len = 16;
855                 opt_len = tlv_len;
856                 subtree = proto_item_add_subtree(ti, ett_dhcpv6_vendor_option);
857
858                 if ((tlv_len % field_len) == 0) {
859                     for (i = 0; i < tlv_len/field_len; i++) {
860                         tvb_get_ipv6(tvb, sub_off, &in6);
861                         proto_tree_add_text(subtree, tvb, sub_off,
862                                             sizeof(in6), "IPv6 address %d: %s",
863                                             i+1, ip6_to_str(&in6));
864                         sub_off += field_len;
865                     }
866                 }
867                 break;
868
869             case CL_OPTION_DEVICE_ID :
870                 opt_len = tlv_len;
871                 field_len = tlv_len;
872                 if (tlv_len != 6) {
873                     proto_item_append_text(ti, "Bogus value length=%d",
874                                            tlv_len);
875                 }
876                 else {
877                     proto_item_append_text(ti, "%s",
878                                            tvb_bytes_to_str(tvb, sub_off, field_len));
879                 }
880                 break;
881
882             case CL_OPTION_TLV5 :
883                 opt_len = tlv_len;
884                 field_len = tlv_len;
885                 proto_item_append_text(ti, "%s",
886                                        tvb_bytes_to_str(tvb, sub_off, field_len));
887                 break;
888
889             case CL_OPTION_TIME_OFFSET :
890                 opt_len = tlv_len;
891                 proto_item_append_text(ti, "%d", tvb_get_ntohl(tvb, sub_off));
892                 break;
893
894             case CL_OPTION_IP_PREF :
895                 opt_len = tlv_len;
896                 field_value = tvb_get_guint8(tvb, sub_off);
897                 if (field_value == 1) {
898                     proto_item_append_text(ti, "%s", "IPv4");
899                 } else if (field_value == 2) {
900                     proto_item_append_text(ti, "%s", "IPv6");
901                 } else {
902                     proto_item_append_text(ti, "%s", "Unknown");
903                 }
904                 break;
905
906             case CL_OPTION_DOCS_CMTS_CAP :
907                 opt_len = tlv_len;
908                 field_len = 0;
909                 subtree = proto_item_add_subtree(ti, ett_dhcpv6_vendor_option);
910
911                 /* tlv_len contains the total length of all the TLVs for this
912                    option */
913                 if (tlv_len > 0) {
914                     for (i = 0; field_len < opt_len; i++) {
915                         int tagLen = 0;
916                         int tag = 0;
917                         tag = tvb_get_guint8(tvb, sub_off);
918                         sub_off++;
919                         tagLen = tvb_get_guint8(tvb, sub_off);
920                         sub_off++;
921                         if (tag == CL_OPTION_DOCS_CMTS_TLV_VERS_NUM &&
922                             tagLen == 2) {
923                             int major = 0;
924                             int minor = 0;
925                             major = tvb_get_guint8(tvb, sub_off);
926                             sub_off++;
927                             minor = tvb_get_guint8(tvb, sub_off);
928                             sub_off++;
929                             proto_tree_add_text(subtree, tvb, sub_off-2,
930                                 2, "DOCSIS Version Number %d.%d",
931                                                 major, minor);
932                         }
933                         else
934                             sub_off += tagLen;
935
936                         field_len += tagLen + 2;
937                     }
938                 }
939                 else
940                     proto_tree_add_text(subtree, tvb, sub_off, 0, "empty");
941                 break;
942
943             case CL_CM_MAC_ADDR :
944                 opt_len = tlv_len;
945                 field_len = tlv_len;
946                 if (tlv_len != 6) {
947                     proto_item_append_text(ti, "Bogus value length=%d",
948                                            tlv_len);
949                 }
950                 else {
951                     /*proto_item_append_text(ti, "CM MAC Address Option = %s", */
952                     proto_item_append_text(ti, "%s", tvb_bytes_to_str_punct(tvb, sub_off, opt_len, ':'));
953                     /* tvb_bytes_to_str(tvb, sub_off, opt_len)); */
954                 }
955                 sub_off += field_len;
956                 break;
957
958             case CL_EROUTER_CONTAINER_OPTION :
959                 opt_len = tlv_len;
960                 field_len = tlv_len;
961                 proto_item_append_text(ti, " %s (len=%d)",
962                                        tvb_bytes_to_str(tvb, sub_off, opt_len), tlv_len);
963                 sub_off += field_len;
964                 break;
965
966             case CL_OPTION_CCC :
967                 opt_len = tlv_len;
968                 field_len = 0;
969                 subtree = proto_item_add_subtree(ti, ett_dhcpv6_vendor_option);
970                 proto_item_append_text(ti, " (%d bytes)", opt_len);
971                 while (field_len < opt_len) {
972                     sub_value = dissect_packetcable_ccc_option(subtree, tvb,
973                                                                sub_off, (opt_len - field_len));
974                     sub_off += sub_value;
975                     field_len += sub_value;
976                 }
977                 sub_off += field_len;
978                 break;
979
980             case CL_OPTION_CCCV6 :
981                 opt_len = tlv_len;
982                 field_len = 0;
983                 subtree = proto_item_add_subtree(ti, ett_dhcpv6_vendor_option);
984                 proto_item_append_text(ti, " (%d bytes)", opt_len);
985                 while (field_len < opt_len) {
986                     sub_value = dissect_packetcable_cccV6_option(subtree, tvb,
987                         sub_off, (opt_len - field_len));
988                     sub_off += sub_value;
989                     field_len += sub_value;
990                 }
991                 sub_off += field_len;
992                 break;
993
994             case CL_OPTION_CORRELATION_ID :
995                 opt_len = tlv_len;
996                  if (tlv_len != 4) {
997                     proto_item_append_text(ti, "Bogus value length=%d",
998                                            tlv_len);
999                 }
1000                 else {
1001                     proto_item_append_text(ti, "%d", tvb_get_ntohl(tvb, sub_off));
1002                 }
1003                 break;
1004
1005             default:
1006                 opt_len = tlv_len;
1007                 break;
1008             }
1009             off += (opt_len + 4);
1010
1011         }
1012     }
1013     else {
1014         proto_tree_add_text(v_tree, tvb, off, len-off,
1015                             "Bogus length: %d", len);
1016     }
1017 }
1018
1019 /* Adds domain */
1020 static void
1021 dhcpv6_domain(proto_tree * subtree, tvbuff_t *tvb, int offset, guint16 optlen)
1022 {
1023     int start_offset=offset;
1024     char domain[256];
1025     int pos;
1026     guint8 len;
1027
1028     pos=0;
1029     while(optlen){
1030         /* this is the start of the domain name */
1031         if(!pos){
1032             start_offset=offset;
1033         }
1034         domain[pos]=0;
1035
1036         /* read length of the next substring */
1037         len = tvb_get_guint8(tvb, offset);
1038         /* Microsoft dhcpv6 clients aren't currently RFC 4704 conform: They send an
1039          * ASCII string instead of a DNS record encoded domain name. Catch that case
1040          * to allow us to continue after such a malformed record.
1041          */
1042         if ( optlen < len ) {
1043             proto_tree_add_text(subtree, tvb, start_offset, optlen, "Malformed DNS name record (MS Vista client?)");
1044             return;
1045         }
1046         offset++;
1047         optlen--;
1048         /* if len==0 and pos>0 we have read an entire domain string */
1049         if(!len){
1050             if(!pos){
1051                 /* empty string, this must be an error? */
1052                 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Malformed option");
1053                 return;
1054             } else {
1055                 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Domain: %s", domain);
1056                 pos=0;
1057                 continue;
1058             }
1059         }
1060
1061         /* add the substring to domain */
1062         if(pos){
1063             domain[pos]='.';
1064             pos++;
1065         }
1066         if(pos+len>254){
1067             /* too long string, this must be an error? */
1068             proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Malformed option");
1069             return;
1070         }
1071         tvb_memcpy(tvb, domain+pos, offset, len);
1072         pos+=len;
1073         offset+=len;
1074         optlen-=len;
1075     }
1076
1077     if(pos){
1078         domain[pos]=0;
1079         proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Domain: %s", domain);
1080     }
1081 }
1082
1083 /* Returns the number of bytes consumed by this option. */
1084 static int
1085 dhcpv6_option(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bp_tree,
1086               gboolean downstream, int off, int eoff, gboolean *at_end)
1087 {
1088     guint8 *buf;
1089     guint16     opttype;
1090     guint16     optlen;
1091     guint16     hwtype;
1092     guint16     temp_optlen = 0;
1093     proto_item *ti;
1094     proto_tree *subtree;
1095     proto_tree *subtree_2;
1096     int i;
1097     struct e_in6_addr in6;
1098     guint16 duidtype;
1099     guint32 enterprise_no;
1100
1101     /* option type and length must be present */
1102     if (eoff - off < 4) {
1103         *at_end = TRUE;
1104         return 0;
1105     }
1106
1107     opttype = tvb_get_ntohs(tvb, off);
1108     optlen = tvb_get_ntohs(tvb, off + 2);
1109
1110     /* all option data must be present */
1111     if (eoff - off < 4 + optlen) {
1112         *at_end = TRUE;
1113         return 0;
1114     }
1115
1116     ti = proto_tree_add_text(bp_tree, tvb, off, 4 + optlen,
1117                              "%s", val_to_str(opttype, opttype_vals, "DHCP option %u"));
1118
1119     subtree = proto_item_add_subtree(ti, ett_dhcpv6_option);
1120     proto_tree_add_item(subtree, hf_option_type, tvb, off, 2, FALSE);
1121     proto_tree_add_item(subtree, hf_option_length, tvb, off + 2, 2, FALSE);
1122     off += 4;
1123     /* Right now, none of the options can be filtered at, so provide a hex
1124        array for minimalistic filtering */
1125     if (optlen)
1126         proto_tree_add_item(subtree, hf_option_value, tvb, off, optlen, ENC_NA);
1127
1128     switch (opttype) {
1129     case OPTION_CLIENTID:
1130         col_append_fstr(pinfo->cinfo, COL_INFO, "CID: %s ", tvb_bytes_to_str(tvb, off, optlen));
1131         /* Fall through */
1132     case OPTION_SERVERID:
1133         if (optlen < 2) {
1134             proto_tree_add_text(subtree, tvb, off, optlen,
1135                                 "DUID: malformed option");
1136             break;
1137         }
1138         proto_item_append_text(ti, ": %s", tvb_bytes_to_str(tvb, off, optlen));
1139         duidtype = tvb_get_ntohs(tvb, off);
1140         proto_tree_add_text(subtree, tvb, off, 2,
1141                             "DUID type: %s (%u)",
1142                             val_to_str(duidtype,
1143                                        duidtype_vals, "Unknown"),
1144                             duidtype);
1145         switch (duidtype) {
1146         case DUID_LLT:
1147             if (optlen < 8) {
1148                 proto_tree_add_text(subtree, tvb, off,
1149                                     optlen, "DUID: malformed option");
1150                 break;
1151             }
1152             hwtype=tvb_get_ntohs(tvb, off + 2);
1153             proto_tree_add_text(subtree, tvb, off + 2, 2,
1154                                 "Hardware type: %s (%u)", arphrdtype_to_str(hwtype, "Unknown"),
1155                                 hwtype);
1156             /* Packet specifies seconds since Jan 1 2000, so add 946684800U (30 years) to get back to epoch */
1157             proto_tree_add_text(subtree, tvb, off + 4, 4,
1158                 "Time: %s",
1159                 abs_time_secs_to_str(tvb_get_ntohl(tvb, off + 4)+946684800U, ABSOLUTE_TIME_LOCAL, TRUE));
1160             if (optlen > 8) {
1161                 proto_tree_add_text(subtree, tvb, off + 8,
1162                                     optlen - 8, "Link-layer address: %s",
1163                                     tvb_arphrdaddr_to_str(tvb, off+8, optlen-8, hwtype));
1164             }
1165             break;
1166         case DUID_EN:
1167             if (optlen < 6) {
1168                 proto_tree_add_text(subtree, tvb, off,
1169                                     optlen, "DUID: malformed option");
1170                 break;
1171             }
1172             proto_tree_add_item(subtree, hf_duiden_enterprise, tvb, off + 2, 4, FALSE);
1173             if (optlen > 6) {
1174                 buf = tvb_bytes_to_str(tvb, off + 6, optlen - 6);
1175                 proto_tree_add_text(subtree, tvb, off + 6,
1176                                     optlen - 6, "identifier: %s", buf);
1177             }
1178             break;
1179         case DUID_LL:
1180         case DUID_LL_OLD:
1181             if (optlen < 4) {
1182                 proto_tree_add_text(subtree, tvb, off,
1183                                     optlen, "DUID: malformed option");
1184                 break;
1185             }
1186             hwtype=tvb_get_ntohs(tvb, off + 2);
1187             proto_tree_add_text(subtree, tvb, off + 2, 2,
1188                                 "Hardware type: %s (%u)",
1189                                 arphrdtype_to_str(hwtype, "Unknown"),
1190                                 hwtype);
1191             if (optlen > 4) {
1192                 proto_tree_add_text(subtree, tvb, off + 4,
1193                                     optlen - 4, "Link-layer address: %s",
1194                                     tvb_arphrdaddr_to_str(tvb, off+4, optlen-4, hwtype));
1195             }
1196             break;
1197         }
1198         break;
1199     case OPTION_IA_NA:
1200     case OPTION_IA_PD:
1201         if (optlen < 12) {
1202             if (opttype == OPTION_IA_NA)
1203                 proto_tree_add_text(subtree, tvb, off,
1204                                     optlen, "IA_NA: malformed option");
1205             else
1206                 proto_tree_add_text(subtree, tvb, off,
1207                                     optlen, "IA_PD: malformed option");
1208             break;
1209         }
1210         proto_tree_add_text(subtree, tvb, off, 4,
1211             "IAID: %s",
1212             tvb_arphrdaddr_to_str(tvb, off, 4, opttype));
1213         if (tvb_get_ntohl(tvb, off+4) == DHCPV6_LEASEDURATION_INFINITY) {
1214             proto_tree_add_text(subtree, tvb, off+4, 4,
1215                                 "T1: infinity");
1216         } else {
1217             proto_tree_add_text(subtree, tvb, off+4, 4,
1218                                 "T1: %u", tvb_get_ntohl(tvb, off+4));
1219         }
1220
1221         if (tvb_get_ntohl(tvb, off+8) == DHCPV6_LEASEDURATION_INFINITY) {
1222             proto_tree_add_text(subtree, tvb, off+8, 4,
1223                                 "T2: infinity");
1224         } else {
1225             proto_tree_add_text(subtree, tvb, off+8, 4,
1226                                 "T2: %u", tvb_get_ntohl(tvb, off+8));
1227         }
1228
1229         temp_optlen = 12;
1230         while ((optlen - temp_optlen) > 0) {
1231             temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
1232                                          off+temp_optlen, off + optlen, at_end);
1233             if (*at_end) {
1234                 /* Bad option - just skip to the end */
1235                 temp_optlen = optlen;
1236             }
1237         }
1238         break;
1239     case OPTION_IA_TA:
1240         if (optlen < 4) {
1241             proto_tree_add_text(subtree, tvb, off,
1242                                 optlen, "IA_TA: malformed option");
1243             break;
1244         }
1245         proto_tree_add_text(subtree, tvb, off, 4,
1246             "IAID: %s",
1247             tvb_arphrdaddr_to_str(tvb, off, 4, opttype));
1248         temp_optlen = 4;
1249         while ((optlen - temp_optlen) > 0) {
1250             temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
1251                                          off+temp_optlen, off + optlen, at_end);
1252             if (*at_end) {
1253                 /* Bad option - just skip to the end */
1254                 temp_optlen = optlen;
1255             }
1256         }
1257         break;
1258     case OPTION_IAADDR:
1259     {
1260         guint32 preferred_lifetime, valid_lifetime;
1261
1262         if (optlen < 24) {
1263             proto_tree_add_text(subtree, tvb, off,
1264                                 optlen, "IAADDR: malformed option");
1265             break;
1266         }
1267         tvb_get_ipv6(tvb, off, &in6);
1268         proto_tree_add_text(subtree, tvb, off,
1269                             sizeof(in6), "IPv6 address: %s",
1270                             ip6_to_str(&in6));
1271         col_append_fstr(pinfo->cinfo, COL_INFO, "IAA: %s ", ip6_to_str(&in6));
1272         proto_item_append_text(ti, ":  %s", ip6_to_str(&in6));
1273
1274         preferred_lifetime = tvb_get_ntohl(tvb, off + 16);
1275         valid_lifetime = tvb_get_ntohl(tvb, off + 20);
1276
1277         if (preferred_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
1278             proto_tree_add_text(subtree, tvb, off + 16, 4,
1279                                 "Preferred lifetime: infinity");
1280         } else {
1281             proto_tree_add_text(subtree, tvb, off + 16, 4,
1282                                 "Preferred lifetime: %u", preferred_lifetime);
1283         }
1284         if (valid_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
1285             proto_tree_add_text(subtree, tvb, off + 20, 4,
1286                                 "Valid lifetime: infinity");
1287         } else {
1288             proto_tree_add_text(subtree, tvb, off + 20, 4,
1289                                 "Valid lifetime: %u", valid_lifetime);
1290         }
1291
1292         temp_optlen = 24;
1293         while ((optlen - temp_optlen) > 0) {
1294             temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
1295                                          off+temp_optlen, off + optlen, at_end);
1296             if (*at_end) {
1297                 /* Bad option - just skip to the end */
1298                 temp_optlen = optlen;
1299             }
1300         }
1301     }
1302     break;
1303     case OPTION_ORO:
1304     case OPTION_ERO:
1305         for (i = 0; i < optlen; i += 2) {
1306             guint16 requested_opt_code;
1307             requested_opt_code = tvb_get_ntohs(tvb, off + i);
1308             proto_tree_add_text(subtree, tvb, off + i,
1309                                 2, "Requested Option code: %s (%d)",
1310                                 val_to_str(requested_opt_code,
1311                                            opttype_vals,
1312                                            "Unknown"),
1313                                 requested_opt_code);
1314         }
1315         break;
1316     case OPTION_PREFERENCE:
1317         if (optlen != 1) {
1318             proto_tree_add_text(subtree, tvb, off,
1319                                 optlen, "PREFERENCE: malformed option");
1320             break;
1321         }
1322         proto_tree_add_text(subtree, tvb, off, 1,
1323                             "pref-value: %d",
1324                             (guint32)tvb_get_guint8(tvb, off));
1325         break;
1326     case OPTION_ELAPSED_TIME:
1327         if (optlen != 2) {
1328             proto_tree_add_text(subtree, tvb, off,
1329                                 optlen, "ELAPSED-TIME: malformed option");
1330             break;
1331         }
1332         proto_tree_add_text(subtree, tvb, off, 2,
1333                             "elapsed-time: %u ms",
1334                             10*(guint32)tvb_get_ntohs(tvb, off));
1335         break;
1336     case OPTION_RELAY_MSG:
1337         if (optlen == 0) {
1338             proto_tree_add_text(subtree, tvb, off,
1339                                 optlen, "RELAY-MSG: malformed option");
1340         } else {
1341             /* here, we should dissect a full DHCP message */
1342             dissect_dhcpv6(tvb, pinfo, subtree, downstream, off, off + optlen);
1343         }
1344         break;
1345     case OPTION_AUTH:
1346         if (optlen < 11) {
1347             proto_tree_add_text(subtree, tvb, off,
1348                                 optlen, "AUTH: malformed option");
1349             break;
1350         }
1351         proto_tree_add_text(subtree, tvb, off, 1,
1352                             "Protocol: %d",
1353                             (guint32)tvb_get_guint8(tvb, off));
1354         proto_tree_add_text(subtree, tvb, off+1, 1,
1355                             "Algorithm: %d",
1356                             (guint32)tvb_get_guint8(tvb, off+1));
1357         proto_tree_add_text(subtree, tvb, off+2, 1,
1358                             "RDM: %d",
1359                             (guint32)tvb_get_guint8(tvb, off+2));
1360         proto_tree_add_text(subtree, tvb, off+3, 8,
1361                             "Replay Detection");
1362         if (optlen != 11)
1363             proto_tree_add_text(subtree, tvb, off+11, optlen-11,
1364                                 "Authentication Information");
1365         break;
1366     case OPTION_UNICAST:
1367         if (optlen != 16) {
1368             proto_tree_add_text(subtree, tvb, off,
1369                                 optlen, "UNICAST: malformed option");
1370             break;
1371         }
1372         tvb_get_ipv6(tvb, off, &in6);
1373         proto_tree_add_text(subtree, tvb, off,
1374                             sizeof(in6), "IPv6 address: %s",
1375                             ip6_to_str(&in6));
1376         break;
1377     case OPTION_STATUS_CODE:
1378     {
1379         guint16 status_code;
1380         char *status_message = 0;
1381         status_code = tvb_get_ntohs(tvb, off);
1382         proto_tree_add_text(subtree, tvb, off, 2,
1383                             "Status Code: %s (%d)",
1384                             val_to_str(status_code, statuscode_vals,
1385                                        "Unknown"),
1386                             status_code);
1387
1388         if (optlen - 2 > 0) {
1389             status_message = tvb_get_ephemeral_string(tvb, off + 2, optlen - 2);
1390             proto_tree_add_text(subtree, tvb, off + 2, optlen - 2,
1391                                 "Status Message: %s",
1392                                 status_message);
1393         }
1394     }
1395     break;
1396     case OPTION_VENDOR_CLASS:
1397         if (optlen < 4) {
1398             proto_tree_add_text(subtree, tvb, off,
1399                                 optlen, "VENDOR_CLASS: malformed option");
1400             break;
1401         }
1402         proto_tree_add_item(subtree, hf_vendorclass_enterprise, tvb, off, 4, FALSE);
1403         if (optlen > 4) {
1404             proto_tree_add_text(subtree, tvb, off+6, optlen-6,
1405                 "vendor-class-data: \"%s\"", tvb_format_stringzpad(tvb, off + 6, optlen - 6));
1406         }
1407         break;
1408     case OPTION_VENDOR_OPTS:
1409         if (optlen < 4) {
1410             proto_tree_add_text(subtree, tvb, off,
1411                                 optlen, "VENDOR_OPTS: malformed option");
1412             break;
1413         }
1414
1415         enterprise_no = tvb_get_ntohl(tvb, off);
1416         proto_tree_add_item(subtree, hf_vendoropts_enterprise, tvb, off, 4, FALSE);
1417
1418         if (optlen >= 4) {
1419             if (enterprise_no == 4491) {
1420                 dissect_cablelabs_specific_opts(subtree, tvb, off+4, optlen-4);
1421             } else {
1422                 int optoffset = 0;
1423
1424                 while((optlen - 4 - optoffset) > 0)  {
1425                     int olen = tvb_get_ntohs(tvb, off + optoffset + 6);
1426                     ti = proto_tree_add_text(subtree, tvb, off + optoffset + 4,
1427                                              4 + olen, "option");
1428                     subtree_2 = proto_item_add_subtree(ti, ett_dhcpv6_option_vsoption);
1429
1430                     proto_tree_add_text(subtree_2, tvb, off + optoffset + 4, 2,
1431                                         "option code: %u", tvb_get_ntohs(tvb, off + optoffset + 4));
1432                     proto_tree_add_text(subtree_2, tvb, off + optoffset + 6, 2,
1433                                         "option length: %u", olen);
1434                     proto_tree_add_text(subtree_2, tvb, off + optoffset + 8, olen,
1435                                         "option-data");
1436                     optoffset += (4 + olen);
1437                 }
1438             }
1439         }
1440         break;
1441     case OPTION_INTERFACE_ID:
1442     {
1443         gint namelen;
1444
1445         if (optlen == 0) {
1446             proto_tree_add_text(subtree, tvb, off,
1447                                 optlen, "INTERFACE_ID: malformed option");
1448             break;
1449         }
1450
1451         namelen = tvb_strnlen(tvb, off, optlen)+1;
1452         if (namelen == 0)
1453         {
1454             buf = tvb_get_ephemeral_string(tvb, off, optlen);
1455             proto_tree_add_text(subtree, tvb, off, optlen, "Interface-ID: %s", buf);
1456         } else {
1457             buf = tvb_get_ephemeral_string(tvb, off, namelen-1);
1458             proto_tree_add_text(subtree, tvb, off, namelen, "Interface-ID: %s", buf);
1459
1460             temp_optlen = optlen - namelen;
1461             off += namelen;
1462             if (temp_optlen >= 6)
1463                 proto_tree_add_text(subtree, tvb, off,
1464                                     temp_optlen, "Link-layer address: %s",
1465                                     tvb_arphrdaddr_to_str(tvb, off, 6, ARPHRD_ETHER));
1466         }
1467     }
1468     break;
1469     case OPTION_RECONF_MSG:
1470         if (optlen != 1) {
1471             proto_tree_add_text(subtree, tvb, off,
1472                                 optlen, "RECONF_MSG: malformed option");
1473             break;
1474         }
1475         proto_tree_add_text(subtree, tvb, off, optlen,
1476                             "Reconfigure-type: %s",
1477                             val_to_str(tvb_get_guint8(tvb, off),
1478                                        msgtype_vals,
1479                                        "Message Type %u"));
1480         break;
1481     case OPTION_SIP_SERVER_D:
1482         if (optlen > 0) {
1483             proto_tree_add_text(subtree, tvb, off, optlen,
1484                                 "SIP Servers Domain Search List");
1485         }
1486         dhcpv6_domain(subtree,tvb, off, optlen);
1487         break;
1488     case OPTION_SIP_SERVER_A:
1489         if (optlen % 16) {
1490             proto_tree_add_text(subtree, tvb, off, optlen,
1491                                 "SIP servers address: malformed option");
1492             break;
1493         }
1494         for (i = 0; i < optlen; i += 16) {
1495             tvb_get_ipv6(tvb, off + i, &in6);
1496             proto_tree_add_text(subtree, tvb, off + i,
1497                                 sizeof(in6), "SIP servers address: %s",
1498                                 ip6_to_str(&in6));
1499         }
1500         break;
1501     case OPTION_DNS_SERVERS:
1502         if (optlen % 16) {
1503             proto_tree_add_text(subtree, tvb, off, optlen,
1504                                 "DNS servers address: malformed option");
1505             break;
1506         }
1507         for (i = 0; i < optlen; i += 16) {
1508             tvb_get_ipv6(tvb, off + i, &in6);
1509             proto_tree_add_text(subtree, tvb, off + i,
1510                                 sizeof(in6), "DNS servers address: %s",
1511                                 ip6_to_str(&in6));
1512         }
1513         break;
1514     case OPTION_DOMAIN_LIST:
1515         if (optlen > 0) {
1516             proto_tree_add_text(subtree, tvb, off, optlen, "DNS Domain Search List");
1517         }
1518         dhcpv6_domain(subtree,tvb, off, optlen);
1519         break;
1520     case OPTION_NIS_SERVERS:
1521         if (optlen % 16) {
1522             proto_tree_add_text(subtree, tvb, off, optlen,
1523                                 "NIS servers address: malformed option");
1524             break;
1525         }
1526         for (i = 0; i < optlen; i += 16) {
1527             tvb_get_ipv6(tvb, off + i, &in6);
1528             proto_tree_add_text(subtree, tvb, off + i,
1529                                 sizeof(in6), "NIS servers address: %s",
1530                                 ip6_to_str(&in6));
1531         }
1532         break;
1533     case OPTION_NISP_SERVERS:
1534         if (optlen % 16) {
1535             proto_tree_add_text(subtree, tvb, off, optlen,
1536                                 "NISP servers address: malformed option");
1537             break;
1538         }
1539         for (i = 0; i < optlen; i += 16) {
1540             tvb_get_ipv6(tvb, off + i, &in6);
1541             proto_tree_add_text(subtree, tvb, off + i,
1542                                 sizeof(in6), "NISP servers address: %s",
1543                                 ip6_to_str(&in6));
1544         }
1545         break;
1546     case OPTION_NIS_DOMAIN_NAME:
1547         if (optlen > 0) {
1548             proto_tree_add_text(subtree, tvb, off, optlen, "nis-domain-name");
1549         }
1550         dhcpv6_domain(subtree,tvb, off, optlen);
1551         break;
1552     case OPTION_NISP_DOMAIN_NAME:
1553         if (optlen > 0) {
1554             proto_tree_add_text(subtree, tvb, off, optlen, "nisp-domain-name");
1555         }
1556         dhcpv6_domain(subtree,tvb, off, optlen);
1557         break;
1558     case OPTION_SNTP_SERVERS:
1559         if (optlen % 16) {
1560             proto_tree_add_text(subtree, tvb, off, optlen,
1561                                 "SNTP servers address: malformed option");
1562             break;
1563         }
1564         for (i = 0; i < optlen; i += 16) {
1565             tvb_get_ipv6(tvb, off + i, &in6);
1566             proto_tree_add_text(subtree, tvb, off + i,
1567                                 sizeof(in6), "SNTP servers address: %s",
1568                                 ip6_to_str(&in6));
1569         }
1570         break;
1571     case OPTION_LIFETIME:
1572         if (optlen != 4) {
1573             proto_tree_add_text(subtree, tvb, off,
1574                                 optlen, "LIFETIME: malformed option");
1575             break;
1576         }
1577         proto_tree_add_text(subtree, tvb, off, 4,
1578                             "Lifetime: %d",
1579                             (guint32)tvb_get_ntohl(tvb, off));
1580         break;
1581     case OPTION_BCMCS_SERVER_D:
1582         if (optlen > 0) {
1583             proto_tree_add_text(subtree, tvb, off, optlen,
1584                                 "BCMCS Servers Domain Search List");
1585         }
1586         dhcpv6_domain(subtree,tvb, off, optlen);
1587         break;
1588     case OPTION_BCMCS_SERVER_A:
1589         if (optlen % 16) {
1590             proto_tree_add_text(subtree, tvb, off, optlen,
1591                                 "BCMCS servers address: malformed option");
1592             break;
1593         }
1594         for (i = 0; i < optlen; i += 16) {
1595             tvb_get_ipv6(tvb, off + i, &in6);
1596             proto_tree_add_text(subtree, tvb, off + i,
1597                                 sizeof(in6), "BCMCS servers address: %s",
1598                                 ip6_to_str(&in6));
1599         }
1600         break;
1601     case OPTION_REMOTE_ID:
1602         if (optlen < 4) {
1603             proto_tree_add_text(subtree, tvb, off,
1604                                 optlen, "REMOTE_ID: malformed option");
1605             break;
1606         }
1607         proto_tree_add_item(subtree, hf_remoteid_enterprise, tvb, off, 4, FALSE);
1608         off += 4;
1609         buf = tvb_bytes_to_str(tvb, off, optlen - 4);
1610         proto_tree_add_text(subtree, tvb, off, optlen - 4, "Remote-ID: %s", buf);
1611         break;
1612     case OPTION_SUBSCRIBER_ID:
1613         if (optlen == 0) {
1614             proto_tree_add_text(subtree, tvb, off,
1615                                 optlen, "SUBSCRIBER_ID: malformed option");
1616             break;
1617         }
1618         buf = tvb_get_ephemeral_string(tvb, off, optlen);
1619         proto_tree_add_text(subtree, tvb, off, optlen, "Subscriber-ID: %s", buf);
1620         break;
1621     case OPTION_CLIENT_FQDN:
1622         if (optlen < 1) {
1623             proto_tree_add_text(subtree, tvb, off,
1624                                 optlen, "FQDN: malformed option");
1625         } else {
1626             /*
1627              * +-----+-+-+-+
1628              * | MBZ |N|O|S|
1629              * +-----+-+-+-+
1630              */
1631             proto_tree_add_item(subtree, hf_clientfqdn_reserved, tvb, off, 1, FALSE);
1632             proto_tree_add_item(subtree, hf_clientfqdn_n, tvb, off, 1, FALSE);
1633             proto_tree_add_item(subtree, hf_clientfqdn_o, tvb, off, 1, FALSE);
1634             proto_tree_add_item(subtree, hf_clientfqdn_s, tvb, off, 1, FALSE);
1635
1636             dhcpv6_domain(subtree, tvb, off+1, optlen-1);
1637         }
1638         break;
1639     case OPTION_PANA_AGENT:
1640         if (optlen % 16) {
1641             proto_tree_add_text(subtree, tvb, off, optlen,
1642                                 "PANA agent address: malformed option");
1643             break;
1644         }
1645         for (i = 0; i < optlen; i += 16) {
1646             tvb_get_ipv6(tvb, off + i, &in6);
1647             proto_tree_add_text(subtree, tvb, off + i,
1648                                 sizeof(in6), "PANA agents address: %s",
1649                                 ip6_to_str(&in6));
1650         }
1651         break;
1652     case OPTION_TIME_ZONE:
1653         if (optlen > 0) {
1654             buf = tvb_get_ephemeral_string(tvb, off, optlen);
1655             proto_tree_add_text(subtree, tvb, off, optlen, "time-zone: %s", buf);
1656         }
1657         break;
1658     case OPTION_TZDB:
1659         if (optlen > 0) {
1660             buf = tvb_get_ephemeral_string(tvb, off, optlen);
1661             proto_tree_add_text(subtree, tvb, off, optlen, "tz-database: %s", buf);
1662         }
1663         break;
1664     case OPTION_LQ_QUERY:
1665     {
1666         guint8 query_type;
1667         struct e_in6_addr in6_local;
1668
1669         if (optlen < 17) {
1670             proto_tree_add_text(subtree, tvb, off, optlen,
1671                                 "LQ-QUERY: malformed option");
1672             break;
1673         }
1674         query_type = tvb_get_guint8(tvb, off);
1675         switch (query_type) {
1676         case 1:
1677             proto_tree_add_text(subtree, tvb, off, 1,
1678                                 "Query-type: %s (%u)",
1679                                 "by-address", query_type);
1680             break;
1681         case 2:
1682             proto_tree_add_text(subtree, tvb, off, 1,
1683                                 "Query-type: %s (%u)",
1684                                 "by-clientID", query_type);
1685             break;
1686         default:
1687             proto_tree_add_text(subtree, tvb, off, 1,
1688                                 "Query-type: %s (%u)",
1689                                 "unknown?", query_type);
1690             break;
1691         }
1692         tvb_get_ipv6(tvb, off + 1, &in6_local);
1693         proto_tree_add_text(subtree, tvb, off + 1, 16,
1694                             "Link address: %s", ip6_to_str(&in6_local));
1695         temp_optlen = 17;
1696         while ((optlen - temp_optlen) > 0) {
1697             temp_optlen += dhcpv6_option(tvb, pinfo, subtree,
1698                                          downstream, off + temp_optlen,
1699                                          off + optlen, at_end);
1700             if (*at_end) {
1701                 /* Bad option - just skip to the end */
1702                 temp_optlen = optlen;
1703             }
1704         }
1705     }
1706     break;
1707     case OPTION_CLIENT_DATA:
1708         temp_optlen = 0;
1709         while ((optlen - temp_optlen) > 0) {
1710             temp_optlen += dhcpv6_option(tvb, pinfo, subtree,
1711                                          downstream, off + temp_optlen,
1712                                          off + optlen, at_end);
1713             if (*at_end) {
1714                 /* Bad option - just skip to the end */
1715                 temp_optlen = optlen;
1716             }
1717         }
1718         break;
1719     case OPTION_CLT_TIME:
1720         if (optlen != 4) {
1721             proto_tree_add_text(subtree, tvb, off, optlen,
1722                                 "CLT_TIME: malformed option");
1723             break;
1724         }
1725         proto_tree_add_text(subtree, tvb, off, 4,
1726                             "Clt_time: %d",
1727                             (guint32)tvb_get_ntohl(tvb, off));
1728         break;
1729     case OPTION_LQ_RELAY_DATA:
1730         if (optlen < 16) {
1731             proto_tree_add_text(subtree, tvb, off, optlen,
1732                                 "LQ_RELAY_DATA: malformed option");
1733             break;
1734         }
1735         tvb_get_ipv6(tvb, off, &in6);
1736         proto_tree_add_text(subtree, tvb, off, 16,
1737                             "Peer address: %s", ip6_to_str(&in6));
1738         proto_tree_add_text(subtree, tvb, off + 16, optlen - 16,
1739                             "DHCPv6 relay message");
1740         break;
1741     case OPTION_LQ_CLIENT_LINK:
1742         if (optlen % 16) {
1743             proto_tree_add_text(subtree, tvb, off, optlen,
1744                                 "LQ client links address: malformed option");
1745             break;
1746         }
1747         for (i = 0; i < optlen; i += 16) {
1748             tvb_get_ipv6(tvb, off + i, &in6);
1749             proto_tree_add_text(subtree, tvb, off + i,
1750                                 sizeof(in6), "LQ client links address: %s",
1751                                 ip6_to_str(&in6));
1752         }
1753         break;
1754     case OPTION_CAPWAP_AC_V6:
1755         if (optlen % 16) {
1756             proto_tree_add_text(subtree, tvb, off, optlen,
1757                                 "CAPWAP Access Controllers address: malformed option");
1758             break;
1759         }
1760         for (i = 0; i < optlen; i += 16) {
1761             tvb_get_ipv6(tvb, off + i, &in6);
1762             proto_tree_add_text(subtree, tvb, off + i,
1763                                 sizeof(in6), "CAPWAP Access Controllers address: %s",
1764                                 ip6_to_str(&in6));
1765         }
1766         break;
1767     case OPTION_AFTR_NAME:
1768     {
1769         const guchar *dns_name;
1770         get_dns_name(tvb, off, optlen, off, &dns_name);
1771         proto_tree_add_text(subtree, tvb, off, optlen,
1772                                 "DS-Lite AFTR Name: %s", dns_name);
1773         break;
1774     }
1775     case OPTION_IAPREFIX:
1776     {
1777         guint32 preferred_lifetime, valid_lifetime;
1778         guint8  prefix_length;
1779         struct e_in6_addr in6_local;
1780
1781         if (optlen < 25) {
1782             proto_tree_add_text(subtree, tvb, off,
1783                                 optlen, "IAPREFIX: malformed option");
1784             break;
1785         }
1786
1787         preferred_lifetime = tvb_get_ntohl(tvb, off);
1788         valid_lifetime = tvb_get_ntohl(tvb, off + 4);
1789         prefix_length  = tvb_get_guint8(tvb, off + 8);
1790         if (preferred_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
1791             proto_tree_add_text(subtree, tvb, off, 4,
1792                                 "Preferred lifetime: infinity");
1793         } else {
1794             proto_tree_add_text(subtree, tvb, off, 4,
1795                                 "Preferred lifetime: %u", preferred_lifetime);
1796         }
1797         if (valid_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
1798             proto_tree_add_text(subtree, tvb, off + 4, 4,
1799                                 "Valid lifetime: infinity");
1800         } else {
1801             proto_tree_add_text(subtree, tvb, off + 4, 4,
1802                                 "Valid lifetime: %u", valid_lifetime);
1803         }
1804         proto_tree_add_text(subtree, tvb, off + 8, 1,
1805                             "Prefix length: %d", prefix_length);
1806         tvb_get_ipv6(tvb, off + 9, &in6_local);
1807         proto_tree_add_text(subtree, tvb, off + 9,
1808                             16, "Prefix address: %s",
1809                             ip6_to_str(&in6_local));
1810
1811         temp_optlen = 25;
1812         while ((optlen - temp_optlen) > 0) {
1813             temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
1814                                          off+temp_optlen, off + optlen, at_end);
1815             if (*at_end) {
1816                 /* Bad option - just skip to the end */
1817                 temp_optlen = optlen;
1818             }
1819         }
1820     }
1821     break;
1822     case OPTION_MIP6_HA:
1823         if (optlen != 16) {
1824             proto_tree_add_text(subtree, tvb, off, optlen,
1825                                 "MIP6_HA: malformed option");
1826             break;
1827         }
1828
1829         tvb_get_ipv6(tvb, off, &in6);
1830         proto_tree_add_text(subtree, tvb, off,
1831                             16, "Home Agent: %s", ip6_to_str(&in6));
1832         break;
1833     case OPTION_MIP6_HOA:
1834         if (optlen != 16) {
1835             proto_tree_add_text(subtree, tvb, off, optlen,
1836                                 "MIP6_HOA: malformed option");
1837             break;
1838         }
1839
1840         tvb_get_ipv6(tvb, off, &in6);
1841         proto_tree_add_text(subtree, tvb, off,
1842                             16, "Home Address: %s", ip6_to_str(&in6));
1843         break;
1844     case OPTION_NAI:
1845         if (optlen < 4) {
1846             proto_tree_add_text(subtree, tvb, off, optlen,
1847                                 "NAI: malformed option");
1848             break;
1849         }
1850         proto_tree_add_text(subtree, tvb, off, optlen,
1851                             "NAI : %s", tvb_get_ephemeral_string(tvb, off, optlen - 2));
1852         break;
1853     }
1854
1855     return 4 + optlen;
1856 }
1857
1858
1859 static void
1860 dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1861                gboolean downstream, int off, int eoff)
1862 {
1863     proto_tree *bp_tree = NULL;
1864     proto_item *ti;
1865     guint8 msgtype;
1866     gboolean at_end;
1867     struct e_in6_addr in6;
1868
1869     msgtype = tvb_get_guint8(tvb, off);
1870
1871     col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(msgtype, msgtype_vals, "Message Type %u"));
1872
1873     if (tree) {
1874         ti = proto_tree_add_item(tree, proto_dhcpv6, tvb, off, eoff - off, FALSE);
1875         bp_tree = proto_item_add_subtree(ti, ett_dhcpv6);
1876     }
1877
1878
1879     if (msgtype == RELAY_FORW || msgtype == RELAY_REPLY) {
1880         if (tree) {
1881             proto_tree_add_item(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1, FALSE);
1882             proto_tree_add_item(bp_tree, hf_dhcpv6_hopcount, tvb, off + 1, 1, FALSE);
1883             proto_tree_add_item(bp_tree, hf_dhcpv6_linkaddr, tvb, off + 2, 16, FALSE);
1884             tvb_get_ipv6(tvb, off + 2, &in6);
1885             col_append_fstr(pinfo->cinfo, COL_INFO, "L: %s ", ip6_to_str(&in6));
1886             proto_tree_add_item(bp_tree, hf_dhcpv6_peeraddr, tvb, off + 18, 16, FALSE);
1887         }
1888         off += 34;
1889     } else {
1890         if (tree) {
1891             proto_tree_add_item(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1, FALSE);
1892             proto_tree_add_item(bp_tree, hf_dhcpv6_xid, tvb, off + 1, 3, FALSE);
1893         }
1894         col_append_fstr(pinfo->cinfo, COL_INFO, "XID: 0x%x ", tvb_get_ntoh24(tvb, off + 1));
1895         off += 4;
1896     }
1897
1898     at_end = FALSE;
1899     while (off < eoff && !at_end)
1900         off += dhcpv6_option(tvb, pinfo, bp_tree, downstream, off, eoff, &at_end);
1901 }
1902
1903 static void
1904 dissect_dhcpv6_downstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1905 {
1906     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
1907     col_clear(pinfo->cinfo, COL_INFO);
1908     dissect_dhcpv6(tvb, pinfo, tree, TRUE, 0, tvb_reported_length(tvb));
1909 }
1910
1911 static void
1912 dissect_dhcpv6_upstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1913 {
1914     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
1915     col_clear(pinfo->cinfo, COL_INFO);
1916     dissect_dhcpv6(tvb, pinfo, tree, FALSE, 0, tvb_reported_length(tvb));
1917 }
1918
1919
1920 void
1921 proto_register_dhcpv6(void)
1922 {
1923     static hf_register_info hf[] = {
1924
1925         /* DHCPv6 header */
1926         { &hf_dhcpv6_msgtype,
1927           { "Message type", "dhcpv6.msgtype", FT_UINT8, BASE_DEC, VALS(msgtype_vals), 0x0, NULL, HFILL }},
1928         { &hf_dhcpv6_hopcount,
1929           { "Hopcount", "dhcpv6.hopcount", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL}},
1930         { &hf_dhcpv6_xid,
1931           { "Transaction ID", "dhcpv6.xid", FT_UINT24, BASE_HEX, NULL, 0, NULL, HFILL}},
1932         { &hf_dhcpv6_linkaddr,
1933           { "Link address", "dhcpv6.linkaddr", FT_IPv6, BASE_NONE, NULL, 0, NULL, HFILL}},
1934         { &hf_dhcpv6_peeraddr,
1935           { "Peer address", "dhcpv6.peeraddr", FT_IPv6, BASE_NONE, NULL, 0, NULL, HFILL}},
1936         /* Generic option stuff */
1937         { &hf_option_type,
1938           { "Option", "dhcpv6.option.type", FT_UINT16, BASE_DEC, VALS(opttype_vals), 0x0, NULL, HFILL}},
1939         { &hf_option_length,
1940           { "Length", "dhcpv6.option.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1941         { &hf_option_value,
1942           { "Value", "dhcpv6.option.value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1943         /* Individual options */
1944         { &hf_clientfqdn_reserved,
1945           { "Reserved", "dhcpv6.clientfqdn.reserved", FT_UINT8, BASE_HEX, NULL, 0xF8, NULL, HFILL}},
1946         { &hf_clientfqdn_n,
1947           { "N bit", "dhcpv6.clientfqdn.n", FT_BOOLEAN, 8, TFS(&fqdn_n), 0x4, "Whether the server SHOULD NOT perform any DNS updates", HFILL}},
1948         { &hf_clientfqdn_o,
1949           { "O bit", "dhcpv6.clientfqdn.o", FT_BOOLEAN, 8, TFS(&fqdn_o), 0x2, "Whether the server has overridden the client's preference for the S bit.  Must be 0 when sent from client", HFILL}},
1950         { &hf_clientfqdn_s,
1951           { "S bit", "dhcpv6.clientfqdn.s", FT_BOOLEAN, 8, TFS(&fqdn_s), 0x1, "Whether the server SHOULD or SHOULD NOT perform the AAAA RR (FQDN-to-address) DNS updates", HFILL}},
1952         { &hf_remoteid_enterprise,
1953           { "Enterprise ID", "dhcpv6.remoteid.enterprise", FT_UINT32, BASE_DEC|BASE_EXT_STRING,  &sminmpec_values_ext, 0, "RemoteID Enterprise Number", HFILL }},
1954         { &hf_vendoropts_enterprise,
1955           { "Enterprise ID", "dhcpv6.vendoropts.enterprise", FT_UINT32, BASE_DEC|BASE_EXT_STRING,  &sminmpec_values_ext, 0, "Vendor opts Enterprise Number", HFILL }},
1956         { &hf_vendorclass_enterprise,
1957           { "Enterprise ID", "dhcpv6.vendorclass.enterprise", FT_UINT32, BASE_DEC|BASE_EXT_STRING,  &sminmpec_values_ext, 0, "Vendor Class Enterprise Number", HFILL }},
1958         { &hf_duiden_enterprise,
1959           { "Enterprise ID", "dhcpv6.duiden.enterprise", FT_UINT32, BASE_DEC|BASE_EXT_STRING,  &sminmpec_values_ext, 0, "DUID EN Enterprise Number", HFILL }},
1960
1961     };
1962     static gint *ett[] = {
1963         &ett_dhcpv6,
1964         &ett_dhcpv6_option,
1965         &ett_dhcpv6_option_vsoption,
1966         &ett_dhcpv6_vendor_option,
1967         &ett_dhcpv6_pkt_option,
1968     };
1969
1970     proto_dhcpv6 = proto_register_protocol("DHCPv6", "DHCPv6", "dhcpv6");
1971     proto_register_field_array(proto_dhcpv6, hf, array_length(hf));
1972     proto_register_subtree_array(ett, array_length(ett));
1973
1974     /* Allow other dissectors to find this one by name.
1975        Just choose upstream version for now as they are identical. */
1976     register_dissector("dhcpv6", dissect_dhcpv6_upstream, proto_dhcpv6);
1977 }
1978
1979 void
1980 proto_reg_handoff_dhcpv6(void)
1981 {
1982     dissector_handle_t dhcpv6_handle;
1983
1984     dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_downstream,
1985                                             proto_dhcpv6);
1986     dissector_add_uint("udp.port", UDP_PORT_DHCPV6_DOWNSTREAM, dhcpv6_handle);
1987     dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_upstream,
1988                                             proto_dhcpv6);
1989     dissector_add_uint("udp.port", UDP_PORT_DHCPV6_UPSTREAM, dhcpv6_handle);
1990 }
1991