2 * Routines for DHCPv6 packet disassembly
3 * Jun-ichiro itojun Hagino <itojun@iijlab.net>
5 * $Id: packet-dhcpv6.c,v 1.4 2002/01/24 09:20:47 guy Exp $
7 * The information used comes from:
8 * draft-ietf-dhc-dhcpv6-22.txt
9 * Note that protocol constants are still subject to change, based on IANA
10 * assignment decisions.
12 * Ethereal - Network traffic analyzer
13 * By Gerald Combs <gerald@ethereal.com>
14 * Copyright 1998 Gerald Combs
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
41 #include <epan/int-64bit.h>
42 #include <epan/packet.h>
43 #include <epan/ipv6-utils.h>
45 static int proto_dhcpv6 = -1;
46 static int hf_dhcpv6_msgtype = -1;
48 static guint ett_dhcpv6 = -1;
49 static guint ett_dhcpv6_option = -1;
51 #define UDP_PORT_DHCPV6_DOWNSTREAM 546
52 #define UDP_PORT_DHCPV6_UPSTREAM 547
54 static const value_string msgtype_vals[] = {
56 { 11, "Information request" },
60 static const value_string opttype_vals[] = {
62 { 11, "DNS servers address" },
66 /* Returns the number of bytes consumed by this option. */
68 dhcpv6_option(tvbuff_t *tvb, proto_tree *bp_tree, int off, int eoff,
76 struct e_in6_addr in6;
79 /* option type and length must be present */
85 opttype = tvb_get_ntohs(tvb, off);
86 optlen = tvb_get_ntohs(tvb, off + 2);
89 if (eoff - off < 4 + optlen) {
94 ti = proto_tree_add_text(bp_tree, tvb, off, 4 + optlen,
95 "%s", val_to_str(opttype, opttype_vals, "DHCP option %u"));
97 subtree = proto_item_add_subtree(ti, ett_dhcpv6_option);
98 proto_tree_add_text(subtree, tvb, off, 2, "option type: %d", opttype);
99 proto_tree_add_text(subtree, tvb, off + 2, 2, "option length: %d",
106 proto_tree_add_text(subtree, tvb, off, optlen,
107 "DUID: malformed option");
110 duidtype = tvb_get_ntohs(tvb, off);
111 proto_tree_add_text(subtree, tvb, off, 2,
112 "DUID type: %u", duidtype);
116 proto_tree_add_text(subtree, tvb, off,
117 optlen, "DUID: malformed option");
120 /* XXX seconds since Jan 1 2000 */
121 proto_tree_add_text(subtree, tvb, off + 2, 4,
122 "Time: %u", tvb_get_ntohl(tvb, off + 6));
123 proto_tree_add_text(subtree, tvb, off + 6, 2,
125 tvb_get_ntohs(tvb, off + 6));
127 proto_tree_add_text(subtree, tvb, off + 8,
128 optlen - 8, "Link-layer address");
133 proto_tree_add_text(subtree, tvb, off,
134 optlen, "DUID: malformed option");
137 proto_tree_add_text(subtree, tvb, off + 2, 8, "VUID");
139 proto_tree_add_text(subtree, tvb, off + 10,
140 optlen - 10, "Domain name");
145 proto_tree_add_text(subtree, tvb, off,
146 optlen, "DUID: malformed option");
149 proto_tree_add_text(subtree, tvb, off + 2, 2,
151 tvb_get_ntohs(tvb, off + 10));
153 proto_tree_add_text(subtree, tvb, off + 4,
154 optlen - 4, "Link-layer address");
159 case 11: /* DNS servers address */
161 proto_tree_add_text(subtree, tvb, off, optlen,
162 "DNS servers address: malformed option");
165 for (i = 0; i < optlen; i += 16) {
166 tvb_memcpy(tvb, (guint8 *)&in6, off + i, sizeof(in6));
167 proto_tree_add_text(subtree, tvb, off + i,
168 sizeof(in6), "DNS servers address: %s",
178 dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
181 proto_tree *bp_tree = NULL;
185 struct e_in6_addr in6;
189 if (check_col(pinfo->cinfo, COL_PROTOCOL))
190 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
191 if (check_col(pinfo->cinfo, COL_INFO))
192 col_clear(pinfo->cinfo, COL_INFO);
194 msgtype = tvb_get_guint8(tvb, 0);
196 /* XXX relay agent messages have to be decoded differently */
198 xid = tvb_get_ntohl(tvb, 0) & 0x00ffffff;
200 if (check_col(pinfo->cinfo, COL_INFO)) {
201 col_set_str(pinfo->cinfo, COL_INFO,
202 downstream ? "DHCPv6 reply" : "DHCPv6 request");
206 ti = proto_tree_add_item(tree, proto_dhcpv6, tvb, 0, -1, FALSE);
207 bp_tree = proto_item_add_subtree(ti, ett_dhcpv6);
209 proto_tree_add_uint(bp_tree, hf_dhcpv6_msgtype, tvb, 0, 1,
211 proto_tree_add_text(bp_tree, tvb, 1, 3, "XID: 0x%08x", xid);
212 tvb_memcpy(tvb, (guint8 *)&in6, 4, sizeof(in6));
213 proto_tree_add_text(bp_tree, tvb, 4, sizeof(in6),
214 "Server address: %s", ip6_to_str(&in6));
218 eoff = tvb_reported_length(tvb);
221 while (off < eoff && !at_end)
222 off += dhcpv6_option(tvb, bp_tree, off, eoff, &at_end);
226 dissect_dhcpv6_downstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
228 dissect_dhcpv6(tvb, pinfo, tree, TRUE);
232 dissect_dhcpv6_upstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
234 dissect_dhcpv6(tvb, pinfo, tree, FALSE);
239 proto_register_dhcpv6(void)
241 static hf_register_info hf[] = {
242 { &hf_dhcpv6_msgtype,
243 { "Message type", "dhcpv6.msgtype", FT_UINT8,
244 BASE_DEC, VALS(msgtype_vals), 0x0,
247 static gint *ett[] = {
252 proto_dhcpv6 = proto_register_protocol("DHCPv6", "DHCPv6", "dhcpv6");
253 proto_register_field_array(proto_dhcpv6, hf, array_length(hf));
254 proto_register_subtree_array(ett, array_length(ett));
258 proto_reg_handoff_dhcpv6(void)
260 dissector_handle_t dhcpv6_handle;
262 dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_downstream,
264 dissector_add("udp.port", UDP_PORT_DHCPV6_DOWNSTREAM, dhcpv6_handle);
265 dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_upstream,
267 dissector_add("udp.port", UDP_PORT_DHCPV6_UPSTREAM, dhcpv6_handle);