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 "packet-arp.h"
55 static int proto_dhcpv6 = -1;
56 static int hf_dhcpv6_msgtype = -1;
57 static int hf_fqdn_1 = -1;
58 static int hf_fqdn_2 = -1;
59 static int hf_fqdn_3 = -1;
60 static int hf_fqdn_4 = -1;
62 static gint ett_dhcpv6 = -1;
63 static gint ett_dhcpv6_option = -1;
64 static gint ett_dhcpv6_option_vsoption = -1;
66 #define UDP_PORT_DHCPV6_DOWNSTREAM 546
67 #define UDP_PORT_DHCPV6_UPSTREAM 547
69 #define DHCPV6_LEASEDURATION_INFINITY 0xffffffff
80 #define RECONFIGURE 10
81 #define INFORMATION_REQUEST 11
83 #define RELAY_REPLY 13
85 #define LEASEQUERY_REPLY 15
87 #define OPTION_CLIENTID 1
88 #define OPTION_SERVERID 2
89 #define OPTION_IA_NA 3
90 #define OPTION_IA_TA 4
91 #define OPTION_IAADDR 5
93 #define OPTION_PREFERENCE 7
94 #define OPTION_ELAPSED_TIME 8
95 #define OPTION_RELAY_MSG 9
96 /* #define OPTION_SERVER_MSG 10 */
97 #define OPTION_AUTH 11
98 #define OPTION_UNICAST 12
99 #define OPTION_STATUS_CODE 13
100 #define OPTION_RAPID_COMMIT 14
101 #define OPTION_USER_CLASS 15
102 #define OPTION_VENDOR_CLASS 16
103 #define OPTION_VENDOR_OPTS 17
104 #define OPTION_INTERFACE_ID 18
105 #define OPTION_RECONF_MSG 19
106 #define OPTION_RECONF_ACCEPT 20
107 #define OPTION_SIP_SERVER_D 21
108 #define OPTION_SIP_SERVER_A 22
109 #define OPTION_DNS_SERVERS 23
110 #define OPTION_DOMAIN_LIST 24
111 #define OPTION_IA_PD 25
112 #define OPTION_IAPREFIX 26
113 #define OPTION_NIS_SERVERS 27
114 #define OPTION_NISP_SERVERS 28
115 #define OPTION_NIS_DOMAIN_NAME 29
116 #define OPTION_NISP_DOMAIN_NAME 30
117 #define OPTION_SNTP_SERVERS 31
118 #define OPTION_LIFETIME 32
119 #define OPTION_BCMCS_SERVER_D 33
120 #define OPTION_BCMCS_SERVER_A 34
121 #define OPTION_GEOCONF_CIVIC 36
122 #define OPTION_REMOTE_ID 37
123 #define OPTION_SUBSCRIBER_ID 38
124 #define OPTION_CLIENT_FQDN 39
125 #define OPTION_PANA_AGENT 40
126 #define OPTION_TIME_ZONE 41
127 #define OPTION_TZDB 42
128 #define OPTION_ERO 43
129 #define OPTION_LQ_QUERY 44
130 #define OPTION_CLIENT_DATA 45
131 #define OPTION_CLT_TIME 46
132 #define OPTION_LQ_RELAY_DATA 47
133 #define OPTION_LQ_CLIENT_LINK 48
134 #define OPTION_CAPWAP_AC_V6 52
136 /* temporary value until defined by IETF */
137 #define OPTION_MIP6_HA 165
138 #define OPTION_MIP6_HOA 166
139 #define OPTION_NAI 167
144 #define DUID_LL_OLD 4
147 dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
148 gboolean downstream, int off, int eoff);
150 static const value_string msgtype_vals[] = {
151 { SOLICIT, "Solicit" },
152 { ADVERTISE, "Advertise" },
153 { REQUEST, "Request" },
154 { CONFIRM, "Confirm" },
156 { REBIND, "Rebind" },
158 { RELEASE, "Release" },
159 { DECLINE, "Decline" },
160 { RECONFIGURE, "Reconfigure" },
161 { INFORMATION_REQUEST, "Information-request" },
162 { RELAY_FORW, "Relay-forw" },
163 { RELAY_REPLY, "Relay-reply" },
164 { LEASEQUERY, "Leasequery" },
165 { LEASEQUERY_REPLY, "Leasequery-reply" },
169 static const value_string opttype_vals[] = {
170 { OPTION_CLIENTID, "Client Identifier" },
171 { OPTION_SERVERID, "Server Identifier" },
172 { OPTION_IA_NA, "Identity Association for Non-temporary Address" },
173 { OPTION_IA_TA, "Identity Association for Temporary Address" },
174 { OPTION_IAADDR, "IA Address" },
175 { OPTION_ORO, "Option Request" },
176 { OPTION_PREFERENCE, "Preference" },
177 { OPTION_ELAPSED_TIME, "Elapsed time" },
178 { OPTION_RELAY_MSG, "Relay Message" },
179 /* { OPTION_SERVER_MSG, "Server message" }, */
180 { OPTION_AUTH, "Authentication" },
181 { OPTION_UNICAST, "Server unicast" },
182 { OPTION_STATUS_CODE, "Status code" },
183 { OPTION_RAPID_COMMIT, "Rapid Commit" },
184 { OPTION_USER_CLASS, "User Class" },
185 { OPTION_VENDOR_CLASS, "Vendor Class" },
186 { OPTION_VENDOR_OPTS, "Vendor-specific Information" },
187 { OPTION_INTERFACE_ID, "Interface-Id" },
188 { OPTION_RECONF_MSG, "Reconfigure Message" },
189 { OPTION_RECONF_ACCEPT, "Reconfigure Accept" },
190 { OPTION_SIP_SERVER_D, "SIP Server Domain Name List" },
191 { OPTION_SIP_SERVER_A, "SIP Servers IPv6 Address List" },
192 { OPTION_DNS_SERVERS, "DNS recursive name server" },
193 { OPTION_DOMAIN_LIST, "Domain Search List" },
194 { OPTION_IA_PD, "Identity Association for Prefix Delegation" },
195 { OPTION_IAPREFIX, "IA Prefix" },
196 { OPTION_NIS_SERVERS, "Network Information Server" },
197 { OPTION_NISP_SERVERS, "Network Information Server V2" },
198 { OPTION_NIS_DOMAIN_NAME, "Network Information Server Domain Name" },
199 { OPTION_NISP_DOMAIN_NAME,"Network Information Server V2 Domain Name" },
200 { OPTION_SNTP_SERVERS, "Simple Network Time Protocol Server" },
201 { OPTION_LIFETIME, "Lifetime" },
202 { OPTION_BCMCS_SERVER_D, "BCMCS Server Domain" },
203 { OPTION_BCMCS_SERVER_A, "BCMCS Servers IPv6 Address List" },
204 { OPTION_GEOCONF_CIVIC, "Geoconf Civic Address" },
205 { OPTION_REMOTE_ID, "Remote Identifier" },
206 { OPTION_SUBSCRIBER_ID, "Subscriber Identifier" },
207 { OPTION_CLIENT_FQDN, "Fully Qualified Domain Name" },
208 { OPTION_PANA_AGENT, "PANA Agents IPv6 Address List" },
209 { OPTION_TIME_ZONE, "Time Zone" },
210 { OPTION_TZDB, "Time Zone Database" },
211 { OPTION_ERO, "Echo Request Option" },
212 { OPTION_LQ_QUERY, "Leasequery Query" },
213 { OPTION_CLIENT_DATA, "Leasequery Client Data" },
214 { OPTION_CLT_TIME, "Client Last Transaction Time" },
215 { OPTION_LQ_RELAY_DATA, "Leasequery Relay Data" },
216 { OPTION_LQ_CLIENT_LINK, "Leasequery Client Link Address List" },
217 { OPTION_CAPWAP_AC_V6, "CAPWAP Access Controllers" },
218 { OPTION_MIP6_HA, "Mobile IPv6 Home Agent" },
219 { OPTION_MIP6_HOA, "Mobile IPv6 Home Address" },
220 { OPTION_NAI, "Network Access Identifier" },
224 static const value_string statuscode_vals[] =
231 {5, "UseMulticast" },
232 {6, "NoPrefixAvail" },
233 {7, "UnknownQueryType" },
234 {8, "MalformedQuery" },
235 {9, "NotConfigured" },
240 static const value_string duidtype_vals[] =
242 { DUID_LLT, "link-layer address plus time" },
243 { DUID_EN, "assigned by vendor based on Enterprise number" },
244 { DUID_LL, "link-layer address" },
245 { DUID_LL_OLD, "link-layer address (old)" },
249 /* This FQDN draft is a mess, I've tried to understand,
250 but N,O,S bit descriptions are really cryptic */
251 static const true_false_string fqdn_n = {
252 /* "Client doesn't want server to perform DNS update", "" */
253 "N bit set","N bit cleared"
256 static const true_false_string fqdn_o = {
257 "O bit set", "O bit cleared"
260 static const true_false_string fqdn_s = {
261 /* "Forward mapping (FQDN-to-IPv6, AAAA) performed by client",
262 "Forward mapping (FQDN-to-IPv6, AAAA) performed by server" */
263 "S bit set", "S bit cleared"
267 dhcpv6_enterprise_number(proto_tree * subtree, tvbuff_t *tvb, int offset)
269 guint32 enterprise_number;
270 enterprise_number = tvb_get_ntohl(tvb, offset);
271 proto_tree_add_text(subtree, tvb, offset, 4,
272 "Enterprise-number: %s (%u)",
273 val_to_str(enterprise_number, sminmpec_values, "%u"),
279 dhcpv6_domain(proto_tree * subtree, tvbuff_t *tvb, int offset, guint16 optlen)
281 int start_offset=offset;
288 /* this is the start of the domain name */
294 /* read length of the next substring */
295 len = tvb_get_guint8(tvb, offset);
296 /* Microsoft dhcpv6 clients aren't currently RFC 4704 conform: They send an
297 * ASCII string instead of a DNS record encoded domain name. Catch that case
298 * to allow us to continue after such a malformed record.
300 if ( optlen < len ) {
301 proto_tree_add_text(subtree, tvb, start_offset, optlen, "Malformed DNS name record (MS Vista client?)");
306 /* if len==0 and pos>0 we have read an entire domain string */
309 /* empty string, this must be an error? */
310 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Malformed option");
313 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Domain: %s", domain);
319 /* add the substring to domain */
325 /* too long string, this must be an error? */
326 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Malformed option");
329 tvb_memcpy(tvb, domain+pos, offset, len);
337 proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Domain: %s", domain);
341 /* Returns the number of bytes consumed by this option. */
343 dhcpv6_option(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bp_tree,
344 gboolean downstream, int off, int eoff, gboolean *at_end)
350 guint16 temp_optlen = 0;
353 proto_tree *subtree_2;
355 struct e_in6_addr in6;
358 /* option type and length must be present */
359 if (eoff - off < 4) {
364 opttype = tvb_get_ntohs(tvb, off);
365 optlen = tvb_get_ntohs(tvb, off + 2);
367 /* all option data must be present */
368 if (eoff - off < 4 + optlen) {
373 ti = proto_tree_add_text(bp_tree, tvb, off, 4 + optlen,
374 "%s", val_to_str(opttype, opttype_vals, "DHCP option %u"));
376 subtree = proto_item_add_subtree(ti, ett_dhcpv6_option);
377 proto_tree_add_text(subtree, tvb, off, 2, "option type: %d", opttype);
378 proto_tree_add_text(subtree, tvb, off + 2, 2, "option length: %d",
383 case OPTION_CLIENTID:
384 case OPTION_SERVERID:
386 proto_tree_add_text(subtree, tvb, off, optlen,
387 "DUID: malformed option");
390 duidtype = tvb_get_ntohs(tvb, off);
391 proto_tree_add_text(subtree, tvb, off, 2,
392 "DUID type: %s (%u)",
394 duidtype_vals, "Unknown"),
399 proto_tree_add_text(subtree, tvb, off,
400 optlen, "DUID: malformed option");
403 hwtype=tvb_get_ntohs(tvb, off + 2);
404 proto_tree_add_text(subtree, tvb, off + 2, 2,
405 "Hardware type: %s (%u)", arphrdtype_to_str(hwtype, "Unknown"),
407 /* XXX seconds since Jan 1 2000 */
408 proto_tree_add_text(subtree, tvb, off + 4, 4,
409 "Time: %u", tvb_get_ntohl(tvb, off + 4));
411 proto_tree_add_text(subtree, tvb, off + 8,
412 optlen - 8, "Link-layer address: %s",
413 arphrdaddr_to_str(tvb_get_ptr(tvb, off+8, optlen-8), optlen-8, hwtype));
418 proto_tree_add_text(subtree, tvb, off,
419 optlen, "DUID: malformed option");
422 dhcpv6_enterprise_number(subtree, tvb, off + 2);
424 buf = tvb_bytes_to_str(tvb, off + 6, optlen - 6);
425 proto_tree_add_text(subtree, tvb, off + 6,
426 optlen - 6, "identifier: %s", buf);
432 proto_tree_add_text(subtree, tvb, off,
433 optlen, "DUID: malformed option");
436 hwtype=tvb_get_ntohs(tvb, off + 2);
437 proto_tree_add_text(subtree, tvb, off + 2, 2,
438 "Hardware type: %s (%u)",
439 arphrdtype_to_str(hwtype, "Unknown"),
442 proto_tree_add_text(subtree, tvb, off + 4,
443 optlen - 4, "Link-layer address: %s",
444 arphrdaddr_to_str(tvb_get_ptr(tvb, off+4, optlen-4), optlen-4, hwtype));
452 if (opttype == OPTION_IA_NA)
453 proto_tree_add_text(subtree, tvb, off,
454 optlen, "IA_NA: malformed option");
456 proto_tree_add_text(subtree, tvb, off,
457 optlen, "IA_PD: malformed option");
460 proto_tree_add_text(subtree, tvb, off, 4,
462 tvb_get_ntohl(tvb, off));
463 if (tvb_get_ntohl(tvb, off+4) == DHCPV6_LEASEDURATION_INFINITY) {
464 proto_tree_add_text(subtree, tvb, off+4, 4,
467 proto_tree_add_text(subtree, tvb, off+4, 4,
468 "T1: %u", tvb_get_ntohl(tvb, off+4));
471 if (tvb_get_ntohl(tvb, off+8) == DHCPV6_LEASEDURATION_INFINITY) {
472 proto_tree_add_text(subtree, tvb, off+8, 4,
475 proto_tree_add_text(subtree, tvb, off+8, 4,
476 "T2: %u", tvb_get_ntohl(tvb, off+8));
480 while ((optlen - temp_optlen) > 0) {
481 temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
482 off+temp_optlen, off + optlen, at_end);
484 /* Bad option - just skip to the end */
485 temp_optlen = optlen;
491 proto_tree_add_text(subtree, tvb, off,
492 optlen, "IA_TA: malformed option");
495 proto_tree_add_text(subtree, tvb, off, 4,
497 tvb_get_ntohl(tvb, off));
499 while ((optlen - temp_optlen) > 0) {
500 temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
501 off+temp_optlen, off + optlen, at_end);
503 /* Bad option - just skip to the end */
504 temp_optlen = optlen;
510 guint32 preferred_lifetime, valid_lifetime;
513 proto_tree_add_text(subtree, tvb, off,
514 optlen, "IAADDR: malformed option");
517 tvb_get_ipv6(tvb, off, &in6);
518 proto_tree_add_text(subtree, tvb, off,
519 sizeof(in6), "IPv6 address: %s",
522 preferred_lifetime = tvb_get_ntohl(tvb, off + 16);
523 valid_lifetime = tvb_get_ntohl(tvb, off + 20);
525 if (preferred_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
526 proto_tree_add_text(subtree, tvb, off + 16, 4,
527 "Preferred lifetime: infinity");
529 proto_tree_add_text(subtree, tvb, off + 16, 4,
530 "Preferred lifetime: %u", preferred_lifetime);
532 if (valid_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
533 proto_tree_add_text(subtree, tvb, off + 20, 4,
534 "Valid lifetime: infinity");
536 proto_tree_add_text(subtree, tvb, off + 20, 4,
537 "Valid lifetime: %u", valid_lifetime);
541 while ((optlen - temp_optlen) > 0) {
542 temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
543 off+temp_optlen, off + optlen, at_end);
545 /* Bad option - just skip to the end */
546 temp_optlen = optlen;
553 for (i = 0; i < optlen; i += 2) {
554 guint16 requested_opt_code;
555 requested_opt_code = tvb_get_ntohs(tvb, off + i);
556 proto_tree_add_text(subtree, tvb, off + i,
557 2, "Requested Option code: %s (%d)",
558 val_to_str(requested_opt_code,
564 case OPTION_PREFERENCE:
566 proto_tree_add_text(subtree, tvb, off,
567 optlen, "PREFERENCE: malformed option");
570 proto_tree_add_text(subtree, tvb, off, 1,
572 (guint32)tvb_get_guint8(tvb, off));
574 case OPTION_ELAPSED_TIME:
576 proto_tree_add_text(subtree, tvb, off,
577 optlen, "ELAPSED-TIME: malformed option");
580 proto_tree_add_text(subtree, tvb, off, 2,
581 "elapsed-time: %u ms",
582 10*(guint32)tvb_get_ntohs(tvb, off));
584 case OPTION_RELAY_MSG:
586 proto_tree_add_text(subtree, tvb, off,
587 optlen, "RELAY-MSG: malformed option");
589 /* here, we should dissect a full DHCP message */
590 dissect_dhcpv6(tvb, pinfo, subtree, downstream, off, off + optlen);
595 proto_tree_add_text(subtree, tvb, off,
596 optlen, "AUTH: malformed option");
599 proto_tree_add_text(subtree, tvb, off, 1,
601 (guint32)tvb_get_guint8(tvb, off));
602 proto_tree_add_text(subtree, tvb, off+1, 1,
604 (guint32)tvb_get_guint8(tvb, off+1));
605 proto_tree_add_text(subtree, tvb, off+2, 1,
607 (guint32)tvb_get_guint8(tvb, off+2));
608 proto_tree_add_text(subtree, tvb, off+3, 8,
611 proto_tree_add_text(subtree, tvb, off+11, optlen-11,
612 "Authentication Information");
616 proto_tree_add_text(subtree, tvb, off,
617 optlen, "UNICAST: malformed option");
620 tvb_get_ipv6(tvb, off, &in6);
621 proto_tree_add_text(subtree, tvb, off,
622 sizeof(in6), "IPv6 address: %s",
625 case OPTION_STATUS_CODE:
628 char *status_message = 0;
629 status_code = tvb_get_ntohs(tvb, off);
630 proto_tree_add_text(subtree, tvb, off, 2,
631 "Status Code: %s (%d)",
632 val_to_str(status_code, statuscode_vals,
636 if (optlen - 2 > 0) {
637 status_message = tvb_get_ephemeral_string(tvb, off + 2, optlen - 2);
638 proto_tree_add_text(subtree, tvb, off + 2, optlen - 2,
639 "Status Message: %s",
644 case OPTION_VENDOR_CLASS:
646 proto_tree_add_text(subtree, tvb, off,
647 optlen, "VENDOR_CLASS: malformed option");
650 dhcpv6_enterprise_number(subtree, tvb, off);
652 buf = tvb_bytes_to_str(tvb, off + 4, optlen - 4);
653 proto_tree_add_text(subtree, tvb, off+4, optlen-4,
654 "vendor-class-data: %s", buf);
657 case OPTION_VENDOR_OPTS:
659 proto_tree_add_text(subtree, tvb, off,
660 optlen, "VENDOR_OPTS: malformed option");
664 dhcpv6_enterprise_number(subtree, tvb, off);
669 while((optlen - 4 - optoffset) > 0)
671 int olen = tvb_get_ntohs(tvb, off + optoffset + 6);
672 ti = proto_tree_add_text(subtree, tvb, off + optoffset + 4, 4 + olen, "option");
673 subtree_2 = proto_item_add_subtree(ti, ett_dhcpv6_option_vsoption);
675 proto_tree_add_text(subtree_2, tvb, off + optoffset + 4, 2, "option code: %u", tvb_get_ntohs(tvb, off + optoffset + 4));
676 proto_tree_add_text(subtree_2, tvb, off + optoffset + 6, 2, "option length: %u", olen);
677 proto_tree_add_text(subtree_2, tvb, off + optoffset + 8, olen, "option-data");
678 optoffset += (4 + olen);
682 case OPTION_INTERFACE_ID:
684 proto_tree_add_text(subtree, tvb, off,
685 optlen, "INTERFACE_ID: malformed option");
688 buf = tvb_get_ephemeral_string(tvb, off, optlen);
689 proto_tree_add_text(subtree, tvb, off, optlen, "Interface-ID: %s", buf);
691 case OPTION_RECONF_MSG:
693 proto_tree_add_text(subtree, tvb, off,
694 optlen, "RECONF_MSG: malformed option");
697 proto_tree_add_text(subtree, tvb, off, optlen,
698 "Reconfigure-type: %s",
699 val_to_str(tvb_get_guint8(tvb, off),
703 case OPTION_SIP_SERVER_D:
705 proto_tree_add_text(subtree, tvb, off, optlen,
706 "SIP Servers Domain Search List");
708 dhcpv6_domain(subtree,tvb, off, optlen);
710 case OPTION_SIP_SERVER_A:
712 proto_tree_add_text(subtree, tvb, off, optlen,
713 "SIP servers address: malformed option");
716 for (i = 0; i < optlen; i += 16) {
717 tvb_get_ipv6(tvb, off + i, &in6);
718 proto_tree_add_text(subtree, tvb, off + i,
719 sizeof(in6), "SIP servers address: %s",
723 case OPTION_DNS_SERVERS:
725 proto_tree_add_text(subtree, tvb, off, optlen,
726 "DNS servers address: malformed option");
729 for (i = 0; i < optlen; i += 16) {
730 tvb_get_ipv6(tvb, off + i, &in6);
731 proto_tree_add_text(subtree, tvb, off + i,
732 sizeof(in6), "DNS servers address: %s",
736 case OPTION_DOMAIN_LIST:
738 proto_tree_add_text(subtree, tvb, off, optlen, "DNS Domain Search List");
740 dhcpv6_domain(subtree,tvb, off, optlen);
742 case OPTION_NIS_SERVERS:
744 proto_tree_add_text(subtree, tvb, off, optlen,
745 "NIS servers address: malformed option");
748 for (i = 0; i < optlen; i += 16) {
749 tvb_get_ipv6(tvb, off + i, &in6);
750 proto_tree_add_text(subtree, tvb, off + i,
751 sizeof(in6), "NIS servers address: %s",
755 case OPTION_NISP_SERVERS:
757 proto_tree_add_text(subtree, tvb, off, optlen,
758 "NISP servers address: malformed option");
761 for (i = 0; i < optlen; i += 16) {
762 tvb_get_ipv6(tvb, off + i, &in6);
763 proto_tree_add_text(subtree, tvb, off + i,
764 sizeof(in6), "NISP servers address: %s",
768 case OPTION_NIS_DOMAIN_NAME:
770 proto_tree_add_text(subtree, tvb, off, optlen, "nis-domain-name");
772 dhcpv6_domain(subtree,tvb, off, optlen);
774 case OPTION_NISP_DOMAIN_NAME:
776 proto_tree_add_text(subtree, tvb, off, optlen, "nisp-domain-name");
778 dhcpv6_domain(subtree,tvb, off, optlen);
780 case OPTION_SNTP_SERVERS:
782 proto_tree_add_text(subtree, tvb, off, optlen,
783 "SNTP servers address: malformed option");
786 for (i = 0; i < optlen; i += 16) {
787 tvb_get_ipv6(tvb, off + i, &in6);
788 proto_tree_add_text(subtree, tvb, off + i,
789 sizeof(in6), "SNTP servers address: %s",
793 case OPTION_LIFETIME:
795 proto_tree_add_text(subtree, tvb, off,
796 optlen, "LIFETIME: malformed option");
799 proto_tree_add_text(subtree, tvb, off, 4,
801 (guint32)tvb_get_ntohl(tvb, off));
803 case OPTION_BCMCS_SERVER_D:
805 proto_tree_add_text(subtree, tvb, off, optlen,
806 "BCMCS Servers Domain Search List");
808 dhcpv6_domain(subtree,tvb, off, optlen);
810 case OPTION_BCMCS_SERVER_A:
812 proto_tree_add_text(subtree, tvb, off, optlen,
813 "BCMCS servers address: malformed option");
816 for (i = 0; i < optlen; i += 16) {
817 tvb_get_ipv6(tvb, off + i, &in6);
818 proto_tree_add_text(subtree, tvb, off + i,
819 sizeof(in6), "BCMCS servers address: %s",
823 case OPTION_REMOTE_ID:
825 proto_tree_add_text(subtree, tvb, off,
826 optlen, "REMOTE_ID: malformed option");
829 dhcpv6_enterprise_number(subtree, tvb, off);
832 buf = tvb_bytes_to_str(tvb, off, optlen);
833 proto_tree_add_text(subtree, tvb, off, optlen, "Remote-ID: %s", buf);
835 case OPTION_SUBSCRIBER_ID:
837 proto_tree_add_text(subtree, tvb, off,
838 optlen, "SUBSCRIBER_ID: malformed option");
841 buf = tvb_get_ephemeral_string(tvb, off, optlen);
842 proto_tree_add_text(subtree, tvb, off, optlen, "Subscriber-ID: %s", buf);
844 case OPTION_CLIENT_FQDN:
846 proto_tree_add_text(subtree, tvb, off,
847 optlen, "FQDN: malformed option");
855 proto_tree_add_item(subtree, hf_fqdn_1, tvb, off, 1, FALSE);
856 proto_tree_add_item(subtree, hf_fqdn_2, tvb, off, 1, FALSE);
857 proto_tree_add_item(subtree, hf_fqdn_3, tvb, off, 1, FALSE);
858 proto_tree_add_item(subtree, hf_fqdn_4, tvb, off, 1, FALSE);
859 /* proto_tree_add_text(subtree, tvb, off, 1, */
861 /* (guint32)tvb_get_guint8(tvb, off)); */
862 dhcpv6_domain(subtree,tvb, off+1, (guint16) (optlen-1));
864 case OPTION_PANA_AGENT:
866 proto_tree_add_text(subtree, tvb, off, optlen,
867 "PANA agent address: malformed option");
870 for (i = 0; i < optlen; i += 16) {
871 tvb_get_ipv6(tvb, off + i, &in6);
872 proto_tree_add_text(subtree, tvb, off + i,
873 sizeof(in6), "PANA agents address: %s",
877 case OPTION_TIME_ZONE:
879 buf = tvb_get_ephemeral_string(tvb, off, optlen);
880 proto_tree_add_text(subtree, tvb, off, optlen, "time-zone: %s", buf);
885 buf = tvb_get_ephemeral_string(tvb, off, optlen);
886 proto_tree_add_text(subtree, tvb, off, optlen, "tz-database: %s", buf);
889 case OPTION_LQ_QUERY:
892 struct e_in6_addr in6_local;
895 proto_tree_add_text(subtree, tvb, off, optlen,
896 "LQ-QUERY: malformed option");
899 query_type = tvb_get_guint8(tvb, off);
900 switch (query_type) {
902 proto_tree_add_text(subtree, tvb, off, 1,
903 "Query-type: %s (%u)",
904 "by-address", query_type);
907 proto_tree_add_text(subtree, tvb, off, 1,
908 "Query-type: %s (%u)",
909 "by-clientID", query_type);
912 proto_tree_add_text(subtree, tvb, off, 1,
913 "Query-type: %s (%u)",
914 "unknown?", query_type);
917 tvb_get_ipv6(tvb, off + 1, &in6_local);
918 proto_tree_add_text(subtree, tvb, off + 1, 16,
919 "Link address: %s", ip6_to_str(&in6_local));
921 while ((optlen - temp_optlen) > 0) {
922 temp_optlen += dhcpv6_option(tvb, pinfo, subtree,
923 downstream, off + temp_optlen,
924 off + optlen, at_end);
926 /* Bad option - just skip to the end */
927 temp_optlen = optlen;
932 case OPTION_CLIENT_DATA:
934 while ((optlen - temp_optlen) > 0) {
935 temp_optlen += dhcpv6_option(tvb, pinfo, subtree,
936 downstream, off + temp_optlen,
937 off + optlen, at_end);
939 /* Bad option - just skip to the end */
940 temp_optlen = optlen;
944 case OPTION_CLT_TIME:
946 proto_tree_add_text(subtree, tvb, off, optlen,
947 "CLT_TIME: malformed option");
950 proto_tree_add_text(subtree, tvb, off, 4,
952 (guint32)tvb_get_ntohl(tvb, off));
954 case OPTION_LQ_RELAY_DATA:
956 proto_tree_add_text(subtree, tvb, off, optlen,
957 "LQ_RELAY_DATA: malformed option");
960 tvb_get_ipv6(tvb, off, &in6);
961 proto_tree_add_text(subtree, tvb, off, 16,
962 "Peer address: %s", ip6_to_str(&in6));
963 proto_tree_add_text(subtree, tvb, off + 16, optlen - 16,
964 "DHCPv6 relay message");
966 case OPTION_LQ_CLIENT_LINK:
968 proto_tree_add_text(subtree, tvb, off, optlen,
969 "LQ client links address: malformed option");
972 for (i = 0; i < optlen; i += 16) {
973 tvb_get_ipv6(tvb, off + i, &in6);
974 proto_tree_add_text(subtree, tvb, off + i,
975 sizeof(in6), "LQ client links address: %s",
979 case OPTION_CAPWAP_AC_V6:
981 proto_tree_add_text(subtree, tvb, off, optlen,
982 "CAPWAP Access Controllers address: malformed option");
985 for (i = 0; i < optlen; i += 16) {
986 tvb_get_ipv6(tvb, off + i, &in6);
987 proto_tree_add_text(subtree, tvb, off + i,
988 sizeof(in6), "CAPWAP Access Controllers address: %s",
992 case OPTION_IAPREFIX:
994 guint32 preferred_lifetime, valid_lifetime;
995 guint8 prefix_length;
996 struct e_in6_addr in6_local;
999 proto_tree_add_text(subtree, tvb, off,
1000 optlen, "IAPREFIX: malformed option");
1004 preferred_lifetime = tvb_get_ntohl(tvb, off);
1005 valid_lifetime = tvb_get_ntohl(tvb, off + 4);
1006 prefix_length = tvb_get_guint8(tvb, off + 8);
1007 if (preferred_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
1008 proto_tree_add_text(subtree, tvb, off, 4,
1009 "Preferred lifetime: infinity");
1011 proto_tree_add_text(subtree, tvb, off, 4,
1012 "Preferred lifetime: %u", preferred_lifetime);
1014 if (valid_lifetime == DHCPV6_LEASEDURATION_INFINITY) {
1015 proto_tree_add_text(subtree, tvb, off + 4, 4,
1016 "Valid lifetime: infinity");
1018 proto_tree_add_text(subtree, tvb, off + 4, 4,
1019 "Valid lifetime: %u", valid_lifetime);
1021 proto_tree_add_text(subtree, tvb, off + 8, 1,
1022 "Prefix length: %d", prefix_length);
1023 tvb_get_ipv6(tvb, off + 9, &in6_local);
1024 proto_tree_add_text(subtree, tvb, off + 9,
1025 16, "Prefix address: %s",
1026 ip6_to_str(&in6_local));
1029 while ((optlen - temp_optlen) > 0) {
1030 temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
1031 off+temp_optlen, off + optlen, at_end);
1033 /* Bad option - just skip to the end */
1034 temp_optlen = optlen;
1039 case OPTION_MIP6_HA:
1041 proto_tree_add_text(subtree, tvb, off, optlen,
1042 "MIP6_HA: malformed option");
1046 tvb_get_ipv6(tvb, off, &in6);
1047 proto_tree_add_text(subtree, tvb, off,
1048 16, "Home Agent: %s", ip6_to_str(&in6));
1050 case OPTION_MIP6_HOA:
1052 proto_tree_add_text(subtree, tvb, off, optlen,
1053 "MIP6_HOA: malformed option");
1057 tvb_get_ipv6(tvb, off, &in6);
1058 proto_tree_add_text(subtree, tvb, off,
1059 16, "Home Address: %s", ip6_to_str(&in6));
1063 proto_tree_add_text(subtree, tvb, off, optlen,
1064 "NAI: malformed option");
1067 proto_tree_add_text(subtree, tvb, off, optlen,
1068 "NAI : %s", tvb_get_ptr(tvb, off, optlen - 2));
1077 dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1078 gboolean downstream, int off, int eoff)
1080 proto_tree *bp_tree = NULL;
1082 guint8 msgtype, hop_count ;
1084 struct e_in6_addr in6;
1087 downstream = 0; /* feature reserved */
1089 msgtype = tvb_get_guint8(tvb, off);
1092 ti = proto_tree_add_item(tree, proto_dhcpv6, tvb, 0, -1, FALSE);
1093 bp_tree = proto_item_add_subtree(ti, ett_dhcpv6);
1096 if (msgtype == RELAY_FORW || msgtype == RELAY_REPLY) {
1099 if (check_col(pinfo->cinfo, COL_INFO)) {
1100 col_add_str(pinfo->cinfo, COL_INFO,
1103 "Message Type %u"));
1107 proto_tree_add_uint(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1, msgtype);
1109 hop_count = tvb_get_guint8(tvb, off+1);
1110 proto_tree_add_text(bp_tree, tvb, off+1, 1, "Hop count: %d", hop_count);
1112 tvb_get_ipv6(tvb, off+2, &in6);
1113 proto_tree_add_text(bp_tree, tvb, off+2, sizeof(in6),
1114 "Link-address: %s",ip6_to_str(&in6));
1116 tvb_get_ipv6(tvb, off+18, &in6);
1117 proto_tree_add_text(bp_tree, tvb, off+18, sizeof(in6),
1118 "Peer-address: %s",ip6_to_str(&in6));
1123 xid = tvb_get_ntohl(tvb, off) & 0x00ffffff;
1126 if (check_col(pinfo->cinfo, COL_INFO)) {
1127 col_add_str(pinfo->cinfo, COL_INFO,
1130 "Message Type %u"));
1135 proto_tree_add_uint(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1,
1137 proto_tree_add_text(bp_tree, tvb, off+1, 3, "Transaction-ID: 0x%08x", xid);
1139 tvb_get_ipv6(tvb, 4, &in6);
1140 proto_tree_add_text(bp_tree, tvb, 4, sizeof(in6),
1141 "Server address: %s", ip6_to_str(&in6));
1149 while (off < eoff && !at_end)
1150 off += dhcpv6_option(tvb, pinfo, bp_tree, downstream, off, eoff, &at_end);
1154 dissect_dhcpv6_downstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1156 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1157 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
1158 if (check_col(pinfo->cinfo, COL_INFO))
1159 col_clear(pinfo->cinfo, COL_INFO);
1160 dissect_dhcpv6(tvb, pinfo, tree, TRUE, 0, tvb_reported_length(tvb));
1164 dissect_dhcpv6_upstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1166 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1167 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
1168 if (check_col(pinfo->cinfo, COL_INFO))
1169 col_clear(pinfo->cinfo, COL_INFO);
1170 dissect_dhcpv6(tvb, pinfo, tree, FALSE, 0, tvb_reported_length(tvb));
1175 proto_register_dhcpv6(void)
1177 static hf_register_info hf[] = {
1179 { &hf_dhcpv6_msgtype,
1180 { "Message type", "dhcpv6.msgtype", FT_UINT8,
1181 BASE_DEC, VALS(msgtype_vals), 0x0,
1184 { "Reserved", "dhcpv6.msgtype.reserved", FT_UINT8, BASE_HEX, NULL, 0xF8, "", HFILL}},
1186 { "N", "dhcpv6.msgtype.n", FT_BOOLEAN, 8, TFS(&fqdn_n), 0x4, "", HFILL}},
1188 { "O", "dhcpv6.msgtype.o", FT_BOOLEAN, 8, TFS(&fqdn_o), 0x2, "", HFILL}},
1190 { "S", "dhcpv6.msgtype.s", FT_BOOLEAN, 8, TFS(&fqdn_s), 0x1, "", HFILL}}
1193 static gint *ett[] = {
1196 &ett_dhcpv6_option_vsoption,
1199 proto_dhcpv6 = proto_register_protocol("DHCPv6", "DHCPv6", "dhcpv6");
1200 proto_register_field_array(proto_dhcpv6, hf, array_length(hf));
1201 proto_register_subtree_array(ett, array_length(ett));
1203 /* Allow other dissectors to find this one by name.
1204 Just choose upstream version for now as they are identical. */
1205 register_dissector("dhcpv6", dissect_dhcpv6_upstream, proto_dhcpv6);
1209 proto_reg_handoff_dhcpv6(void)
1211 dissector_handle_t dhcpv6_handle;
1213 dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_downstream,
1215 dissector_add("udp.port", UDP_PORT_DHCPV6_DOWNSTREAM, dhcpv6_handle);
1216 dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_upstream,
1218 dissector_add("udp.port", UDP_PORT_DHCPV6_UPSTREAM, dhcpv6_handle);