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 * Ethereal - Network traffic analyzer
25 * By Gerald Combs <gerald@ethereal.com>
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 <epan/ipv6-utils.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
130 static const value_string msgtype_vals[] = {
131 { SOLICIT, "Solicit" },
132 { ADVERTISE, "Advertise" },
133 { REQUEST, "Request" },
134 { CONFIRM, "Confirm" },
136 { REBIND, "Rebind" },
138 { RELEASE, "Release" },
139 { DECLINE, "Decline" },
140 { RECONFIGURE, "Reconfigure" },
141 { INFORMATION_REQUEST, "Information-request" },
142 { RELAY_FORW, "Relay-forw" },
143 { RELAY_REPLY, "Relay-reply" },
147 static const value_string opttype_vals[] = {
148 { OPTION_CLIENTID, "Client Identifier" },
149 { OPTION_SERVERID, "Server Identifier" },
150 { OPTION_IA_NA, "Identity Association" },
151 { OPTION_IA_TA, "Identity Association for Temporary Address" },
152 { OPTION_IAADDR, "IA Address" },
153 { OPTION_ORO, "Option Request" },
154 { OPTION_PREFERENCE, "Preference" },
155 { OPTION_ELAPSED_TIME, "Elapsed time" },
156 { OPTION_RELAY_MSG, "Relay Message" },
157 /* { OPTION_SERVER_MSG, "Server message" }, */
158 { OPTION_AUTH, "Authentication" },
159 { OPTION_UNICAST, "Server unicast" },
160 { OPTION_STATUS_CODE, "Status code" },
161 { OPTION_RAPID_COMMIT, "Rapid Commit" },
162 { OPTION_USER_CLASS, "User Class" },
163 { OPTION_VENDOR_CLASS, "Vendor Class" },
164 { OPTION_VENDOR_OPTS, "Vendor-specific Information" },
165 { OPTION_INTERFACE_ID, "Interface-Id" },
166 { OPTION_RECONF_MSG, "Reconfigure Message" },
167 { OPTION_RECONF_ACCEPT, "Reconfigure Accept" },
168 { OPTION_SIP_SERVER_D, "SIP Server Domain Name List" },
169 { OPTION_SIP_SERVER_A, "SIP Servers IPv6 Address List" },
170 { OPTION_DNS_SERVERS, "DNS recursive name server" },
171 { OPTION_DOMAIN_LIST, "Domain Search List" },
172 { OPTION_IA_PD, "Identity Association for Prefix Delegation" },
173 { OPTION_IAPREFIX, "IA Prefix" },
174 { OPTION_NIS_SERVERS, "Network Information Server" },
175 { OPTION_NISP_SERVERS, "Network Information Server V2" },
176 { OPTION_NIS_DOMAIN_NAME, "Network Information Server Domain Name" },
177 { OPTION_NISP_DOMAIN_NAME,"Network Information Server V2 Domain Name" },
178 { OPTION_SNTP_SERVERS, "Simple Network Time Protocol Server" },
179 { OPTION_TIME_ZONE, "Time zone" },
180 { OPTION_LIFETIME, "Lifetime" },
181 { OPTION_CLIENT_FQDN, "Fully Qualified Domain Name" },
182 { OPTION_MIP6_HA, "Mobile IPv6 Home Agent" },
183 { OPTION_MIP6_HOA, "Mobile IPv6 Home Address" },
184 { OPTION_NAI, "Network Access Identifier" },
188 static const value_string statuscode_vals[] =
195 {5, "UseMulticast" },
196 {6, "NoPrefixAvail" },
200 static const value_string duidtype_vals[] =
202 { DUID_LLT, "link-layer address plus time" },
203 { DUID_EN, "assigned by vendor based on Enterprise number" },
204 { DUID_LL, "link-layer address" },
205 { DUID_LL_OLD, "link-layer address (old)" },
209 /* This FQDN draft is a mess, I've tried to understand,
210 but N,O,S bit descriptions are really cryptic */
211 static const true_false_string fqdn_n = {
212 /* "Client doesn't want server to perform DNS update", "" */
213 "N bit set","N bit cleared"
216 static const true_false_string fqdn_o = {
217 "O bit set", "O bit cleared"
220 static const true_false_string fqdn_s = {
221 /* "Forward mapping (FQDN-to-IPv6, AAAA) performed by client",
222 "Forward mapping (FQDN-to-IPv6, AAAA) performed by server" */
223 "S bit set", "S bit cleared"
228 dhcpv6_domain(proto_tree * subtree, tvbuff_t *tvb, int off, guint16 optlen)
234 len = tvb_get_guint8(tvb, off);
238 proto_tree_add_text(subtree, tvb, off, optlen, "Malformed option");
241 domain = tvb_get_string(tvb, off+1, len);
242 proto_tree_add_text(subtree, tvb, off, len+1, "Domain: %s", domain);
249 /* Returns the number of bytes consumed by this option. */
251 dhcpv6_option(tvbuff_t *tvb, proto_tree *bp_tree, int off, int eoff,
257 guint16 temp_optlen = 0;
261 struct e_in6_addr in6;
265 /* option type and length must be present */
266 if (eoff - off < 4) {
271 opttype = tvb_get_ntohs(tvb, off);
272 optlen = tvb_get_ntohs(tvb, off + 2);
274 /* all option data must be present */
275 if (eoff - off < 4 + optlen) {
280 ti = proto_tree_add_text(bp_tree, tvb, off, 4 + optlen,
281 "%s", val_to_str(opttype, opttype_vals, "DHCP option %u"));
283 subtree = proto_item_add_subtree(ti, ett_dhcpv6_option);
284 proto_tree_add_text(subtree, tvb, off, 2, "option type: %d", opttype);
285 proto_tree_add_text(subtree, tvb, off + 2, 2, "option length: %d",
290 case OPTION_CLIENTID:
291 case OPTION_SERVERID:
293 proto_tree_add_text(subtree, tvb, off, optlen,
294 "DUID: malformed option");
297 duidtype = tvb_get_ntohs(tvb, off);
298 proto_tree_add_text(subtree, tvb, off, 2,
299 "DUID type: %s (%u)",
301 duidtype_vals, "Unknown"),
306 proto_tree_add_text(subtree, tvb, off,
307 optlen, "DUID: malformed option");
310 /* XXX seconds since Jan 1 2000 */
311 proto_tree_add_text(subtree, tvb, off + 2, 2,
313 tvb_get_ntohs(tvb, off + 2));
314 proto_tree_add_text(subtree, tvb, off + 4, 4,
315 "Time: %u", tvb_get_ntohl(tvb, off + 4));
317 proto_tree_add_text(subtree, tvb, off + 8,
318 optlen - 8, "Link-layer address");
323 proto_tree_add_text(subtree, tvb, off,
324 optlen, "DUID: malformed option");
327 proto_tree_add_text(subtree, tvb, off + 2, 4,
328 "enterprise-number");
330 proto_tree_add_text(subtree, tvb, off + 6,
331 optlen - 6, "identifier");
337 proto_tree_add_text(subtree, tvb, off,
338 optlen, "DUID: malformed option");
341 proto_tree_add_text(subtree, tvb, off + 2, 2,
343 tvb_get_ntohs(tvb, off + 2));
345 proto_tree_add_text(subtree, tvb, off + 4,
346 optlen - 4, "Link-layer address");
354 if (opttype == OPTION_IA_NA)
355 proto_tree_add_text(subtree, tvb, off,
356 optlen, "IA_NA: malformed option");
358 proto_tree_add_text(subtree, tvb, off,
359 optlen, "IA_PD: malformed option");
362 proto_tree_add_text(subtree, tvb, off, 4,
364 tvb_get_ntohl(tvb, off));
365 if (tvb_get_ntohl(tvb, off+4) == DHCPV6_LEASEDURATION_INFINITY) {
366 proto_tree_add_text(subtree, tvb, off+4, 4,
369 proto_tree_add_text(subtree, tvb, off+4, 4,
370 "T1: %u", tvb_get_ntohl(tvb, off+4));
373 if (tvb_get_ntohl(tvb, off+8) == DHCPV6_LEASEDURATION_INFINITY) {
374 proto_tree_add_text(subtree, tvb, off+8, 4,
377 proto_tree_add_text(subtree, tvb, off+8, 4,
378 "T2: %u", tvb_get_ntohl(tvb, off+8));
382 while ((optlen - temp_optlen) > 0) {
383 temp_optlen += dhcpv6_option(tvb, subtree, off+temp_optlen,
384 off + optlen, at_end);
386 /* Bad option - just skip to the end */
387 temp_optlen = optlen;
393 proto_tree_add_text(subtree, tvb, off,
394 optlen, "IA_TA: malformed option");
397 proto_tree_add_text(subtree, tvb, off, 4,
399 tvb_get_ntohl(tvb, off));
401 while ((optlen - temp_optlen) > 0) {
402 temp_optlen += dhcpv6_option(tvb, subtree, off+temp_optlen,
403 off + optlen, at_end);
405 /* Bad option - just skip to the end */
406 temp_optlen = optlen;
412 guint32 preferred_lifetime, valid_lifetime;
415 proto_tree_add_text(subtree, tvb, off,
416 optlen, "IAADDR: malformed option");
419 tvb_memcpy(tvb, (guint8 *)&in6, off, sizeof(in6));
420 proto_tree_add_text(subtree, tvb, off,
421 sizeof(in6), "IPv6 address: %s",
424 preferred_lifetime = tvb_get_ntohl(tvb, off + 16);
425 valid_lifetime = tvb_get_ntohl(tvb, off + 20);
427 if (preferred_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
428 proto_tree_add_text(subtree, tvb, off + 16, 4,
429 "Preferred lifetime: infinity");
431 proto_tree_add_text(subtree, tvb, off + 16, 4,
432 "Preferred lifetime: %u", preferred_lifetime);
434 if (valid_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
435 proto_tree_add_text(subtree, tvb, off + 20, 4,
436 "Valid lifetime: infinity");
438 proto_tree_add_text(subtree, tvb, off + 20, 4,
439 "Valid lifetime: %u", valid_lifetime);
443 while ((optlen - temp_optlen) > 0) {
444 temp_optlen += dhcpv6_option(tvb, subtree, off+temp_optlen,
445 off + optlen, at_end);
447 /* Bad option - just skip to the end */
448 temp_optlen = optlen;
454 for (i = 0; i < optlen; i += 2) {
455 guint16 requested_opt_code;
456 requested_opt_code = tvb_get_ntohs(tvb, off + i);
457 proto_tree_add_text(subtree, tvb, off + i,
458 2, "Requested Option code: %s (%d)",
459 val_to_str(requested_opt_code,
465 case OPTION_PREFERENCE:
467 proto_tree_add_text(subtree, tvb, off,
468 optlen, "PREFERENCE: malformed option");
471 proto_tree_add_text(subtree, tvb, off, 1,
473 (guint32)tvb_get_guint8(tvb, off));
475 case OPTION_ELAPSED_TIME:
477 proto_tree_add_text(subtree, tvb, off,
478 optlen, "ELAPSED-TIME: malformed option");
481 proto_tree_add_text(subtree, tvb, off, 2,
482 "elapsed-time: %d sec",
483 (guint32)tvb_get_ntohs(tvb, off));
485 case OPTION_RELAY_MSG:
487 proto_tree_add_text(subtree, tvb, off,
488 optlen, "RELAY-MSG: malformed option");
491 /* XXX - shouldn't we be dissecting a full DHCP message
493 proto_tree_add_uint(subtree, hf_dhcpv6_msgtype, tvb, off, 1, (guint32)tvb_get_guint8(tvb, off));
494 xid = tvb_get_ntohl(tvb, off) & 0x00ffffff;
495 proto_tree_add_text(subtree, tvb, off+1, 3, "Transaction-ID: 0x%08x", xid);
497 while (optlen > temp_optlen)
498 temp_optlen += dhcpv6_option(tvb, subtree, off+temp_optlen, off + optlen, at_end);
505 proto_tree_add_text(subtree, tvb, off,
506 optlen, "AUTH: malformed option");
509 proto_tree_add_text(subtree, tvb, off, 1,
511 (guint32)tvb_get_guint8(tvb, off));
512 proto_tree_add_text(subtree, tvb, off+1, 1,
514 (guint32)tvb_get_guint8(tvb, off+1));
515 proto_tree_add_text(subtree, tvb, off+2, 1,
517 (guint32)tvb_get_guint8(tvb, off+2));
518 proto_tree_add_text(subtree, tvb, off+3, 8,
521 proto_tree_add_text(subtree, tvb, off+11, optlen-11,
522 "Authentication Information");
526 proto_tree_add_text(subtree, tvb, off,
527 optlen, "UNICAST: malformed option");
530 tvb_memcpy(tvb, (guint8 *)&in6, off, sizeof(in6));
531 proto_tree_add_text(subtree, tvb, off,
532 sizeof(in6), "IPv6 address: %s",
535 case OPTION_STATUS_CODE:
538 char *status_message = 0;
539 status_code = tvb_get_ntohs(tvb, off);
540 proto_tree_add_text(subtree, tvb, off, 2,
541 "Status Code: %s (%d)",
542 val_to_str(status_code, statuscode_vals,
546 if (optlen - 2 > 0) {
547 status_message = tvb_get_string(tvb, off + 2, optlen - 2);
548 proto_tree_add_text(subtree, tvb, off + 2, optlen - 2,
549 "Status Message: %s",
551 g_free(status_message);
555 case OPTION_VENDOR_CLASS:
557 proto_tree_add_text(subtree, tvb, off,
558 optlen, "VENDOR_CLASS: malformed option");
561 proto_tree_add_text(subtree, tvb, off, 4,
562 "enterprise-number: %u",
563 tvb_get_ntohl(tvb, off));
565 proto_tree_add_text(subtree, tvb, off+4, optlen-4,
566 "vendor-class-data");
569 case OPTION_VENDOR_OPTS:
571 proto_tree_add_text(subtree, tvb, off,
572 optlen, "VENDOR_OPTS: malformed option");
575 proto_tree_add_text(subtree, tvb, off, 4,
576 "enterprise-number: %u",
577 tvb_get_ntohl(tvb, off));
579 proto_tree_add_text(subtree, tvb, off+4, optlen-4,
583 case OPTION_INTERFACE_ID:
585 proto_tree_add_text(subtree, tvb, off,
586 optlen, "INTERFACE_ID: malformed option");
589 proto_tree_add_text(subtree, tvb, off, optlen, "Interface-ID");
591 case OPTION_RECONF_MSG:
593 proto_tree_add_text(subtree, tvb, off,
594 optlen, "RECONF_MSG: malformed option");
597 proto_tree_add_text(subtree, tvb, off, optlen,
598 "Reconfigure-type: %s",
599 val_to_str(tvb_get_guint8(tvb, off),
603 case OPTION_SIP_SERVER_D:
605 proto_tree_add_text(subtree, tvb, off, optlen,
606 "SIP Servers Domain Search List");
608 dhcpv6_domain(subtree,tvb, off, optlen);
610 case OPTION_SIP_SERVER_A:
612 proto_tree_add_text(subtree, tvb, off, optlen,
613 "SIP servers address: malformed option");
616 for (i = 0; i < optlen; i += 16) {
617 tvb_memcpy(tvb, (guint8 *)&in6, off + i, sizeof(in6));
618 proto_tree_add_text(subtree, tvb, off + i,
619 sizeof(in6), "SIP servers address: %s",
623 case OPTION_DNS_SERVERS:
625 proto_tree_add_text(subtree, tvb, off, optlen,
626 "DNS servers address: malformed option");
629 for (i = 0; i < optlen; i += 16) {
630 tvb_memcpy(tvb, (guint8 *)&in6, off + i, sizeof(in6));
631 proto_tree_add_text(subtree, tvb, off + i,
632 sizeof(in6), "DNS servers address: %s",
636 case OPTION_DOMAIN_LIST:
638 proto_tree_add_text(subtree, tvb, off, optlen, "DNS Domain Search List");
640 dhcpv6_domain(subtree,tvb, off, optlen);
642 case OPTION_NIS_SERVERS:
644 proto_tree_add_text(subtree, tvb, off, optlen,
645 "NIS servers address: malformed option");
648 for (i = 0; i < optlen; i += 16) {
649 tvb_memcpy(tvb, (guint8 *)&in6, off + i, sizeof(in6));
650 proto_tree_add_text(subtree, tvb, off + i,
651 sizeof(in6), "NIS servers address: %s",
655 case OPTION_NISP_SERVERS:
657 proto_tree_add_text(subtree, tvb, off, optlen,
658 "NISP servers address: malformed option");
661 for (i = 0; i < optlen; i += 16) {
662 tvb_memcpy(tvb, (guint8 *)&in6, off + i, sizeof(in6));
663 proto_tree_add_text(subtree, tvb, off + i,
664 sizeof(in6), "NISP servers address: %s",
668 case OPTION_NIS_DOMAIN_NAME:
670 proto_tree_add_text(subtree, tvb, off, optlen, "nis-domain-name");
672 dhcpv6_domain(subtree,tvb, off, optlen);
674 case OPTION_NISP_DOMAIN_NAME:
676 proto_tree_add_text(subtree, tvb, off, optlen, "nisp-domain-name");
678 dhcpv6_domain(subtree,tvb, off, optlen);
680 case OPTION_SNTP_SERVERS:
682 proto_tree_add_text(subtree, tvb, off, optlen,
683 "SNTP servers address: malformed option");
686 for (i = 0; i < optlen; i += 16) {
687 tvb_memcpy(tvb, (guint8 *)&in6, off + i, sizeof(in6));
688 proto_tree_add_text(subtree, tvb, off + i,
689 sizeof(in6), "SNTP servers address: %s",
693 case OPTION_TIME_ZONE:
695 buf = tvb_get_string(tvb, off, optlen);
696 proto_tree_add_text(subtree, tvb, off, optlen, "time-zone: %s", buf);
700 case OPTION_LIFETIME:
702 proto_tree_add_text(subtree, tvb, off,
703 optlen, "LIFETIME: malformed option");
706 proto_tree_add_text(subtree, tvb, off, 4,
708 (guint32)tvb_get_ntohl(tvb, off));
710 case OPTION_CLIENT_FQDN:
712 proto_tree_add_text(subtree, tvb, off,
713 optlen, "FQDN: malformed option");
721 proto_tree_add_item(subtree, hf_fqdn_1, tvb, off, 1, FALSE);
722 proto_tree_add_item(subtree, hf_fqdn_2, tvb, off, 1, FALSE);
723 proto_tree_add_item(subtree, hf_fqdn_3, tvb, off, 1, FALSE);
724 proto_tree_add_item(subtree, hf_fqdn_4, tvb, off, 1, FALSE);
725 /* proto_tree_add_text(subtree, tvb, off, 1, */
727 /* (guint32)tvb_get_guint8(tvb, off)); */
728 dhcpv6_domain(subtree,tvb, off+1, (guint16) (optlen-1));
731 case OPTION_IAPREFIX:
733 guint32 preferred_lifetime, valid_lifetime;
734 guint8 prefix_length;
735 struct e_in6_addr in6;
738 proto_tree_add_text(subtree, tvb, off,
739 optlen, "IAPREFIX: malformed option");
743 preferred_lifetime = tvb_get_ntohl(tvb, off);
744 valid_lifetime = tvb_get_ntohl(tvb, off + 4);
745 prefix_length = tvb_get_guint8(tvb, off + 8);
746 if (preferred_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
747 proto_tree_add_text(subtree, tvb, off, 4,
748 "Preferred lifetime: infinity");
750 proto_tree_add_text(subtree, tvb, off, 4,
751 "Preferred lifetime: %u", preferred_lifetime);
753 if (valid_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
754 proto_tree_add_text(subtree, tvb, off + 4, 4,
755 "Valid lifetime: infinity");
757 proto_tree_add_text(subtree, tvb, off + 4, 4,
758 "Valid lifetime: %u", valid_lifetime);
760 proto_tree_add_text(subtree, tvb, off + 8, 1,
761 "Prefix length: %d", prefix_length);
762 tvb_memcpy(tvb, (guint8 *)&in6, off + 9 , sizeof(in6));
763 proto_tree_add_text(subtree, tvb, off + 9,
764 16, "Prefix address: %s",
768 while ((optlen - temp_optlen) > 0) {
769 temp_optlen += dhcpv6_option(tvb, subtree, off+temp_optlen,
770 off + optlen, at_end);
772 /* Bad option - just skip to the end */
773 temp_optlen = optlen;
780 proto_tree_add_text(subtree, tvb, off, optlen,
781 "MIP6_HA: malformed option");
785 tvb_memcpy(tvb, (guint8 *)&in6, off , sizeof(in6));
786 proto_tree_add_text(subtree, tvb, off,
787 16, "Home Agent: %s", ip6_to_str(&in6));
789 case OPTION_MIP6_HOA:
791 proto_tree_add_text(subtree, tvb, off, optlen,
792 "MIP6_HOA: malformed option");
796 tvb_memcpy(tvb, (guint8 *)&in6, off , sizeof(in6));
797 proto_tree_add_text(subtree, tvb, off,
798 16, "Home Address: %s", ip6_to_str(&in6));
802 proto_tree_add_text(subtree, tvb, off, optlen,
803 "NAI: malformed option");
806 proto_tree_add_text(subtree, tvb, off, optlen,
807 "NAI : %s", tvb_get_ptr(tvb, off, optlen - 2));
816 dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
819 proto_tree *bp_tree = NULL;
821 guint8 msgtype, hop_count ;
825 struct e_in6_addr in6;
827 gboolean relay_msg_option = FALSE;
830 eoff = tvb_reported_length(tvb);
831 downstream = 0; /* feature reserved */
832 if (check_col(pinfo->cinfo, COL_PROTOCOL))
833 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
834 if (check_col(pinfo->cinfo, COL_INFO))
835 col_clear(pinfo->cinfo, COL_INFO);
837 msgtype = tvb_get_guint8(tvb, off);
840 ti = proto_tree_add_item(tree, proto_dhcpv6, tvb, 0, -1, FALSE);
841 bp_tree = proto_item_add_subtree(ti, ett_dhcpv6);
844 while (msgtype == RELAY_FORW || msgtype == RELAY_REPLY) {
846 if (check_col(pinfo->cinfo, COL_INFO)) {
847 col_set_str(pinfo->cinfo, COL_INFO,
853 proto_tree_add_uint(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1, msgtype);
855 hop_count = tvb_get_guint8(tvb, off+1);
856 proto_tree_add_text(bp_tree, tvb, off+1, 1, "Hop count: %d", hop_count);
858 tvb_memcpy(tvb, (guint8 *)&in6, off+2, sizeof(in6));
859 proto_tree_add_text(bp_tree, tvb, off+2, sizeof(in6),
860 "Link-address: %s",ip6_to_str(&in6));
862 tvb_memcpy(tvb, (guint8 *)&in6, off+18, sizeof(in6));
863 proto_tree_add_text(bp_tree, tvb, off+18, sizeof(in6),
864 "Peer-address: %s",ip6_to_str(&in6));
867 relay_msg_option = FALSE;
869 while (!relay_msg_option && off < eoff) {
870 length = dhcpv6_option(tvb, bp_tree, off, eoff, &at_end);
874 if (tvb_get_ntohs(tvb, off) == OPTION_RELAY_MSG) {
875 relay_msg_option = TRUE;
882 proto_tree_add_text(bp_tree, tvb, off, eoff, "Message: malformed");
888 msgtype = tvb_get_guint8(tvb, off);
891 xid = tvb_get_ntohl(tvb, off) & 0x00ffffff;
894 if (check_col(pinfo->cinfo, COL_INFO)) {
895 col_set_str(pinfo->cinfo, COL_INFO,
903 proto_tree_add_uint(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1,
905 proto_tree_add_text(bp_tree, tvb, off+1, 3, "Transaction-ID: 0x%08x", xid);
907 tvb_memcpy(tvb, (guint8 *)&in6, 4, sizeof(in6));
908 proto_tree_add_text(bp_tree, tvb, 4, sizeof(in6),
909 "Server address: %s", ip6_to_str(&in6));
916 while (off < eoff && !at_end)
917 off += dhcpv6_option(tvb, bp_tree, off, eoff, &at_end);
921 dissect_dhcpv6_downstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
923 dissect_dhcpv6(tvb, pinfo, tree, TRUE);
927 dissect_dhcpv6_upstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
929 dissect_dhcpv6(tvb, pinfo, tree, FALSE);
934 proto_register_dhcpv6(void)
936 static hf_register_info hf[] = {
938 { &hf_dhcpv6_msgtype,
939 { "Message type", "dhcpv6.msgtype", FT_UINT8,
940 BASE_DEC, VALS(msgtype_vals), 0x0,
943 { "Reserved", "", FT_UINT8, BASE_HEX, NULL, 0xF8, "", HFILL}},
945 { "N", "", FT_BOOLEAN, 8, TFS(&fqdn_n), 0x4, "", HFILL}},
947 { "O", "", FT_BOOLEAN, 8, TFS(&fqdn_o), 0x2, "", HFILL}},
949 { "S", "", FT_BOOLEAN, 8, TFS(&fqdn_s), 0x1, "", HFILL}}
952 static gint *ett[] = {
957 proto_dhcpv6 = proto_register_protocol("DHCPv6", "DHCPv6", "dhcpv6");
958 proto_register_field_array(proto_dhcpv6, hf, array_length(hf));
959 proto_register_subtree_array(ett, array_length(ett));
963 proto_reg_handoff_dhcpv6(void)
965 dissector_handle_t dhcpv6_handle;
967 dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_downstream,
969 dissector_add("udp.port", UDP_PORT_DHCPV6_DOWNSTREAM, dhcpv6_handle);
970 dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_upstream,
972 dissector_add("udp.port", UDP_PORT_DHCPV6_UPSTREAM, dhcpv6_handle);