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