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 * draft-ietf-dhc-dhcpv6-opt-timeconfig-03.txt
18 * draft-ietf-dhc-dhcpv6-opt-fqdn-00.txt
19 * draft-ietf-dhc-dhcpv6-opt-lifetime-00.txt
21 * Note that protocol constants are still subject to change, based on IANA
22 * assignment decisions.
24 * Wireshark - Network traffic analyzer
25 * By Gerald Combs <gerald@wireshark.org>
26 * Copyright 1998 Gerald Combs
28 * This program is free software; you can redistribute it and/or
29 * modify it under the terms of the GNU General Public License
30 * as published by the Free Software Foundation; either version 2
31 * of the License, or (at your option) any later version.
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
38 * You should have received a copy of the GNU General Public License
39 * along with this program; if not, write to the Free Software
40 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
49 #include <epan/packet.h>
50 #include "packet-arp.h"
52 static int proto_dhcpv6 = -1;
53 static int hf_dhcpv6_msgtype = -1;
54 static int hf_fqdn_1 = -1;
55 static int hf_fqdn_2 = -1;
56 static int hf_fqdn_3 = -1;
57 static int hf_fqdn_4 = -1;
59 static gint ett_dhcpv6 = -1;
60 static gint ett_dhcpv6_option = -1;
62 #define UDP_PORT_DHCPV6_DOWNSTREAM 546
63 #define UDP_PORT_DHCPV6_UPSTREAM 547
65 #define DHCPV6_LEASEDURATION_INFINITY 0xffffffff
76 #define RECONFIGURE 10
77 #define INFORMATION_REQUEST 11
79 #define RELAY_REPLY 13
81 #define OPTION_CLIENTID 1
82 #define OPTION_SERVERID 2
83 #define OPTION_IA_NA 3
84 #define OPTION_IA_TA 4
85 #define OPTION_IAADDR 5
87 #define OPTION_PREFERENCE 7
88 #define OPTION_ELAPSED_TIME 8
89 #define OPTION_RELAY_MSG 9
90 /* #define OPTION_SERVER_MSG 10 */
91 #define OPTION_AUTH 11
92 #define OPTION_UNICAST 12
93 #define OPTION_STATUS_CODE 13
94 #define OPTION_RAPID_COMMIT 14
95 #define OPTION_USER_CLASS 15
96 #define OPTION_VENDOR_CLASS 16
97 #define OPTION_VENDOR_OPTS 17
98 #define OPTION_INTERFACE_ID 18
99 #define OPTION_RECONF_MSG 19
100 #define OPTION_RECONF_ACCEPT 20
101 #define OPTION_SIP_SERVER_D 21
102 #define OPTION_SIP_SERVER_A 22
103 #define OPTION_DNS_SERVERS 23
104 #define OPTION_DOMAIN_LIST 24
105 #define OPTION_IA_PD 25
106 #define OPTION_IAPREFIX 26
107 #define OPTION_NIS_SERVERS 27
108 #define OPTION_NISP_SERVERS 28
109 #define OPTION_NIS_DOMAIN_NAME 29
110 #define OPTION_NISP_DOMAIN_NAME 30
113 * The followings are unassigned numbers.
115 #define OPTION_CLIENT_FQDN 34
116 #define OPTION_SNTP_SERVERS 40
117 #define OPTION_TIME_ZONE 41
118 #define OPTION_LIFETIME 42
120 /* temporary value until defined by IETF */
121 #define OPTION_MIP6_HA 165
122 #define OPTION_MIP6_HOA 166
123 #define OPTION_NAI 167
128 #define DUID_LL_OLD 4
131 dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
132 gboolean downstream, int off, int eoff);
134 static const value_string msgtype_vals[] = {
135 { SOLICIT, "Solicit" },
136 { ADVERTISE, "Advertise" },
137 { REQUEST, "Request" },
138 { CONFIRM, "Confirm" },
140 { REBIND, "Rebind" },
142 { RELEASE, "Release" },
143 { DECLINE, "Decline" },
144 { RECONFIGURE, "Reconfigure" },
145 { INFORMATION_REQUEST, "Information-request" },
146 { RELAY_FORW, "Relay-forw" },
147 { RELAY_REPLY, "Relay-reply" },
151 static const value_string opttype_vals[] = {
152 { OPTION_CLIENTID, "Client Identifier" },
153 { OPTION_SERVERID, "Server Identifier" },
154 { OPTION_IA_NA, "Identity Association for Non-temporary Address" },
155 { OPTION_IA_TA, "Identity Association for Temporary Address" },
156 { OPTION_IAADDR, "IA Address" },
157 { OPTION_ORO, "Option Request" },
158 { OPTION_PREFERENCE, "Preference" },
159 { OPTION_ELAPSED_TIME, "Elapsed time" },
160 { OPTION_RELAY_MSG, "Relay Message" },
161 /* { OPTION_SERVER_MSG, "Server message" }, */
162 { OPTION_AUTH, "Authentication" },
163 { OPTION_UNICAST, "Server unicast" },
164 { OPTION_STATUS_CODE, "Status code" },
165 { OPTION_RAPID_COMMIT, "Rapid Commit" },
166 { OPTION_USER_CLASS, "User Class" },
167 { OPTION_VENDOR_CLASS, "Vendor Class" },
168 { OPTION_VENDOR_OPTS, "Vendor-specific Information" },
169 { OPTION_INTERFACE_ID, "Interface-Id" },
170 { OPTION_RECONF_MSG, "Reconfigure Message" },
171 { OPTION_RECONF_ACCEPT, "Reconfigure Accept" },
172 { OPTION_SIP_SERVER_D, "SIP Server Domain Name List" },
173 { OPTION_SIP_SERVER_A, "SIP Servers IPv6 Address List" },
174 { OPTION_DNS_SERVERS, "DNS recursive name server" },
175 { OPTION_DOMAIN_LIST, "Domain Search List" },
176 { OPTION_IA_PD, "Identity Association for Prefix Delegation" },
177 { OPTION_IAPREFIX, "IA Prefix" },
178 { OPTION_NIS_SERVERS, "Network Information Server" },
179 { OPTION_NISP_SERVERS, "Network Information Server V2" },
180 { OPTION_NIS_DOMAIN_NAME, "Network Information Server Domain Name" },
181 { OPTION_NISP_DOMAIN_NAME,"Network Information Server V2 Domain Name" },
182 { OPTION_SNTP_SERVERS, "Simple Network Time Protocol Server" },
183 { OPTION_TIME_ZONE, "Time zone" },
184 { OPTION_LIFETIME, "Lifetime" },
185 { OPTION_CLIENT_FQDN, "Fully Qualified Domain Name" },
186 { OPTION_MIP6_HA, "Mobile IPv6 Home Agent" },
187 { OPTION_MIP6_HOA, "Mobile IPv6 Home Address" },
188 { OPTION_NAI, "Network Access Identifier" },
192 static const value_string statuscode_vals[] =
199 {5, "UseMulticast" },
200 {6, "NoPrefixAvail" },
204 static const value_string duidtype_vals[] =
206 { DUID_LLT, "link-layer address plus time" },
207 { DUID_EN, "assigned by vendor based on Enterprise number" },
208 { DUID_LL, "link-layer address" },
209 { DUID_LL_OLD, "link-layer address (old)" },
213 /* This FQDN draft is a mess, I've tried to understand,
214 but N,O,S bit descriptions are really cryptic */
215 static const true_false_string fqdn_n = {
216 /* "Client doesn't want server to perform DNS update", "" */
217 "N bit set","N bit cleared"
220 static const true_false_string fqdn_o = {
221 "O bit set", "O bit cleared"
224 static const true_false_string fqdn_s = {
225 /* "Forward mapping (FQDN-to-IPv6, AAAA) performed by client",
226 "Forward mapping (FQDN-to-IPv6, AAAA) performed by server" */
227 "S bit set", "S bit cleared"
232 dhcpv6_domain(proto_tree * subtree, tvbuff_t *tvb, int offset, guint16 optlen)
234 int start_offset=offset;
241 /* this is the start of the domain name */
247 /* read length of the next substring */
248 len = tvb_get_guint8(tvb, offset);
252 /* if len==0 and pos>0 we have read an entire domain string */
255 /* empty string, this must be an error? */
256 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Malformed option");
259 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Domain: %s", domain);
265 /* add the substring to domain */
271 /* too long string, this must be an error? */
272 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Malformed option");
275 tvb_memcpy(tvb, domain+pos, offset, len);
283 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Domain: %s", domain);
287 /* Returns the number of bytes consumed by this option. */
289 dhcpv6_option(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bp_tree,
290 gboolean downstream, int off, int eoff, gboolean *at_end)
296 guint16 temp_optlen = 0;
300 struct e_in6_addr in6;
303 /* option type and length must be present */
304 if (eoff - off < 4) {
309 opttype = tvb_get_ntohs(tvb, off);
310 optlen = tvb_get_ntohs(tvb, off + 2);
312 /* all option data must be present */
313 if (eoff - off < 4 + optlen) {
318 ti = proto_tree_add_text(bp_tree, tvb, off, 4 + optlen,
319 "%s", val_to_str(opttype, opttype_vals, "DHCP option %u"));
321 subtree = proto_item_add_subtree(ti, ett_dhcpv6_option);
322 proto_tree_add_text(subtree, tvb, off, 2, "option type: %d", opttype);
323 proto_tree_add_text(subtree, tvb, off + 2, 2, "option length: %d",
328 case OPTION_CLIENTID:
329 case OPTION_SERVERID:
331 proto_tree_add_text(subtree, tvb, off, optlen,
332 "DUID: malformed option");
335 duidtype = tvb_get_ntohs(tvb, off);
336 proto_tree_add_text(subtree, tvb, off, 2,
337 "DUID type: %s (%u)",
339 duidtype_vals, "Unknown"),
344 proto_tree_add_text(subtree, tvb, off,
345 optlen, "DUID: malformed option");
348 hwtype=tvb_get_ntohs(tvb, off + 2);
349 proto_tree_add_text(subtree, tvb, off + 2, 2,
350 "Hardware type: %s (%u)",
351 arphrdtype_to_str(hwtype, "Unknown"),
353 /* XXX seconds since Jan 1 2000 */
354 proto_tree_add_text(subtree, tvb, off + 4, 4,
355 "Time: %u", tvb_get_ntohl(tvb, off + 4));
357 proto_tree_add_text(subtree, tvb, off + 8,
358 optlen - 8, "Link-layer address: %s",
359 arphrdaddr_to_str(tvb_get_ptr(tvb, off+8, optlen-8), optlen-8, hwtype));
364 proto_tree_add_text(subtree, tvb, off,
365 optlen, "DUID: malformed option");
368 proto_tree_add_text(subtree, tvb, off + 2, 4,
369 "enterprise-number");
371 proto_tree_add_text(subtree, tvb, off + 6,
372 optlen - 6, "identifier");
378 proto_tree_add_text(subtree, tvb, off,
379 optlen, "DUID: malformed option");
382 hwtype=tvb_get_ntohs(tvb, off + 2);
383 proto_tree_add_text(subtree, tvb, off + 2, 2,
384 "Hardware type: %s (%u)",
385 arphrdtype_to_str(hwtype, "Unknown"),
388 proto_tree_add_text(subtree, tvb, off + 4,
389 optlen - 4, "Link-layer address: %s",
390 arphrdaddr_to_str(tvb_get_ptr(tvb, off+4, optlen-4), optlen-4, hwtype));
398 if (opttype == OPTION_IA_NA)
399 proto_tree_add_text(subtree, tvb, off,
400 optlen, "IA_NA: malformed option");
402 proto_tree_add_text(subtree, tvb, off,
403 optlen, "IA_PD: malformed option");
406 proto_tree_add_text(subtree, tvb, off, 4,
408 tvb_get_ntohl(tvb, off));
409 if (tvb_get_ntohl(tvb, off+4) == DHCPV6_LEASEDURATION_INFINITY) {
410 proto_tree_add_text(subtree, tvb, off+4, 4,
413 proto_tree_add_text(subtree, tvb, off+4, 4,
414 "T1: %u", tvb_get_ntohl(tvb, off+4));
417 if (tvb_get_ntohl(tvb, off+8) == DHCPV6_LEASEDURATION_INFINITY) {
418 proto_tree_add_text(subtree, tvb, off+8, 4,
421 proto_tree_add_text(subtree, tvb, off+8, 4,
422 "T2: %u", tvb_get_ntohl(tvb, off+8));
426 while ((optlen - temp_optlen) > 0) {
427 temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
428 off+temp_optlen, off + optlen, at_end);
430 /* Bad option - just skip to the end */
431 temp_optlen = optlen;
437 proto_tree_add_text(subtree, tvb, off,
438 optlen, "IA_TA: malformed option");
441 proto_tree_add_text(subtree, tvb, off, 4,
443 tvb_get_ntohl(tvb, off));
445 while ((optlen - temp_optlen) > 0) {
446 temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
447 off+temp_optlen, off + optlen, at_end);
449 /* Bad option - just skip to the end */
450 temp_optlen = optlen;
456 guint32 preferred_lifetime, valid_lifetime;
459 proto_tree_add_text(subtree, tvb, off,
460 optlen, "IAADDR: malformed option");
463 tvb_get_ipv6(tvb, off, &in6);
464 proto_tree_add_text(subtree, tvb, off,
465 sizeof(in6), "IPv6 address: %s",
468 preferred_lifetime = tvb_get_ntohl(tvb, off + 16);
469 valid_lifetime = tvb_get_ntohl(tvb, off + 20);
471 if (preferred_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
472 proto_tree_add_text(subtree, tvb, off + 16, 4,
473 "Preferred lifetime: infinity");
475 proto_tree_add_text(subtree, tvb, off + 16, 4,
476 "Preferred lifetime: %u", preferred_lifetime);
478 if (valid_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
479 proto_tree_add_text(subtree, tvb, off + 20, 4,
480 "Valid lifetime: infinity");
482 proto_tree_add_text(subtree, tvb, off + 20, 4,
483 "Valid lifetime: %u", valid_lifetime);
487 while ((optlen - temp_optlen) > 0) {
488 temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
489 off+temp_optlen, off + optlen, at_end);
491 /* Bad option - just skip to the end */
492 temp_optlen = optlen;
498 for (i = 0; i < optlen; i += 2) {
499 guint16 requested_opt_code;
500 requested_opt_code = tvb_get_ntohs(tvb, off + i);
501 proto_tree_add_text(subtree, tvb, off + i,
502 2, "Requested Option code: %s (%d)",
503 val_to_str(requested_opt_code,
509 case OPTION_PREFERENCE:
511 proto_tree_add_text(subtree, tvb, off,
512 optlen, "PREFERENCE: malformed option");
515 proto_tree_add_text(subtree, tvb, off, 1,
517 (guint32)tvb_get_guint8(tvb, off));
519 case OPTION_ELAPSED_TIME:
521 proto_tree_add_text(subtree, tvb, off,
522 optlen, "ELAPSED-TIME: malformed option");
525 proto_tree_add_text(subtree, tvb, off, 2,
526 "elapsed-time: %d sec",
527 (guint32)tvb_get_ntohs(tvb, off));
529 case OPTION_RELAY_MSG:
531 proto_tree_add_text(subtree, tvb, off,
532 optlen, "RELAY-MSG: malformed option");
534 /* here, we should dissect a full DHCP message */
535 dissect_dhcpv6(tvb, pinfo, subtree, downstream, off, off + optlen);
540 proto_tree_add_text(subtree, tvb, off,
541 optlen, "AUTH: malformed option");
544 proto_tree_add_text(subtree, tvb, off, 1,
546 (guint32)tvb_get_guint8(tvb, off));
547 proto_tree_add_text(subtree, tvb, off+1, 1,
549 (guint32)tvb_get_guint8(tvb, off+1));
550 proto_tree_add_text(subtree, tvb, off+2, 1,
552 (guint32)tvb_get_guint8(tvb, off+2));
553 proto_tree_add_text(subtree, tvb, off+3, 8,
556 proto_tree_add_text(subtree, tvb, off+11, optlen-11,
557 "Authentication Information");
561 proto_tree_add_text(subtree, tvb, off,
562 optlen, "UNICAST: malformed option");
565 tvb_get_ipv6(tvb, off, &in6);
566 proto_tree_add_text(subtree, tvb, off,
567 sizeof(in6), "IPv6 address: %s",
570 case OPTION_STATUS_CODE:
573 char *status_message = 0;
574 status_code = tvb_get_ntohs(tvb, off);
575 proto_tree_add_text(subtree, tvb, off, 2,
576 "Status Code: %s (%d)",
577 val_to_str(status_code, statuscode_vals,
581 if (optlen - 2 > 0) {
582 status_message = tvb_get_ephemeral_string(tvb, off + 2, optlen - 2);
583 proto_tree_add_text(subtree, tvb, off + 2, optlen - 2,
584 "Status Message: %s",
589 case OPTION_VENDOR_CLASS:
591 proto_tree_add_text(subtree, tvb, off,
592 optlen, "VENDOR_CLASS: malformed option");
595 proto_tree_add_text(subtree, tvb, off, 4,
596 "enterprise-number: %u",
597 tvb_get_ntohl(tvb, off));
599 proto_tree_add_text(subtree, tvb, off+4, optlen-4,
600 "vendor-class-data");
603 case OPTION_VENDOR_OPTS:
605 proto_tree_add_text(subtree, tvb, off,
606 optlen, "VENDOR_OPTS: malformed option");
609 proto_tree_add_text(subtree, tvb, off, 4,
610 "enterprise-number: %u",
611 tvb_get_ntohl(tvb, off));
613 proto_tree_add_text(subtree, tvb, off+4, optlen-4,
617 case OPTION_INTERFACE_ID:
619 proto_tree_add_text(subtree, tvb, off,
620 optlen, "INTERFACE_ID: malformed option");
623 proto_tree_add_text(subtree, tvb, off, optlen, "Interface-ID");
625 case OPTION_RECONF_MSG:
627 proto_tree_add_text(subtree, tvb, off,
628 optlen, "RECONF_MSG: malformed option");
631 proto_tree_add_text(subtree, tvb, off, optlen,
632 "Reconfigure-type: %s",
633 val_to_str(tvb_get_guint8(tvb, off),
637 case OPTION_SIP_SERVER_D:
639 proto_tree_add_text(subtree, tvb, off, optlen,
640 "SIP Servers Domain Search List");
642 dhcpv6_domain(subtree,tvb, off, optlen);
644 case OPTION_SIP_SERVER_A:
646 proto_tree_add_text(subtree, tvb, off, optlen,
647 "SIP servers address: malformed option");
650 for (i = 0; i < optlen; i += 16) {
651 tvb_get_ipv6(tvb, off + i, &in6);
652 proto_tree_add_text(subtree, tvb, off + i,
653 sizeof(in6), "SIP servers address: %s",
657 case OPTION_DNS_SERVERS:
659 proto_tree_add_text(subtree, tvb, off, optlen,
660 "DNS servers address: malformed option");
663 for (i = 0; i < optlen; i += 16) {
664 tvb_get_ipv6(tvb, off + i, &in6);
665 proto_tree_add_text(subtree, tvb, off + i,
666 sizeof(in6), "DNS servers address: %s",
670 case OPTION_DOMAIN_LIST:
672 proto_tree_add_text(subtree, tvb, off, optlen, "DNS Domain Search List");
674 dhcpv6_domain(subtree,tvb, off, optlen);
676 case OPTION_NIS_SERVERS:
678 proto_tree_add_text(subtree, tvb, off, optlen,
679 "NIS servers address: malformed option");
682 for (i = 0; i < optlen; i += 16) {
683 tvb_get_ipv6(tvb, off + i, &in6);
684 proto_tree_add_text(subtree, tvb, off + i,
685 sizeof(in6), "NIS servers address: %s",
689 case OPTION_NISP_SERVERS:
691 proto_tree_add_text(subtree, tvb, off, optlen,
692 "NISP servers address: malformed option");
695 for (i = 0; i < optlen; i += 16) {
696 tvb_get_ipv6(tvb, off + i, &in6);
697 proto_tree_add_text(subtree, tvb, off + i,
698 sizeof(in6), "NISP servers address: %s",
702 case OPTION_NIS_DOMAIN_NAME:
704 proto_tree_add_text(subtree, tvb, off, optlen, "nis-domain-name");
706 dhcpv6_domain(subtree,tvb, off, optlen);
708 case OPTION_NISP_DOMAIN_NAME:
710 proto_tree_add_text(subtree, tvb, off, optlen, "nisp-domain-name");
712 dhcpv6_domain(subtree,tvb, off, optlen);
714 case OPTION_SNTP_SERVERS:
716 proto_tree_add_text(subtree, tvb, off, optlen,
717 "SNTP servers address: malformed option");
720 for (i = 0; i < optlen; i += 16) {
721 tvb_get_ipv6(tvb, off + i, &in6);
722 proto_tree_add_text(subtree, tvb, off + i,
723 sizeof(in6), "SNTP servers address: %s",
727 case OPTION_TIME_ZONE:
729 buf = tvb_get_ephemeral_string(tvb, off, optlen);
730 proto_tree_add_text(subtree, tvb, off, optlen, "time-zone: %s", buf);
733 case OPTION_LIFETIME:
735 proto_tree_add_text(subtree, tvb, off,
736 optlen, "LIFETIME: malformed option");
739 proto_tree_add_text(subtree, tvb, off, 4,
741 (guint32)tvb_get_ntohl(tvb, off));
743 case OPTION_CLIENT_FQDN:
745 proto_tree_add_text(subtree, tvb, off,
746 optlen, "FQDN: malformed option");
754 proto_tree_add_item(subtree, hf_fqdn_1, tvb, off, 1, FALSE);
755 proto_tree_add_item(subtree, hf_fqdn_2, tvb, off, 1, FALSE);
756 proto_tree_add_item(subtree, hf_fqdn_3, tvb, off, 1, FALSE);
757 proto_tree_add_item(subtree, hf_fqdn_4, tvb, off, 1, FALSE);
758 /* proto_tree_add_text(subtree, tvb, off, 1, */
760 /* (guint32)tvb_get_guint8(tvb, off)); */
761 dhcpv6_domain(subtree,tvb, off+1, (guint16) (optlen-1));
764 case OPTION_IAPREFIX:
766 guint32 preferred_lifetime, valid_lifetime;
767 guint8 prefix_length;
768 struct e_in6_addr in6;
771 proto_tree_add_text(subtree, tvb, off,
772 optlen, "IAPREFIX: malformed option");
776 preferred_lifetime = tvb_get_ntohl(tvb, off);
777 valid_lifetime = tvb_get_ntohl(tvb, off + 4);
778 prefix_length = tvb_get_guint8(tvb, off + 8);
779 if (preferred_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
780 proto_tree_add_text(subtree, tvb, off, 4,
781 "Preferred lifetime: infinity");
783 proto_tree_add_text(subtree, tvb, off, 4,
784 "Preferred lifetime: %u", preferred_lifetime);
786 if (valid_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
787 proto_tree_add_text(subtree, tvb, off + 4, 4,
788 "Valid lifetime: infinity");
790 proto_tree_add_text(subtree, tvb, off + 4, 4,
791 "Valid lifetime: %u", valid_lifetime);
793 proto_tree_add_text(subtree, tvb, off + 8, 1,
794 "Prefix length: %d", prefix_length);
795 tvb_get_ipv6(tvb, off + 9, &in6);
796 proto_tree_add_text(subtree, tvb, off + 9,
797 16, "Prefix address: %s",
801 while ((optlen - temp_optlen) > 0) {
802 temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
803 off+temp_optlen, off + optlen, at_end);
805 /* Bad option - just skip to the end */
806 temp_optlen = optlen;
813 proto_tree_add_text(subtree, tvb, off, optlen,
814 "MIP6_HA: malformed option");
818 tvb_get_ipv6(tvb, off, &in6);
819 proto_tree_add_text(subtree, tvb, off,
820 16, "Home Agent: %s", ip6_to_str(&in6));
822 case OPTION_MIP6_HOA:
824 proto_tree_add_text(subtree, tvb, off, optlen,
825 "MIP6_HOA: malformed option");
829 tvb_get_ipv6(tvb, off, &in6);
830 proto_tree_add_text(subtree, tvb, off,
831 16, "Home Address: %s", ip6_to_str(&in6));
835 proto_tree_add_text(subtree, tvb, off, optlen,
836 "NAI: malformed option");
839 proto_tree_add_text(subtree, tvb, off, optlen,
840 "NAI : %s", tvb_get_ptr(tvb, off, optlen - 2));
849 dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
850 gboolean downstream, int off, int eoff)
852 proto_tree *bp_tree = NULL;
854 guint8 msgtype, hop_count ;
856 struct e_in6_addr in6;
859 downstream = 0; /* feature reserved */
861 msgtype = tvb_get_guint8(tvb, off);
864 ti = proto_tree_add_item(tree, proto_dhcpv6, tvb, 0, -1, FALSE);
865 bp_tree = proto_item_add_subtree(ti, ett_dhcpv6);
868 if (msgtype == RELAY_FORW || msgtype == RELAY_REPLY) {
871 if (check_col(pinfo->cinfo, COL_INFO)) {
872 col_set_str(pinfo->cinfo, COL_INFO,
879 proto_tree_add_uint(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1, msgtype);
881 hop_count = tvb_get_guint8(tvb, off+1);
882 proto_tree_add_text(bp_tree, tvb, off+1, 1, "Hop count: %d", hop_count);
884 tvb_get_ipv6(tvb, off+2, &in6);
885 proto_tree_add_text(bp_tree, tvb, off+2, sizeof(in6),
886 "Link-address: %s",ip6_to_str(&in6));
888 tvb_get_ipv6(tvb, off+18, &in6);
889 proto_tree_add_text(bp_tree, tvb, off+18, sizeof(in6),
890 "Peer-address: %s",ip6_to_str(&in6));
895 xid = tvb_get_ntohl(tvb, off) & 0x00ffffff;
898 if (check_col(pinfo->cinfo, COL_INFO)) {
899 col_set_str(pinfo->cinfo, COL_INFO,
907 proto_tree_add_uint(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1,
909 proto_tree_add_text(bp_tree, tvb, off+1, 3, "Transaction-ID: 0x%08x", xid);
911 tvb_get_ipv6(tvb, 4, &in6);
912 proto_tree_add_text(bp_tree, tvb, 4, sizeof(in6),
913 "Server address: %s", ip6_to_str(&in6));
921 while (off < eoff && !at_end)
922 off += dhcpv6_option(tvb, pinfo, bp_tree, downstream, off, eoff, &at_end);
926 dissect_dhcpv6_downstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
928 if (check_col(pinfo->cinfo, COL_PROTOCOL))
929 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
930 if (check_col(pinfo->cinfo, COL_INFO))
931 col_clear(pinfo->cinfo, COL_INFO);
932 dissect_dhcpv6(tvb, pinfo, tree, TRUE, 0, tvb_reported_length(tvb));
936 dissect_dhcpv6_upstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
938 if (check_col(pinfo->cinfo, COL_PROTOCOL))
939 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
940 if (check_col(pinfo->cinfo, COL_INFO))
941 col_clear(pinfo->cinfo, COL_INFO);
942 dissect_dhcpv6(tvb, pinfo, tree, FALSE, 0, tvb_reported_length(tvb));
947 proto_register_dhcpv6(void)
949 static hf_register_info hf[] = {
951 { &hf_dhcpv6_msgtype,
952 { "Message type", "dhcpv6.msgtype", FT_UINT8,
953 BASE_DEC, VALS(msgtype_vals), 0x0,
956 { "Reserved", "", FT_UINT8, BASE_HEX, NULL, 0xF8, "", HFILL}},
958 { "N", "dhcpv6.msgtype.n", FT_BOOLEAN, 8, TFS(&fqdn_n), 0x4, "", HFILL}},
960 { "O", "dhcpv6.msgtype.o", FT_BOOLEAN, 8, TFS(&fqdn_o), 0x2, "", HFILL}},
962 { "S", "dhcpv6.msgtype.s", FT_BOOLEAN, 8, TFS(&fqdn_s), 0x1, "", HFILL}}
965 static gint *ett[] = {
970 proto_dhcpv6 = proto_register_protocol("DHCPv6", "DHCPv6", "dhcpv6");
971 proto_register_field_array(proto_dhcpv6, hf, array_length(hf));
972 proto_register_subtree_array(ett, array_length(ett));
976 proto_reg_handoff_dhcpv6(void)
978 dissector_handle_t dhcpv6_handle;
980 dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_downstream,
982 dissector_add("udp.port", UDP_PORT_DHCPV6_DOWNSTREAM, dhcpv6_handle);
983 dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_upstream,
985 dissector_add("udp.port", UDP_PORT_DHCPV6_UPSTREAM, dhcpv6_handle);