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>
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
23 * Note that protocol constants are still subject to change, based on IANA
24 * assignment decisions.
26 * Wireshark - Network traffic analyzer
27 * By Gerald Combs <gerald@wireshark.org>
28 * Copyright 1998 Gerald Combs
30 * This program is free software; you can redistribute it and/or
31 * modify it under the terms of the GNU General Public License
32 * as published by the Free Software Foundation; either version 2
33 * of the License, or (at your option) any later version.
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, write to the Free Software
42 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
51 #include <epan/packet.h>
52 #include <epan/sminmpec.h>
53 #include <epan/strutil.h>
54 #include "packet-arp.h"
56 static int proto_dhcpv6 = -1;
57 static int hf_dhcpv6_msgtype = -1;
58 static int hf_fqdn_1 = -1;
59 static int hf_fqdn_2 = -1;
60 static int hf_fqdn_3 = -1;
61 static int hf_fqdn_4 = -1;
63 static gint ett_dhcpv6 = -1;
64 static gint ett_dhcpv6_option = -1;
65 static gint ett_dhcpv6_option_vsoption = -1;
66 static gint ett_dhcpv6_vendor_option = -1;
67 static gint ett_dhcpv6_pkt_option = -1;
69 #define UDP_PORT_DHCPV6_DOWNSTREAM 546
70 #define UDP_PORT_DHCPV6_UPSTREAM 547
72 #define DHCPV6_LEASEDURATION_INFINITY 0xffffffff
83 #define RECONFIGURE 10
84 #define INFORMATION_REQUEST 11
86 #define RELAY_REPLY 13
88 #define LEASEQUERY_REPLY 15
90 #define OPTION_CLIENTID 1
91 #define OPTION_SERVERID 2
92 #define OPTION_IA_NA 3
93 #define OPTION_IA_TA 4
94 #define OPTION_IAADDR 5
96 #define OPTION_PREFERENCE 7
97 #define OPTION_ELAPSED_TIME 8
98 #define OPTION_RELAY_MSG 9
99 /* #define OPTION_SERVER_MSG 10 */
100 #define OPTION_AUTH 11
101 #define OPTION_UNICAST 12
102 #define OPTION_STATUS_CODE 13
103 #define OPTION_RAPID_COMMIT 14
104 #define OPTION_USER_CLASS 15
105 #define OPTION_VENDOR_CLASS 16
106 #define OPTION_VENDOR_OPTS 17
107 #define OPTION_INTERFACE_ID 18
108 #define OPTION_RECONF_MSG 19
109 #define OPTION_RECONF_ACCEPT 20
110 #define OPTION_SIP_SERVER_D 21
111 #define OPTION_SIP_SERVER_A 22
112 #define OPTION_DNS_SERVERS 23
113 #define OPTION_DOMAIN_LIST 24
114 #define OPTION_IA_PD 25
115 #define OPTION_IAPREFIX 26
116 #define OPTION_NIS_SERVERS 27
117 #define OPTION_NISP_SERVERS 28
118 #define OPTION_NIS_DOMAIN_NAME 29
119 #define OPTION_NISP_DOMAIN_NAME 30
120 #define OPTION_SNTP_SERVERS 31
121 #define OPTION_LIFETIME 32
122 #define OPTION_BCMCS_SERVER_D 33
123 #define OPTION_BCMCS_SERVER_A 34
124 #define OPTION_GEOCONF_CIVIC 36
125 #define OPTION_REMOTE_ID 37
126 #define OPTION_SUBSCRIBER_ID 38
127 #define OPTION_CLIENT_FQDN 39
128 #define OPTION_PANA_AGENT 40
129 #define OPTION_TIME_ZONE 41
130 #define OPTION_TZDB 42
131 #define OPTION_ERO 43
132 #define OPTION_LQ_QUERY 44
133 #define OPTION_CLIENT_DATA 45
134 #define OPTION_CLT_TIME 46
135 #define OPTION_LQ_RELAY_DATA 47
136 #define OPTION_LQ_CLIENT_LINK 48
137 #define OPTION_CAPWAP_AC_V6 52
139 /* temporary value until defined by IETF */
140 #define OPTION_MIP6_HA 165
141 #define OPTION_MIP6_HOA 166
142 #define OPTION_NAI 167
147 #define DUID_LL_OLD 4
150 dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
151 gboolean downstream, int off, int eoff);
153 static const value_string msgtype_vals[] = {
154 { SOLICIT, "Solicit" },
155 { ADVERTISE, "Advertise" },
156 { REQUEST, "Request" },
157 { CONFIRM, "Confirm" },
159 { REBIND, "Rebind" },
161 { RELEASE, "Release" },
162 { DECLINE, "Decline" },
163 { RECONFIGURE, "Reconfigure" },
164 { INFORMATION_REQUEST, "Information-request" },
165 { RELAY_FORW, "Relay-forw" },
166 { RELAY_REPLY, "Relay-reply" },
167 { LEASEQUERY, "Leasequery" },
168 { LEASEQUERY_REPLY, "Leasequery-reply" },
172 static const value_string opttype_vals[] = {
173 { OPTION_CLIENTID, "Client Identifier" },
174 { OPTION_SERVERID, "Server Identifier" },
175 { OPTION_IA_NA, "Identity Association for Non-temporary Address" },
176 { OPTION_IA_TA, "Identity Association for Temporary Address" },
177 { OPTION_IAADDR, "IA Address" },
178 { OPTION_ORO, "Option Request" },
179 { OPTION_PREFERENCE, "Preference" },
180 { OPTION_ELAPSED_TIME, "Elapsed time" },
181 { OPTION_RELAY_MSG, "Relay Message" },
182 /* { OPTION_SERVER_MSG, "Server message" }, */
183 { OPTION_AUTH, "Authentication" },
184 { OPTION_UNICAST, "Server unicast" },
185 { OPTION_STATUS_CODE, "Status code" },
186 { OPTION_RAPID_COMMIT, "Rapid Commit" },
187 { OPTION_USER_CLASS, "User Class" },
188 { OPTION_VENDOR_CLASS, "Vendor Class" },
189 { OPTION_VENDOR_OPTS, "Vendor-specific Information" },
190 { OPTION_INTERFACE_ID, "Interface-Id" },
191 { OPTION_RECONF_MSG, "Reconfigure Message" },
192 { OPTION_RECONF_ACCEPT, "Reconfigure Accept" },
193 { OPTION_SIP_SERVER_D, "SIP Server Domain Name List" },
194 { OPTION_SIP_SERVER_A, "SIP Servers IPv6 Address List" },
195 { OPTION_DNS_SERVERS, "DNS recursive name server" },
196 { OPTION_DOMAIN_LIST, "Domain Search List" },
197 { OPTION_IA_PD, "Identity Association for Prefix Delegation" },
198 { OPTION_IAPREFIX, "IA Prefix" },
199 { OPTION_NIS_SERVERS, "Network Information Server" },
200 { OPTION_NISP_SERVERS, "Network Information Server V2" },
201 { OPTION_NIS_DOMAIN_NAME, "Network Information Server Domain Name" },
202 { OPTION_NISP_DOMAIN_NAME,"Network Information Server V2 Domain Name" },
203 { OPTION_SNTP_SERVERS, "Simple Network Time Protocol Server" },
204 { OPTION_LIFETIME, "Lifetime" },
205 { OPTION_BCMCS_SERVER_D, "BCMCS Server Domain" },
206 { OPTION_BCMCS_SERVER_A, "BCMCS Servers IPv6 Address List" },
207 { OPTION_GEOCONF_CIVIC, "Geoconf Civic Address" },
208 { OPTION_REMOTE_ID, "Remote Identifier" },
209 { OPTION_SUBSCRIBER_ID, "Subscriber Identifier" },
210 { OPTION_CLIENT_FQDN, "Fully Qualified Domain Name" },
211 { OPTION_PANA_AGENT, "PANA Agents IPv6 Address List" },
212 { OPTION_TIME_ZONE, "Time Zone" },
213 { OPTION_TZDB, "Time Zone Database" },
214 { OPTION_ERO, "Echo Request Option" },
215 { OPTION_LQ_QUERY, "Leasequery Query" },
216 { OPTION_CLIENT_DATA, "Leasequery Client Data" },
217 { OPTION_CLT_TIME, "Client Last Transaction Time" },
218 { OPTION_LQ_RELAY_DATA, "Leasequery Relay Data" },
219 { OPTION_LQ_CLIENT_LINK, "Leasequery Client Link Address List" },
220 { OPTION_CAPWAP_AC_V6, "CAPWAP Access Controllers" },
221 { OPTION_MIP6_HA, "Mobile IPv6 Home Agent" },
222 { OPTION_MIP6_HOA, "Mobile IPv6 Home Address" },
223 { OPTION_NAI, "Network Access Identifier" },
227 static const value_string statuscode_vals[] =
234 {5, "UseMulticast" },
235 {6, "NoPrefixAvail" },
236 {7, "UnknownQueryType" },
237 {8, "MalformedQuery" },
238 {9, "NotConfigured" },
243 static const value_string duidtype_vals[] =
245 { DUID_LLT, "link-layer address plus time" },
246 { DUID_EN, "assigned by vendor based on Enterprise number" },
247 { DUID_LL, "link-layer address" },
248 { DUID_LL_OLD, "link-layer address (old)" },
252 /* This FQDN draft is a mess, I've tried to understand,
253 but N,O,S bit descriptions are really cryptic */
254 static const true_false_string fqdn_n = {
255 /* "Client doesn't want server to perform DNS update", "" */
256 "N bit set","N bit cleared"
259 static const true_false_string fqdn_o = {
260 "O bit set", "O bit cleared"
263 static const true_false_string fqdn_s = {
264 /* "Forward mapping (FQDN-to-IPv6, AAAA) performed by client",
265 "Forward mapping (FQDN-to-IPv6, AAAA) performed by server" */
266 "S bit set", "S bit cleared"
270 dhcpv6_enterprise_number(proto_tree * subtree, tvbuff_t *tvb, int offset)
272 guint32 enterprise_number;
273 enterprise_number = tvb_get_ntohl(tvb, offset);
274 proto_tree_add_text(subtree, tvb, offset, 4,
275 "Enterprise-number: %s (%u)",
276 val_to_str(enterprise_number, sminmpec_values, "%u"),
280 /* CableLabs Common Vendor Specific Options */
281 #define CL_OPTION_ORO 0x0001 /* 1 */
282 #define CL_OPTION_DEVICE_TYPE 0x0002 /* 2 */
283 #define CL_OPTION_EMBEDDED_COMPONENT_LIST 0x0003 /* 3 */
284 #define CL_OPTION_DEVICE_SERIAL_NUMBER 0x0004 /* 4 */
285 #define CL_OPTION_HARDWARE_VERSION_NUMBER 0x0005 /* 5 */
286 #define CL_OPTION_SOFTWARE_VERSION_NUMBER 0x0006 /* 6 */
287 #define CL_OPTION_BOOT_ROM_VERSION 0x0007 /* 7 */
288 #define CL_OPTION_VENDOR_OUI 0x0008 /* 8 */
289 #define CL_OPTION_MODEL_NUMBER 0x0009 /* 9 */
290 #define CL_OPTION_VENDOR_NAME 0x000a /* 10 */
291 /* 11-32 is currently reserved */
292 #define CL_OPTION_TFTP_SERVERS 0x0020 /* 32 */
293 #define CL_OPTION_CONFIG_FILE_NAME 0x0021 /* 33 */
294 #define CL_OPTION_SYSLOG_SERVERS 0x0022 /* 34 */
295 #define CL_OPTION_TLV5 0x0023 /* 35 */
296 #define CL_OPTION_DEVICE_ID 0x0024 /* 36 */
297 #define CL_OPTION_RFC868_SERVERS 0x0025 /* 37 */
298 #define CL_OPTION_TIME_OFFSET 0x0026 /* 38 */
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 */
305 /** CableLabs PacketCable Project Vendor Specific Options **/
306 #define CL_OPTION_CCC 0x087a /* 2170 */
308 /** CableLabs TLVs for DOCS_CMTS_CAP Vendor Option **/
309 #define CL_OPTION_DOCS_CMTS_TLV_VERS_NUM 0x01 /* 1 */
311 static const value_string cl_vendor_subopt_values[] = {
312 /* 1 */ { CL_OPTION_ORO, "Option Request = " },
313 /* 2 */ { CL_OPTION_DEVICE_TYPE, "Device Type = " },
314 /* 3 */ { CL_OPTION_EMBEDDED_COMPONENT_LIST, "Embedded Components = " },
315 /* 4 */ { CL_OPTION_DEVICE_SERIAL_NUMBER, "Serial Number = " },
316 /* 5 */ { CL_OPTION_HARDWARE_VERSION_NUMBER, "Hardware Version = " },
317 /* 6 */ { CL_OPTION_SOFTWARE_VERSION_NUMBER, "Software Version = " },
318 /* 7 */ { CL_OPTION_BOOT_ROM_VERSION, "Boot ROM Version = " },
319 /* 8 */ { CL_OPTION_VENDOR_OUI, "Organization Unique Identifier = " },
320 /* 9 */ { CL_OPTION_MODEL_NUMBER, "Model Number = " },
321 /* 10 */ { CL_OPTION_VENDOR_NAME, "Vendor Name = " },
322 /* 32 */ { CL_OPTION_TFTP_SERVERS, "TFTP Server Addresses : " },
323 /* 33 */ { CL_OPTION_CONFIG_FILE_NAME, "Configuration File Name = " },
324 /* 34 */ { CL_OPTION_SYSLOG_SERVERS, "Syslog Servers : " },
325 /* 35 */ { CL_OPTION_TLV5, "TLV5 = " },
326 /* 36 */ { CL_OPTION_DEVICE_ID, "Device Identifier = " },
327 /* 37 */ { CL_OPTION_RFC868_SERVERS, "Time Protocol Servers : " },
328 /* 38 */ { CL_OPTION_TIME_OFFSET, "Time Offset = " },
329 /* 1025 */ {CL_OPTION_DOCS_CMTS_CAP, "CMTS Capabilities Option : " },
330 /* 1026 */ {CL_CM_MAC_ADDR, "CM MAC Address Option = " },
331 /* 1027 */ {CL_EROUTER_CONTAINER_OPTION, "eRouter Container Option : " },
332 /* 2170 */ {CL_OPTION_CCC, "CableLabs Client Configuration : " },
336 #define PKT_CCC_PRI_DHCP 0x0001
337 #define PKT_CCC_SEC_DHCP 0x0002
338 #define PKT_CCC_IETF_PROV_SRV 0x0003
339 #define PKT_CCC_IETF_AS_KRB 0x0004
340 #define PKT_CCC_IETF_AP_KRB 0x0005
341 #define PKT_CCC_KRB_REALM 0x0006
342 #define PKT_CCC_TGT_FLAG 0x0007
343 #define PKT_CCC_PROV_TIMER 0x0008
344 #define PKT_CCC_IETF_SEC_TKT 0x0009
345 /** 10 -255 Reservered for future extensions **/
347 static const value_string pkt_ccc_opt_vals[] = {
348 { PKT_CCC_PRI_DHCP, "TSP's Primary DHCP Server" },
349 { PKT_CCC_SEC_DHCP, "TSP's Secondary DHCP Server" },
350 { PKT_CCC_IETF_PROV_SRV, "TSP's Provisioning Server" },
351 { PKT_CCC_IETF_AS_KRB, "TSP's AS-REQ/AS-REP Backoff and Retry" },
352 { PKT_CCC_IETF_AP_KRB, "TSP's AP-REQ/AP-REP Backoff and Retry" },
353 { PKT_CCC_KRB_REALM, "TSP's Kerberos Realm Name" },
354 { PKT_CCC_TGT_FLAG, "TSP's Ticket Granting Server Utilization" },
355 { PKT_CCC_PROV_TIMER, "TSP's Provisioning Timer Value" },
356 { PKT_CCC_IETF_SEC_TKT, "PacketCable Security Ticket Control" },
360 static const value_string sec_tcm_vals[] = {
361 { 1 << 0, "PacketCable Provisioning Server" },
362 { 1 << 1, "PacketCable Call Manager Servers" },
366 static void dissect_cablelabs_specific_opts(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len);
367 static int dissect_packetcable_ccc_option(proto_tree *v_tree, tvbuff_t *tvb, int optoff, int optend);
369 /* End CableLabs Vendor Specific Options */
373 dhcpv6_domain(proto_tree * subtree, tvbuff_t *tvb, int offset, guint16 optlen)
375 int start_offset=offset;
382 /* this is the start of the domain name */
388 /* read length of the next substring */
389 len = tvb_get_guint8(tvb, offset);
390 /* Microsoft dhcpv6 clients aren't currently RFC 4704 conform: They send an
391 * ASCII string instead of a DNS record encoded domain name. Catch that case
392 * to allow us to continue after such a malformed record.
394 if ( optlen < len ) {
395 proto_tree_add_text(subtree, tvb, start_offset, optlen, "Malformed DNS name record (MS Vista client?)");
400 /* if len==0 and pos>0 we have read an entire domain string */
403 /* empty string, this must be an error? */
404 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Malformed option");
407 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Domain: %s", domain);
413 /* add the substring to domain */
419 /* too long string, this must be an error? */
420 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Malformed option");
423 tvb_memcpy(tvb, domain+pos, offset, len);
431 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Domain: %s", domain);
435 /* Returns the number of bytes consumed by this option. */
437 dhcpv6_option(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bp_tree,
438 gboolean downstream, int off, int eoff, gboolean *at_end)
444 guint16 temp_optlen = 0;
447 proto_tree *subtree_2;
449 struct e_in6_addr in6;
451 guint32 enterprise_no;
453 /* option type and length must be present */
454 if (eoff - off < 4) {
459 opttype = tvb_get_ntohs(tvb, off);
460 optlen = tvb_get_ntohs(tvb, off + 2);
462 /* all option data must be present */
463 if (eoff - off < 4 + optlen) {
468 ti = proto_tree_add_text(bp_tree, tvb, off, 4 + optlen,
469 "%s", val_to_str(opttype, opttype_vals, "DHCP option %u"));
471 subtree = proto_item_add_subtree(ti, ett_dhcpv6_option);
472 proto_tree_add_text(subtree, tvb, off, 2, "option type: %d", opttype);
473 proto_tree_add_text(subtree, tvb, off + 2, 2, "option length: %d",
478 case OPTION_CLIENTID:
479 case OPTION_SERVERID:
481 proto_tree_add_text(subtree, tvb, off, optlen,
482 "DUID: malformed option");
485 duidtype = tvb_get_ntohs(tvb, off);
486 proto_tree_add_text(subtree, tvb, off, 2,
487 "DUID type: %s (%u)",
489 duidtype_vals, "Unknown"),
494 proto_tree_add_text(subtree, tvb, off,
495 optlen, "DUID: malformed option");
498 hwtype=tvb_get_ntohs(tvb, off + 2);
499 proto_tree_add_text(subtree, tvb, off + 2, 2,
500 "Hardware type: %s (%u)", arphrdtype_to_str(hwtype, "Unknown"),
502 /* XXX seconds since Jan 1 2000 */
503 proto_tree_add_text(subtree, tvb, off + 4, 4,
504 "Time: %u", tvb_get_ntohl(tvb, off + 4));
506 proto_tree_add_text(subtree, tvb, off + 8,
507 optlen - 8, "Link-layer address: %s",
508 arphrdaddr_to_str(tvb_get_ptr(tvb, off+8, optlen-8), optlen-8, hwtype));
513 proto_tree_add_text(subtree, tvb, off,
514 optlen, "DUID: malformed option");
517 dhcpv6_enterprise_number(subtree, tvb, off + 2);
519 buf = tvb_bytes_to_str(tvb, off + 6, optlen - 6);
520 proto_tree_add_text(subtree, tvb, off + 6,
521 optlen - 6, "identifier: %s", buf);
527 proto_tree_add_text(subtree, tvb, off,
528 optlen, "DUID: malformed option");
531 hwtype=tvb_get_ntohs(tvb, off + 2);
532 proto_tree_add_text(subtree, tvb, off + 2, 2,
533 "Hardware type: %s (%u)",
534 arphrdtype_to_str(hwtype, "Unknown"),
537 proto_tree_add_text(subtree, tvb, off + 4,
538 optlen - 4, "Link-layer address: %s",
539 arphrdaddr_to_str(tvb_get_ptr(tvb, off+4, optlen-4), optlen-4, hwtype));
547 if (opttype == OPTION_IA_NA)
548 proto_tree_add_text(subtree, tvb, off,
549 optlen, "IA_NA: malformed option");
551 proto_tree_add_text(subtree, tvb, off,
552 optlen, "IA_PD: malformed option");
555 proto_tree_add_text(subtree, tvb, off, 4,
557 tvb_get_ntohl(tvb, off));
558 if (tvb_get_ntohl(tvb, off+4) == DHCPV6_LEASEDURATION_INFINITY) {
559 proto_tree_add_text(subtree, tvb, off+4, 4,
562 proto_tree_add_text(subtree, tvb, off+4, 4,
563 "T1: %u", tvb_get_ntohl(tvb, off+4));
566 if (tvb_get_ntohl(tvb, off+8) == DHCPV6_LEASEDURATION_INFINITY) {
567 proto_tree_add_text(subtree, tvb, off+8, 4,
570 proto_tree_add_text(subtree, tvb, off+8, 4,
571 "T2: %u", tvb_get_ntohl(tvb, off+8));
575 while ((optlen - temp_optlen) > 0) {
576 temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
577 off+temp_optlen, off + optlen, at_end);
579 /* Bad option - just skip to the end */
580 temp_optlen = optlen;
586 proto_tree_add_text(subtree, tvb, off,
587 optlen, "IA_TA: malformed option");
590 proto_tree_add_text(subtree, tvb, off, 4,
592 tvb_get_ntohl(tvb, off));
594 while ((optlen - temp_optlen) > 0) {
595 temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
596 off+temp_optlen, off + optlen, at_end);
598 /* Bad option - just skip to the end */
599 temp_optlen = optlen;
605 guint32 preferred_lifetime, valid_lifetime;
608 proto_tree_add_text(subtree, tvb, off,
609 optlen, "IAADDR: malformed option");
612 tvb_get_ipv6(tvb, off, &in6);
613 proto_tree_add_text(subtree, tvb, off,
614 sizeof(in6), "IPv6 address: %s",
617 preferred_lifetime = tvb_get_ntohl(tvb, off + 16);
618 valid_lifetime = tvb_get_ntohl(tvb, off + 20);
620 if (preferred_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
621 proto_tree_add_text(subtree, tvb, off + 16, 4,
622 "Preferred lifetime: infinity");
624 proto_tree_add_text(subtree, tvb, off + 16, 4,
625 "Preferred lifetime: %u", preferred_lifetime);
627 if (valid_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
628 proto_tree_add_text(subtree, tvb, off + 20, 4,
629 "Valid lifetime: infinity");
631 proto_tree_add_text(subtree, tvb, off + 20, 4,
632 "Valid lifetime: %u", valid_lifetime);
636 while ((optlen - temp_optlen) > 0) {
637 temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
638 off+temp_optlen, off + optlen, at_end);
640 /* Bad option - just skip to the end */
641 temp_optlen = optlen;
648 for (i = 0; i < optlen; i += 2) {
649 guint16 requested_opt_code;
650 requested_opt_code = tvb_get_ntohs(tvb, off + i);
651 proto_tree_add_text(subtree, tvb, off + i,
652 2, "Requested Option code: %s (%d)",
653 val_to_str(requested_opt_code,
659 case OPTION_PREFERENCE:
661 proto_tree_add_text(subtree, tvb, off,
662 optlen, "PREFERENCE: malformed option");
665 proto_tree_add_text(subtree, tvb, off, 1,
667 (guint32)tvb_get_guint8(tvb, off));
669 case OPTION_ELAPSED_TIME:
671 proto_tree_add_text(subtree, tvb, off,
672 optlen, "ELAPSED-TIME: malformed option");
675 proto_tree_add_text(subtree, tvb, off, 2,
676 "elapsed-time: %u ms",
677 10*(guint32)tvb_get_ntohs(tvb, off));
679 case OPTION_RELAY_MSG:
681 proto_tree_add_text(subtree, tvb, off,
682 optlen, "RELAY-MSG: malformed option");
684 /* here, we should dissect a full DHCP message */
685 dissect_dhcpv6(tvb, pinfo, subtree, downstream, off, off + optlen);
690 proto_tree_add_text(subtree, tvb, off,
691 optlen, "AUTH: malformed option");
694 proto_tree_add_text(subtree, tvb, off, 1,
696 (guint32)tvb_get_guint8(tvb, off));
697 proto_tree_add_text(subtree, tvb, off+1, 1,
699 (guint32)tvb_get_guint8(tvb, off+1));
700 proto_tree_add_text(subtree, tvb, off+2, 1,
702 (guint32)tvb_get_guint8(tvb, off+2));
703 proto_tree_add_text(subtree, tvb, off+3, 8,
706 proto_tree_add_text(subtree, tvb, off+11, optlen-11,
707 "Authentication Information");
711 proto_tree_add_text(subtree, tvb, off,
712 optlen, "UNICAST: malformed option");
715 tvb_get_ipv6(tvb, off, &in6);
716 proto_tree_add_text(subtree, tvb, off,
717 sizeof(in6), "IPv6 address: %s",
720 case OPTION_STATUS_CODE:
723 char *status_message = 0;
724 status_code = tvb_get_ntohs(tvb, off);
725 proto_tree_add_text(subtree, tvb, off, 2,
726 "Status Code: %s (%d)",
727 val_to_str(status_code, statuscode_vals,
731 if (optlen - 2 > 0) {
732 status_message = tvb_get_ephemeral_string(tvb, off + 2, optlen - 2);
733 proto_tree_add_text(subtree, tvb, off + 2, optlen - 2,
734 "Status Message: %s",
739 case OPTION_VENDOR_CLASS:
741 proto_tree_add_text(subtree, tvb, off,
742 optlen, "VENDOR_CLASS: malformed option");
745 dhcpv6_enterprise_number(subtree, tvb, off);
747 buf = tvb_bytes_to_str(tvb, off + 4, optlen - 4);
748 proto_tree_add_text(subtree, tvb, off+4, optlen-4,
749 "vendor-class-data: %s", buf);
752 case OPTION_VENDOR_OPTS:
754 proto_tree_add_text(subtree, tvb, off,
755 optlen, "VENDOR_OPTS: malformed option");
759 enterprise_no = tvb_get_ntohl(tvb, off);
760 proto_tree_add_text(subtree, tvb, off, 4,
761 "enterprise-number: %s (%u)",
762 val_to_str(enterprise_no, sminmpec_values, "Unknown"), enterprise_no);
765 if (enterprise_no == 4491) {
766 dissect_cablelabs_specific_opts(subtree, tvb, off+4, optlen-4);
770 while((optlen - 4 - optoffset) > 0) {
771 int olen = tvb_get_ntohs(tvb, off + optoffset + 6);
772 ti = proto_tree_add_text(subtree, tvb, off + optoffset + 4,
774 subtree_2 = proto_item_add_subtree(ti, ett_dhcpv6_option_vsoption);
776 proto_tree_add_text(subtree_2, tvb, off + optoffset + 4, 2,
777 "option code: %u", tvb_get_ntohs(tvb, off + optoffset + 4));
778 proto_tree_add_text(subtree_2, tvb, off + optoffset + 6, 2,
779 "option length: %u", olen);
780 proto_tree_add_text(subtree_2, tvb, off + optoffset + 8, olen,
782 optoffset += (4 + olen);
787 case OPTION_INTERFACE_ID:
789 proto_tree_add_text(subtree, tvb, off,
790 optlen, "INTERFACE_ID: malformed option");
793 buf = tvb_get_ephemeral_string(tvb, off, optlen);
794 proto_tree_add_text(subtree, tvb, off, optlen, "Interface-ID: %s", buf);
796 case OPTION_RECONF_MSG:
798 proto_tree_add_text(subtree, tvb, off,
799 optlen, "RECONF_MSG: malformed option");
802 proto_tree_add_text(subtree, tvb, off, optlen,
803 "Reconfigure-type: %s",
804 val_to_str(tvb_get_guint8(tvb, off),
808 case OPTION_SIP_SERVER_D:
810 proto_tree_add_text(subtree, tvb, off, optlen,
811 "SIP Servers Domain Search List");
813 dhcpv6_domain(subtree,tvb, off, optlen);
815 case OPTION_SIP_SERVER_A:
817 proto_tree_add_text(subtree, tvb, off, optlen,
818 "SIP servers address: malformed option");
821 for (i = 0; i < optlen; i += 16) {
822 tvb_get_ipv6(tvb, off + i, &in6);
823 proto_tree_add_text(subtree, tvb, off + i,
824 sizeof(in6), "SIP servers address: %s",
828 case OPTION_DNS_SERVERS:
830 proto_tree_add_text(subtree, tvb, off, optlen,
831 "DNS servers address: malformed option");
834 for (i = 0; i < optlen; i += 16) {
835 tvb_get_ipv6(tvb, off + i, &in6);
836 proto_tree_add_text(subtree, tvb, off + i,
837 sizeof(in6), "DNS servers address: %s",
841 case OPTION_DOMAIN_LIST:
843 proto_tree_add_text(subtree, tvb, off, optlen, "DNS Domain Search List");
845 dhcpv6_domain(subtree,tvb, off, optlen);
847 case OPTION_NIS_SERVERS:
849 proto_tree_add_text(subtree, tvb, off, optlen,
850 "NIS servers address: malformed option");
853 for (i = 0; i < optlen; i += 16) {
854 tvb_get_ipv6(tvb, off + i, &in6);
855 proto_tree_add_text(subtree, tvb, off + i,
856 sizeof(in6), "NIS servers address: %s",
860 case OPTION_NISP_SERVERS:
862 proto_tree_add_text(subtree, tvb, off, optlen,
863 "NISP servers address: malformed option");
866 for (i = 0; i < optlen; i += 16) {
867 tvb_get_ipv6(tvb, off + i, &in6);
868 proto_tree_add_text(subtree, tvb, off + i,
869 sizeof(in6), "NISP servers address: %s",
873 case OPTION_NIS_DOMAIN_NAME:
875 proto_tree_add_text(subtree, tvb, off, optlen, "nis-domain-name");
877 dhcpv6_domain(subtree,tvb, off, optlen);
879 case OPTION_NISP_DOMAIN_NAME:
881 proto_tree_add_text(subtree, tvb, off, optlen, "nisp-domain-name");
883 dhcpv6_domain(subtree,tvb, off, optlen);
885 case OPTION_SNTP_SERVERS:
887 proto_tree_add_text(subtree, tvb, off, optlen,
888 "SNTP servers address: malformed option");
891 for (i = 0; i < optlen; i += 16) {
892 tvb_get_ipv6(tvb, off + i, &in6);
893 proto_tree_add_text(subtree, tvb, off + i,
894 sizeof(in6), "SNTP servers address: %s",
898 case OPTION_LIFETIME:
900 proto_tree_add_text(subtree, tvb, off,
901 optlen, "LIFETIME: malformed option");
904 proto_tree_add_text(subtree, tvb, off, 4,
906 (guint32)tvb_get_ntohl(tvb, off));
908 case OPTION_BCMCS_SERVER_D:
910 proto_tree_add_text(subtree, tvb, off, optlen,
911 "BCMCS Servers Domain Search List");
913 dhcpv6_domain(subtree,tvb, off, optlen);
915 case OPTION_BCMCS_SERVER_A:
917 proto_tree_add_text(subtree, tvb, off, optlen,
918 "BCMCS servers address: malformed option");
921 for (i = 0; i < optlen; i += 16) {
922 tvb_get_ipv6(tvb, off + i, &in6);
923 proto_tree_add_text(subtree, tvb, off + i,
924 sizeof(in6), "BCMCS servers address: %s",
928 case OPTION_REMOTE_ID:
930 proto_tree_add_text(subtree, tvb, off,
931 optlen, "REMOTE_ID: malformed option");
934 dhcpv6_enterprise_number(subtree, tvb, off);
937 buf = tvb_bytes_to_str(tvb, off, optlen);
938 proto_tree_add_text(subtree, tvb, off, optlen, "Remote-ID: %s", buf);
940 case OPTION_SUBSCRIBER_ID:
942 proto_tree_add_text(subtree, tvb, off,
943 optlen, "SUBSCRIBER_ID: malformed option");
946 buf = tvb_get_ephemeral_string(tvb, off, optlen);
947 proto_tree_add_text(subtree, tvb, off, optlen, "Subscriber-ID: %s", buf);
949 case OPTION_CLIENT_FQDN:
951 proto_tree_add_text(subtree, tvb, off,
952 optlen, "FQDN: malformed option");
960 proto_tree_add_item(subtree, hf_fqdn_1, tvb, off, 1, FALSE);
961 proto_tree_add_item(subtree, hf_fqdn_2, tvb, off, 1, FALSE);
962 proto_tree_add_item(subtree, hf_fqdn_3, tvb, off, 1, FALSE);
963 proto_tree_add_item(subtree, hf_fqdn_4, tvb, off, 1, FALSE);
964 /* proto_tree_add_text(subtree, tvb, off, 1, */
966 /* (guint32)tvb_get_guint8(tvb, off)); */
967 dhcpv6_domain(subtree,tvb, off+1, (guint16) (optlen-1));
969 case OPTION_PANA_AGENT:
971 proto_tree_add_text(subtree, tvb, off, optlen,
972 "PANA agent address: malformed option");
975 for (i = 0; i < optlen; i += 16) {
976 tvb_get_ipv6(tvb, off + i, &in6);
977 proto_tree_add_text(subtree, tvb, off + i,
978 sizeof(in6), "PANA agents address: %s",
982 case OPTION_TIME_ZONE:
984 buf = tvb_get_ephemeral_string(tvb, off, optlen);
985 proto_tree_add_text(subtree, tvb, off, optlen, "time-zone: %s", buf);
990 buf = tvb_get_ephemeral_string(tvb, off, optlen);
991 proto_tree_add_text(subtree, tvb, off, optlen, "tz-database: %s", buf);
994 case OPTION_LQ_QUERY:
997 struct e_in6_addr in6_local;
1000 proto_tree_add_text(subtree, tvb, off, optlen,
1001 "LQ-QUERY: malformed option");
1004 query_type = tvb_get_guint8(tvb, off);
1005 switch (query_type) {
1007 proto_tree_add_text(subtree, tvb, off, 1,
1008 "Query-type: %s (%u)",
1009 "by-address", query_type);
1012 proto_tree_add_text(subtree, tvb, off, 1,
1013 "Query-type: %s (%u)",
1014 "by-clientID", query_type);
1017 proto_tree_add_text(subtree, tvb, off, 1,
1018 "Query-type: %s (%u)",
1019 "unknown?", query_type);
1022 tvb_get_ipv6(tvb, off + 1, &in6_local);
1023 proto_tree_add_text(subtree, tvb, off + 1, 16,
1024 "Link address: %s", ip6_to_str(&in6_local));
1026 while ((optlen - temp_optlen) > 0) {
1027 temp_optlen += dhcpv6_option(tvb, pinfo, subtree,
1028 downstream, off + temp_optlen,
1029 off + optlen, at_end);
1031 /* Bad option - just skip to the end */
1032 temp_optlen = optlen;
1037 case OPTION_CLIENT_DATA:
1039 while ((optlen - temp_optlen) > 0) {
1040 temp_optlen += dhcpv6_option(tvb, pinfo, subtree,
1041 downstream, off + temp_optlen,
1042 off + optlen, at_end);
1044 /* Bad option - just skip to the end */
1045 temp_optlen = optlen;
1049 case OPTION_CLT_TIME:
1051 proto_tree_add_text(subtree, tvb, off, optlen,
1052 "CLT_TIME: malformed option");
1055 proto_tree_add_text(subtree, tvb, off, 4,
1057 (guint32)tvb_get_ntohl(tvb, off));
1059 case OPTION_LQ_RELAY_DATA:
1061 proto_tree_add_text(subtree, tvb, off, optlen,
1062 "LQ_RELAY_DATA: malformed option");
1065 tvb_get_ipv6(tvb, off, &in6);
1066 proto_tree_add_text(subtree, tvb, off, 16,
1067 "Peer address: %s", ip6_to_str(&in6));
1068 proto_tree_add_text(subtree, tvb, off + 16, optlen - 16,
1069 "DHCPv6 relay message");
1071 case OPTION_LQ_CLIENT_LINK:
1073 proto_tree_add_text(subtree, tvb, off, optlen,
1074 "LQ client links address: malformed option");
1077 for (i = 0; i < optlen; i += 16) {
1078 tvb_get_ipv6(tvb, off + i, &in6);
1079 proto_tree_add_text(subtree, tvb, off + i,
1080 sizeof(in6), "LQ client links address: %s",
1084 case OPTION_CAPWAP_AC_V6:
1086 proto_tree_add_text(subtree, tvb, off, optlen,
1087 "CAPWAP Access Controllers address: malformed option");
1090 for (i = 0; i < optlen; i += 16) {
1091 tvb_get_ipv6(tvb, off + i, &in6);
1092 proto_tree_add_text(subtree, tvb, off + i,
1093 sizeof(in6), "CAPWAP Access Controllers address: %s",
1097 case OPTION_IAPREFIX:
1099 guint32 preferred_lifetime, valid_lifetime;
1100 guint8 prefix_length;
1101 struct e_in6_addr in6_local;
1104 proto_tree_add_text(subtree, tvb, off,
1105 optlen, "IAPREFIX: malformed option");
1109 preferred_lifetime = tvb_get_ntohl(tvb, off);
1110 valid_lifetime = tvb_get_ntohl(tvb, off + 4);
1111 prefix_length = tvb_get_guint8(tvb, off + 8);
1112 if (preferred_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
1113 proto_tree_add_text(subtree, tvb, off, 4,
1114 "Preferred lifetime: infinity");
1116 proto_tree_add_text(subtree, tvb, off, 4,
1117 "Preferred lifetime: %u", preferred_lifetime);
1119 if (valid_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
1120 proto_tree_add_text(subtree, tvb, off + 4, 4,
1121 "Valid lifetime: infinity");
1123 proto_tree_add_text(subtree, tvb, off + 4, 4,
1124 "Valid lifetime: %u", valid_lifetime);
1126 proto_tree_add_text(subtree, tvb, off + 8, 1,
1127 "Prefix length: %d", prefix_length);
1128 tvb_get_ipv6(tvb, off + 9, &in6_local);
1129 proto_tree_add_text(subtree, tvb, off + 9,
1130 16, "Prefix address: %s",
1131 ip6_to_str(&in6_local));
1134 while ((optlen - temp_optlen) > 0) {
1135 temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
1136 off+temp_optlen, off + optlen, at_end);
1138 /* Bad option - just skip to the end */
1139 temp_optlen = optlen;
1144 case OPTION_MIP6_HA:
1146 proto_tree_add_text(subtree, tvb, off, optlen,
1147 "MIP6_HA: malformed option");
1151 tvb_get_ipv6(tvb, off, &in6);
1152 proto_tree_add_text(subtree, tvb, off,
1153 16, "Home Agent: %s", ip6_to_str(&in6));
1155 case OPTION_MIP6_HOA:
1157 proto_tree_add_text(subtree, tvb, off, optlen,
1158 "MIP6_HOA: malformed option");
1162 tvb_get_ipv6(tvb, off, &in6);
1163 proto_tree_add_text(subtree, tvb, off,
1164 16, "Home Address: %s", ip6_to_str(&in6));
1168 proto_tree_add_text(subtree, tvb, off, optlen,
1169 "NAI: malformed option");
1172 proto_tree_add_text(subtree, tvb, off, optlen,
1173 "NAI : %s", tvb_get_ptr(tvb, off, optlen - 2));
1182 dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1183 gboolean downstream, int off, int eoff)
1185 proto_tree *bp_tree = NULL;
1187 guint8 msgtype, hop_count ;
1189 struct e_in6_addr in6;
1192 downstream = 0; /* feature reserved */
1194 msgtype = tvb_get_guint8(tvb, off);
1197 ti = proto_tree_add_item(tree, proto_dhcpv6, tvb, 0, -1, FALSE);
1198 bp_tree = proto_item_add_subtree(ti, ett_dhcpv6);
1201 if (msgtype == RELAY_FORW || msgtype == RELAY_REPLY) {
1204 if (check_col(pinfo->cinfo, COL_INFO)) {
1205 col_add_str(pinfo->cinfo, COL_INFO,
1208 "Message Type %u"));
1212 proto_tree_add_uint(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1, msgtype);
1214 hop_count = tvb_get_guint8(tvb, off+1);
1215 proto_tree_add_text(bp_tree, tvb, off+1, 1, "Hop count: %d", hop_count);
1217 tvb_get_ipv6(tvb, off+2, &in6);
1218 proto_tree_add_text(bp_tree, tvb, off+2, sizeof(in6),
1219 "Link-address: %s",ip6_to_str(&in6));
1221 tvb_get_ipv6(tvb, off+18, &in6);
1222 proto_tree_add_text(bp_tree, tvb, off+18, sizeof(in6),
1223 "Peer-address: %s",ip6_to_str(&in6));
1228 xid = tvb_get_ntohl(tvb, off) & 0x00ffffff;
1231 if (check_col(pinfo->cinfo, COL_INFO)) {
1232 col_add_str(pinfo->cinfo, COL_INFO,
1235 "Message Type %u"));
1240 proto_tree_add_uint(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1,
1242 proto_tree_add_text(bp_tree, tvb, off+1, 3, "Transaction-ID: 0x%08x", xid);
1244 tvb_get_ipv6(tvb, 4, &in6);
1245 proto_tree_add_text(bp_tree, tvb, 4, sizeof(in6),
1246 "Server address: %s", ip6_to_str(&in6));
1254 while (off < eoff && !at_end)
1255 off += dhcpv6_option(tvb, pinfo, bp_tree, downstream, off, eoff, &at_end);
1259 dissect_dhcpv6_downstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1261 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
1262 col_clear(pinfo->cinfo, COL_INFO);
1263 dissect_dhcpv6(tvb, pinfo, tree, TRUE, 0, tvb_reported_length(tvb));
1267 dissect_dhcpv6_upstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1269 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
1270 col_clear(pinfo->cinfo, COL_INFO);
1271 dissect_dhcpv6(tvb, pinfo, tree, FALSE, 0, tvb_reported_length(tvb));
1276 proto_register_dhcpv6(void)
1278 static hf_register_info hf[] = {
1280 { &hf_dhcpv6_msgtype,
1281 { "Message type", "dhcpv6.msgtype", FT_UINT8,
1282 BASE_DEC, VALS(msgtype_vals), 0x0,
1285 { "Reserved", "dhcpv6.msgtype.reserved", FT_UINT8, BASE_HEX, NULL, 0xF8, NULL, HFILL}},
1287 { "N", "dhcpv6.msgtype.n", FT_BOOLEAN, 8, TFS(&fqdn_n), 0x4, NULL, HFILL}},
1289 { "O", "dhcpv6.msgtype.o", FT_BOOLEAN, 8, TFS(&fqdn_o), 0x2, NULL, HFILL}},
1291 { "S", "dhcpv6.msgtype.s", FT_BOOLEAN, 8, TFS(&fqdn_s), 0x1, NULL, HFILL}}
1294 static gint *ett[] = {
1297 &ett_dhcpv6_option_vsoption,
1298 &ett_dhcpv6_vendor_option,
1299 &ett_dhcpv6_pkt_option,
1302 proto_dhcpv6 = proto_register_protocol("DHCPv6", "DHCPv6", "dhcpv6");
1303 proto_register_field_array(proto_dhcpv6, hf, array_length(hf));
1304 proto_register_subtree_array(ett, array_length(ett));
1306 /* Allow other dissectors to find this one by name.
1307 Just choose upstream version for now as they are identical. */
1308 register_dissector("dhcpv6", dissect_dhcpv6_upstream, proto_dhcpv6);
1312 proto_reg_handoff_dhcpv6(void)
1314 dissector_handle_t dhcpv6_handle;
1316 dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_downstream,
1318 dissector_add("udp.port", UDP_PORT_DHCPV6_DOWNSTREAM, dhcpv6_handle);
1319 dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_upstream,
1321 dissector_add("udp.port", UDP_PORT_DHCPV6_UPSTREAM, dhcpv6_handle);
1325 dissect_cablelabs_specific_opts(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len)
1328 guint16 tlv_len; /* holds the number of elements in the tlv */
1329 guint16 opt_len; /* holds the length of the suboption */
1332 int sub_off; /** The offset for the sub-option */
1335 int field_len; /* holds the lenght of one occurrence of a field */
1336 proto_tree *subtree;
1337 struct e_in6_addr in6;
1340 while (off - voff < len) {
1343 type = tvb_get_ntohs(tvb, off);
1344 ti = proto_tree_add_text(v_tree, tvb, off, 2,
1345 "Suboption %d: %s", type, val_to_str(type,
1346 cl_vendor_subopt_values, "unknown"));
1348 tlv_len = tvb_get_ntohs(tvb, off+2);
1355 case CL_OPTION_DEVICE_TYPE :
1356 case CL_OPTION_DEVICE_SERIAL_NUMBER :
1357 case CL_OPTION_HARDWARE_VERSION_NUMBER :
1358 case CL_OPTION_SOFTWARE_VERSION_NUMBER :
1359 case CL_OPTION_BOOT_ROM_VERSION :
1360 case CL_OPTION_MODEL_NUMBER :
1361 case CL_OPTION_VENDOR_NAME :
1362 case CL_OPTION_CONFIG_FILE_NAME :
1363 case CL_OPTION_EMBEDDED_COMPONENT_LIST :
1365 field_len = tlv_len;
1366 proto_item_append_text(ti, "\"%s\"",
1367 tvb_format_stringzpad(tvb, sub_off, field_len));
1369 case CL_OPTION_ORO :
1371 opt_len = tlv_len * field_len;
1373 for (i = 0; i < tlv_len; i += field_len) {
1374 sub_value = tvb_get_ntohs(tvb, sub_off);
1375 proto_item_append_text(ti, " %d", sub_value);
1376 sub_off += field_len;
1381 /* List of IPv6 Address */
1382 case CL_OPTION_TFTP_SERVERS :
1383 case CL_OPTION_SYSLOG_SERVERS :
1384 case CL_OPTION_RFC868_SERVERS :
1387 subtree = proto_item_add_subtree(ti, ett_dhcpv6_vendor_option);
1389 if ((tlv_len % field_len) == 0) {
1390 for (i = 0; i < tlv_len/field_len; i++) {
1391 tvb_get_ipv6(tvb, sub_off, &in6);
1392 proto_tree_add_text(subtree, tvb, sub_off,
1393 sizeof(in6), "IPv6 address %d: %s",
1394 i+1, ip6_to_str(&in6));
1395 sub_off += field_len;
1400 case CL_OPTION_VENDOR_OUI :
1401 case CL_OPTION_DEVICE_ID :
1403 field_len = tlv_len;
1405 proto_item_append_text(ti, "Bogus value length=%d",
1409 proto_item_append_text(ti, "%s",
1410 tvb_bytes_to_str(tvb, sub_off, field_len));
1414 case CL_OPTION_TLV5 :
1416 field_len = tlv_len;
1417 proto_item_append_text(ti, "%s",
1418 tvb_bytes_to_str(tvb, sub_off, field_len));
1421 case CL_OPTION_TIME_OFFSET :
1423 proto_item_append_text(ti, "%d", tvb_get_ntohl(tvb, sub_off));
1426 case CL_OPTION_DOCS_CMTS_CAP :
1429 subtree = proto_item_add_subtree(ti, ett_dhcpv6_vendor_option);
1431 /* tlv_len contains the total length of all the TLVs for this
1434 for (i = 0; field_len < opt_len; i++) {
1437 tag = tvb_get_guint8(tvb, sub_off);
1439 tagLen = tvb_get_guint8(tvb, sub_off);
1441 if (tag == CL_OPTION_DOCS_CMTS_TLV_VERS_NUM &&
1445 major = tvb_get_guint8(tvb, sub_off);
1447 minor = tvb_get_guint8(tvb, sub_off);
1449 proto_tree_add_text(subtree, tvb, sub_off,
1450 sizeof(4), "DOCSIS Version Number %d.%d",
1456 field_len += tagLen + 2;
1460 proto_tree_add_text(subtree, tvb, sub_off,
1461 sizeof(0), "empty");
1464 case CL_CM_MAC_ADDR :
1466 field_len = tlv_len;
1468 proto_item_append_text(ti, "Bogus value length=%d",
1472 /*proto_item_append_text(ti, "CM MAC Address Option = %s", */
1473 proto_item_append_text(ti, "%s",
1474 bytes_to_str_punct(tvb_get_ptr(tvb, sub_off, opt_len), opt_len, ':'));
1475 /* tvb_bytes_to_str(tvb, sub_off, opt_len)); */
1477 sub_off += field_len;
1480 case CL_EROUTER_CONTAINER_OPTION :
1482 field_len = tlv_len;
1483 proto_item_append_text(ti, " %s (len=%d)",
1484 tvb_bytes_to_str(tvb, sub_off, opt_len), tlv_len);
1485 sub_off += field_len;
1488 case CL_OPTION_CCC :
1491 subtree = proto_item_add_subtree(ti, ett_dhcpv6_vendor_option);
1492 proto_item_append_text(ti, " (%d bytes)", opt_len);
1493 while (field_len < opt_len) {
1494 sub_value = dissect_packetcable_ccc_option(subtree, tvb,
1495 sub_off, (opt_len - field_len));
1496 sub_off += sub_value;
1497 field_len += sub_value;
1499 sub_off += field_len;
1505 off += (opt_len + 4);
1510 proto_tree_add_text(v_tree, tvb, off, len-off,
1511 "Bogus length: %d", len);
1515 dissect_packetcable_ccc_option(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
1518 /** THE ENCODING OF THIS SUBOPTION HAS CHANGED FROM DHCPv4
1519 the code and length fields have grown from a single octet to
1520 two octets each. **/
1521 int suboptoff = optoff;
1522 guint16 subopt, subopt_len, sec_tcm;
1523 guint8 fetch_tgt, timer_val, type;
1525 proto_tree *pkt_s_tree;
1527 guchar kr_name; /** A character in the kerberos realm name option */
1528 guint8 kr_value; /* The integer value of the character currently being tested */
1529 int kr_fail_flag = 0; /* Flag indicating an invalid character was found */
1530 int kr_pos = 0; /* The position of the first invalid character */
1534 subopt = tvb_get_ntohs(tvb, optoff);
1537 subopt_len = tvb_get_ntohs(tvb, suboptoff);
1540 /* There must be at least five octets left to be a valid sub element */
1542 proto_tree_add_text(v_tree, tvb, optoff, 1,
1543 "Sub element %d: no room left in option for suboption length",
1547 /* g_print("dissect packetcable ccc option subopt_len=%d optend=%d\n\n", subopt_len, optend); */
1549 vti = proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 4,
1550 "Sub element %u: %s: ", subopt,
1551 val_to_str(subopt, pkt_ccc_opt_vals, "unknown/reserved") );
1554 case PKT_CCC_PRI_DHCP: /* IPv4 address values */
1555 case PKT_CCC_SEC_DHCP:
1556 if (subopt_len == 4) {
1557 ipv4_addr = tvb_get_ipv4(tvb, suboptoff);
1558 proto_item_append_text(vti, "%s (%u byte%s%s)",
1559 ip_to_str((guint8 *)&ipv4_addr), subopt_len,
1560 plurality(subopt_len, "", "s"),
1561 subopt_len != 4 ? " [Invalid]" : "");
1564 proto_tree_add_text(vti, tvb, suboptoff, subopt_len,
1565 "Bogus length: %d", subopt_len);
1569 suboptoff += subopt_len;
1571 case PKT_CCC_IETF_PROV_SRV :
1572 type = tvb_get_guint8(tvb, suboptoff);
1573 /** Type 0 is FQDN **/
1575 proto_item_append_text(vti, "%s (%u byte%s)",
1576 tvb_format_stringzpad(tvb, suboptoff+1, subopt_len-1),
1578 plurality(subopt_len-1, "", "s") );
1580 /** Type 0 is IPv4 **/
1581 else if (type == 1) {
1582 if (subopt_len == 5) {
1583 ipv4_addr = tvb_get_ipv4(tvb, suboptoff+1);
1584 proto_item_append_text(vti, "%s (%u byte%s%s)",
1585 ip_to_str((guint8 *)&ipv4_addr), subopt_len,
1586 plurality(subopt_len, "", "s"),
1587 subopt_len != 5 ? " [Invalid]" : "");
1590 proto_item_append_text(vti, "Bogus length: %d", subopt_len);
1594 proto_item_append_text(vti, "Invalid type: %u (%u byte%s)",
1595 type, subopt_len, plurality(subopt_len, "", "s"));
1597 suboptoff += subopt_len;
1600 case PKT_CCC_IETF_AS_KRB :
1601 case PKT_CCC_IETF_AP_KRB :
1602 if (subopt_len == 12) {
1603 pkt_s_tree = proto_item_add_subtree(vti, ett_dhcpv6_pkt_option);
1604 proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
1605 "Nominal Timeout : %u", tvb_get_ntohl(tvb, suboptoff));
1606 proto_tree_add_text(pkt_s_tree, tvb, suboptoff+4, 4,
1607 "Maximum Timeout : %u", tvb_get_ntohl(tvb, suboptoff+4));
1608 proto_tree_add_text(pkt_s_tree, tvb, suboptoff+8, 4,
1609 "Maximum Retry Count : %u", tvb_get_ntohl(tvb, suboptoff+8));
1613 proto_item_append_text(vti, "Bogus length: %d", subopt_len);
1615 suboptoff += subopt_len;
1617 case PKT_CCC_KRB_REALM:
1618 if (subopt_len > 0) {
1619 /** The only allowable characters are
1620 A-Z (upper case only) 65-90
1630 make sure it conforms to the expected syntax.
1632 for (i=0; i < subopt_len; i++) {
1633 kr_name = tvb_get_guint8(tvb, suboptoff + i);
1634 kr_value = (int)kr_name;
1635 if ((kr_value >= 65 && kr_value <= 90) ||
1644 else if (!kr_fail_flag) {
1648 proto_item_append_text(vti, "%c",
1653 proto_item_append_text(vti, " (%u byte%s [Invalid at byte=%d]) ",
1655 plurality(subopt_len, "", "s"),
1659 proto_item_append_text(vti, " (%u byte%s%s) ",
1661 plurality(subopt_len, "", "s"),
1662 kr_fail_flag != 0 ? " [Invalid]" : "");
1665 suboptoff += subopt_len;
1668 case PKT_CCC_TGT_FLAG:
1669 fetch_tgt = tvb_get_guint8(tvb, suboptoff);
1670 proto_item_append_text(vti, "%s (%u byte%s%s)",
1671 fetch_tgt == 1 ? "True" : "False",
1673 plurality(subopt_len, "", "s"),
1674 subopt_len != 1 ? " [Invalid]" : "");
1675 suboptoff += subopt_len;
1678 case PKT_CCC_PROV_TIMER:
1679 timer_val = tvb_get_guint8(tvb, suboptoff);
1680 /* proto_item_append_text(vti, "%u%s (%u byte%s%s)", timer_val,
1681 timer_val > 30 ? " [Invalid]" : "", */
1682 proto_item_append_text(vti, "%u (%u byte%s%s)", timer_val,
1684 plurality(subopt_len, "", "s"),
1685 subopt_len != 1 ? " [Invalid]" : "");
1686 suboptoff += subopt_len;
1689 case PKT_CCC_IETF_SEC_TKT :
1690 sec_tcm = tvb_get_ntohs(tvb, suboptoff);
1691 proto_item_append_text(vti, "0x%04x (%u byte%s%s)",
1692 sec_tcm, subopt_len, plurality(subopt_len, "", "s"),
1693 subopt_len != 2 ? " [Invalid]" : "");
1695 if (subopt_len == 2) {
1696 pkt_s_tree = proto_item_add_subtree(vti, ett_dhcpv6_pkt_option);
1697 for (i=0; i< 2; i++) {
1698 if (sec_tcm & sec_tcm_vals[i].value) {
1699 decode_bitfield_value(bit_fld, sec_tcm, sec_tcm_vals[i].value, 16);
1700 proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 2, "%s %s",
1701 bit_fld, sec_tcm_vals[i].strptr);
1705 suboptoff += subopt_len;
1710 suboptoff += subopt_len;
1715 /** Return the number of bytes processed **/
1716 return (suboptoff - optoff);