/* packet-dhpcv6.c
* Routines for DHCPv6 packet disassembly
+ * Copyright 2004, Nicolas DICHTEL - 6WIND - <nicolas.dichtel@6wind.com>
* Jun-ichiro itojun Hagino <itojun@iijlab.net>
* IItom Tsutomu MIENO <iitom@utouto.com>
* SHIRASAKI Yasuhiro <yasuhiro@gnome.gr.jp>
* $Id$
*
* The information used comes from:
- * RFC3315.txt
- * RFC3319.txt
- * RFC3633.txt
- * RFC3646.txt
- * draft-ietf-dhc-dhcpv6-opt-nisconfig-02.txt
- * draft-ietf-dhc-dhcpv6-opt-timeconfig-02.txt
+ * RFC3315.txt (DHCPv6)
+ * RFC3319.txt (SIP options)
+ * RFC3633.txt (Prefix options)
+ * RFC3646.txt (DNS servers/domains)
+ * RFC3898.txt (NIS options)
+ * draft-ietf-dhc-dhcpv6-opt-timeconfig-03.txt
+ * draft-ietf-dhc-dhcpv6-opt-fqdn-00.txt
+ * draft-ietf-dhc-dhcpv6-opt-lifetime-00.txt
+ *
* Note that protocol constants are still subject to change, based on IANA
* assignment decisions.
*
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
#include <string.h>
#include <glib.h>
#include <epan/packet.h>
-#include <epan/ipv6-utils.h>
+#include "packet-arp.h"
static int proto_dhcpv6 = -1;
static int hf_dhcpv6_msgtype = -1;
+static int hf_fqdn_1 = -1;
+static int hf_fqdn_2 = -1;
+static int hf_fqdn_3 = -1;
+static int hf_fqdn_4 = -1;
-static guint ett_dhcpv6 = -1;
-static guint ett_dhcpv6_option = -1;
+static gint ett_dhcpv6 = -1;
+static gint ett_dhcpv6_option = -1;
#define UDP_PORT_DHCPV6_DOWNSTREAM 546
#define UDP_PORT_DHCPV6_UPSTREAM 547
#define OPTION_DOMAIN_LIST 24
#define OPTION_IA_PD 25
#define OPTION_IAPREFIX 26
+#define OPTION_NIS_SERVERS 27
+#define OPTION_NISP_SERVERS 28
+#define OPTION_NIS_DOMAIN_NAME 29
+#define OPTION_NISP_DOMAIN_NAME 30
/*
* The followings are unassigned numbers.
*/
-#define OPTION_NIS_SERVERS 35
-#define OPTION_NISP_SERVERS 36
-#define OPTION_NIS_DOMAIN_NAME 37
-#define OPTION_NISP_DOMAIN_NAME 38
-#define OPTION_NTP_SERVERS 40
+#define OPTION_CLIENT_FQDN 34
+#define OPTION_SNTP_SERVERS 40
#define OPTION_TIME_ZONE 41
+#define OPTION_LIFETIME 42
+
+/* temporary value until defined by IETF */
+#define OPTION_MIP6_HA 165
+#define OPTION_MIP6_HOA 166
+#define OPTION_NAI 167
#define DUID_LLT 1
#define DUID_EN 2
#define DUID_LL 3
#define DUID_LL_OLD 4
+static void
+dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ gboolean downstream, int off, int eoff);
+
static const value_string msgtype_vals[] = {
{ SOLICIT, "Solicit" },
{ ADVERTISE, "Advertise" },
static const value_string opttype_vals[] = {
{ OPTION_CLIENTID, "Client Identifier" },
{ OPTION_SERVERID, "Server Identifier" },
- { OPTION_IA_NA, "Identify Association" },
- { OPTION_IA_TA, "Identify Association for Temporary Address" },
+ { OPTION_IA_NA, "Identity Association for Non-temporary Address" },
+ { OPTION_IA_TA, "Identity Association for Temporary Address" },
{ OPTION_IAADDR, "IA Address" },
{ OPTION_ORO, "Option Request" },
{ OPTION_PREFERENCE, "Preference" },
{ OPTION_SIP_SERVER_A, "SIP Servers IPv6 Address List" },
{ OPTION_DNS_SERVERS, "DNS recursive name server" },
{ OPTION_DOMAIN_LIST, "Domain Search List" },
- { OPTION_IA_PD, "Identify Association for Prefix Delegation" },
+ { OPTION_IA_PD, "Identity Association for Prefix Delegation" },
{ OPTION_IAPREFIX, "IA Prefix" },
{ OPTION_NIS_SERVERS, "Network Information Server" },
{ OPTION_NISP_SERVERS, "Network Information Server V2" },
{ OPTION_NIS_DOMAIN_NAME, "Network Information Server Domain Name" },
{ OPTION_NISP_DOMAIN_NAME,"Network Information Server V2 Domain Name" },
- { OPTION_NTP_SERVERS, "Network Time Protocol Server" },
+ { OPTION_SNTP_SERVERS, "Simple Network Time Protocol Server" },
{ OPTION_TIME_ZONE, "Time zone" },
+ { OPTION_LIFETIME, "Lifetime" },
+ { OPTION_CLIENT_FQDN, "Fully Qualified Domain Name" },
+ { OPTION_MIP6_HA, "Mobile IPv6 Home Agent" },
+ { OPTION_MIP6_HOA, "Mobile IPv6 Home Address" },
+ { OPTION_NAI, "Network Access Identifier" },
{ 0, NULL }
};
{ 0, NULL }
};
+/* This FQDN draft is a mess, I've tried to understand,
+ but N,O,S bit descriptions are really cryptic */
+static const true_false_string fqdn_n = {
+/* "Client doesn't want server to perform DNS update", "" */
+ "N bit set","N bit cleared"
+};
+
+static const true_false_string fqdn_o = {
+ "O bit set", "O bit cleared"
+};
+
+static const true_false_string fqdn_s = {
+/* "Forward mapping (FQDN-to-IPv6, AAAA) performed by client",
+ "Forward mapping (FQDN-to-IPv6, AAAA) performed by server" */
+ "S bit set", "S bit cleared"
+};
+
+/* Adds domain */
+static void
+dhcpv6_domain(proto_tree * subtree, tvbuff_t *tvb, int offset, guint16 optlen)
+{
+ int start_offset=offset;
+ char domain[256];
+ int pos;
+ guint8 len;
+
+ pos=0;
+ while(optlen){
+ /* this is the start of the domain name */
+ if(!pos){
+ start_offset=offset;
+ }
+ domain[pos]=0;
+
+ /* read length of the next substring */
+ len = tvb_get_guint8(tvb, offset);
+ offset++;
+ optlen--;
+
+ /* if len==0 and pos>0 we have read an entire domain string */
+ if(!len){
+ if(!pos){
+ /* empty string, this must be an error? */
+ proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Malformed option");
+ return;
+ } else {
+ proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Domain: %s", domain);
+ pos=0;
+ continue;
+ }
+ }
+
+ /* add the substring to domain */
+ if(pos){
+ domain[pos]='.';
+ pos++;
+ }
+ if(pos+len>254){
+ /* too long string, this must be an error? */
+ proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Malformed option");
+ return;
+ }
+ tvb_memcpy(tvb, domain+pos, offset, len);
+ pos+=len;
+ offset+=len;
+ optlen-=len;
+ }
+
+ if(pos){
+ domain[pos]=0;
+ proto_tree_add_text(subtree, tvb, start_offset, offset-start_offset, "Domain: %s", domain);
+ }
+}
+
/* Returns the number of bytes consumed by this option. */
static int
-dhcpv6_option(tvbuff_t *tvb, proto_tree *bp_tree, int off, int eoff,
- gboolean *at_end)
+dhcpv6_option(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bp_tree,
+ gboolean downstream, int off, int eoff, gboolean *at_end)
{
+ guint8 *buf;
guint16 opttype;
guint16 optlen;
+ guint16 hwtype;
guint16 temp_optlen = 0;
proto_item *ti;
proto_tree *subtree;
optlen, "DUID: malformed option");
break;
}
- /* XXX seconds since Jan 1 2000 */
+ hwtype=tvb_get_ntohs(tvb, off + 2);
proto_tree_add_text(subtree, tvb, off + 2, 2,
- "Hardware type: %u",
- tvb_get_ntohs(tvb, off + 2));
+ "Hardware type: %s (%u)",
+ arphrdtype_to_str(hwtype, "Unknown"),
+ hwtype);
+ /* XXX seconds since Jan 1 2000 */
proto_tree_add_text(subtree, tvb, off + 4, 4,
"Time: %u", tvb_get_ntohl(tvb, off + 4));
if (optlen > 8) {
proto_tree_add_text(subtree, tvb, off + 8,
- optlen - 8, "Link-layer address");
+ optlen - 8, "Link-layer address: %s",
+ arphrdaddr_to_str(tvb_get_ptr(tvb, off+8, optlen-8), optlen-8, hwtype));
}
break;
case DUID_EN:
optlen, "DUID: malformed option");
break;
}
+ hwtype=tvb_get_ntohs(tvb, off + 2);
proto_tree_add_text(subtree, tvb, off + 2, 2,
- "Hardware type: %u",
- tvb_get_ntohs(tvb, off + 2));
+ "Hardware type: %s (%u)",
+ arphrdtype_to_str(hwtype, "Unknown"),
+ hwtype);
if (optlen > 4) {
proto_tree_add_text(subtree, tvb, off + 4,
- optlen - 4, "Link-layer address");
+ optlen - 4, "Link-layer address: %s",
+ arphrdaddr_to_str(tvb_get_ptr(tvb, off+4, optlen-4), optlen-4, hwtype));
}
break;
}
proto_tree_add_text(subtree, tvb, off, 4,
"IAID: %u",
tvb_get_ntohl(tvb, off));
- proto_tree_add_text(subtree, tvb, off+4, 4,
- "T1: %u", tvb_get_ntohl(tvb, off+4));
- proto_tree_add_text(subtree, tvb, off+8, 4,
- "T2: %u", tvb_get_ntohl(tvb, off+8));
+ if (tvb_get_ntohl(tvb, off+4) == DHCPV6_LEASEDURATION_INFINITY) {
+ proto_tree_add_text(subtree, tvb, off+4, 4,
+ "T1: infinity");
+ } else {
+ proto_tree_add_text(subtree, tvb, off+4, 4,
+ "T1: %u", tvb_get_ntohl(tvb, off+4));
+ }
+
+ if (tvb_get_ntohl(tvb, off+8) == DHCPV6_LEASEDURATION_INFINITY) {
+ proto_tree_add_text(subtree, tvb, off+8, 4,
+ "T2: infinity");
+ } else {
+ proto_tree_add_text(subtree, tvb, off+8, 4,
+ "T2: %u", tvb_get_ntohl(tvb, off+8));
+ }
temp_optlen = 12;
while ((optlen - temp_optlen) > 0) {
- temp_optlen += dhcpv6_option(tvb, subtree, off+temp_optlen,
- off + optlen, at_end);
+ temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
+ off+temp_optlen, off + optlen, at_end);
if (*at_end) {
/* Bad option - just skip to the end */
temp_optlen = optlen;
tvb_get_ntohl(tvb, off));
temp_optlen = 4;
while ((optlen - temp_optlen) > 0) {
- temp_optlen += dhcpv6_option(tvb, subtree, off+temp_optlen,
- off + optlen, at_end);
+ temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
+ off+temp_optlen, off + optlen, at_end);
if (*at_end) {
/* Bad option - just skip to the end */
temp_optlen = optlen;
optlen, "IAADDR: malformed option");
break;
}
- tvb_memcpy(tvb, (guint8 *)&in6, off, sizeof(in6));
+ tvb_get_ipv6(tvb, off, &in6);
proto_tree_add_text(subtree, tvb, off,
sizeof(in6), "IPv6 address: %s",
ip6_to_str(&in6));
temp_optlen = 24;
while ((optlen - temp_optlen) > 0) {
- temp_optlen += dhcpv6_option(tvb, subtree, off+temp_optlen,
- off + optlen, at_end);
+ temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
+ off+temp_optlen, off + optlen, at_end);
if (*at_end) {
/* Bad option - just skip to the end */
temp_optlen = optlen;
break;
}
proto_tree_add_text(subtree, tvb, off, 2,
- "elapsed-time: %d sec",
- (guint32)tvb_get_ntohs(tvb, off));
+ "elapsed-time: %u ms",
+ 10*(guint32)tvb_get_ntohs(tvb, off));
break;
case OPTION_RELAY_MSG:
if (optlen == 0) {
proto_tree_add_text(subtree, tvb, off,
optlen, "RELAY-MSG: malformed option");
- break;
} else {
- /* XXX - shouldn't we be dissecting a full DHCP message
- here? */
- dhcpv6_option(tvb, subtree, off, off + optlen, at_end);
- if (*at_end)
- return 0;
+ /* here, we should dissect a full DHCP message */
+ dissect_dhcpv6(tvb, pinfo, subtree, downstream, off, off + optlen);
}
break;
case OPTION_AUTH:
- if (optlen < 15) {
+ if (optlen < 11) {
proto_tree_add_text(subtree, tvb, off,
optlen, "AUTH: malformed option");
break;
"RDM: %d",
(guint32)tvb_get_guint8(tvb, off+2));
proto_tree_add_text(subtree, tvb, off+3, 8,
- "Reply Detection");
- proto_tree_add_text(subtree, tvb, off+11, optlen-11,
- "Authentication Information");
+ "Replay Detection");
+ if (optlen != 11)
+ proto_tree_add_text(subtree, tvb, off+11, optlen-11,
+ "Authentication Information");
break;
case OPTION_UNICAST:
if (optlen != 16) {
optlen, "UNICAST: malformed option");
break;
}
- tvb_memcpy(tvb, (guint8 *)&in6, off, sizeof(in6));
+ tvb_get_ipv6(tvb, off, &in6);
proto_tree_add_text(subtree, tvb, off,
sizeof(in6), "IPv6 address: %s",
ip6_to_str(&in6));
status_code);
if (optlen - 2 > 0) {
- status_message = tvb_get_string(tvb, off + 2, optlen - 2);
+ status_message = tvb_get_ephemeral_string(tvb, off + 2, optlen - 2);
proto_tree_add_text(subtree, tvb, off + 2, optlen - 2,
"Status Message: %s",
status_message);
- g_free(status_message);
}
}
break;
proto_tree_add_text(subtree, tvb, off, optlen,
"SIP Servers Domain Search List");
}
+ dhcpv6_domain(subtree,tvb, off, optlen);
+ break;
case OPTION_SIP_SERVER_A:
if (optlen % 16) {
proto_tree_add_text(subtree, tvb, off, optlen,
break;
}
for (i = 0; i < optlen; i += 16) {
- tvb_memcpy(tvb, (guint8 *)&in6, off + i, sizeof(in6));
+ tvb_get_ipv6(tvb, off + i, &in6);
proto_tree_add_text(subtree, tvb, off + i,
sizeof(in6), "SIP servers address: %s",
ip6_to_str(&in6));
break;
}
for (i = 0; i < optlen; i += 16) {
- tvb_memcpy(tvb, (guint8 *)&in6, off + i, sizeof(in6));
+ tvb_get_ipv6(tvb, off + i, &in6);
proto_tree_add_text(subtree, tvb, off + i,
sizeof(in6), "DNS servers address: %s",
ip6_to_str(&in6));
if (optlen > 0) {
proto_tree_add_text(subtree, tvb, off, optlen, "DNS Domain Search List");
}
+ dhcpv6_domain(subtree,tvb, off, optlen);
break;
case OPTION_NIS_SERVERS:
if (optlen % 16) {
break;
}
for (i = 0; i < optlen; i += 16) {
- tvb_memcpy(tvb, (guint8 *)&in6, off + i, sizeof(in6));
+ tvb_get_ipv6(tvb, off + i, &in6);
proto_tree_add_text(subtree, tvb, off + i,
sizeof(in6), "NIS servers address: %s",
ip6_to_str(&in6));
break;
}
for (i = 0; i < optlen; i += 16) {
- tvb_memcpy(tvb, (guint8 *)&in6, off + i, sizeof(in6));
+ tvb_get_ipv6(tvb, off + i, &in6);
proto_tree_add_text(subtree, tvb, off + i,
sizeof(in6), "NISP servers address: %s",
ip6_to_str(&in6));
if (optlen > 0) {
proto_tree_add_text(subtree, tvb, off, optlen, "nis-domain-name");
}
+ dhcpv6_domain(subtree,tvb, off, optlen);
break;
case OPTION_NISP_DOMAIN_NAME:
if (optlen > 0) {
proto_tree_add_text(subtree, tvb, off, optlen, "nisp-domain-name");
}
+ dhcpv6_domain(subtree,tvb, off, optlen);
break;
- case OPTION_NTP_SERVERS:
+ case OPTION_SNTP_SERVERS:
if (optlen % 16) {
proto_tree_add_text(subtree, tvb, off, optlen,
- "NTP servers address: malformed option");
+ "SNTP servers address: malformed option");
break;
}
for (i = 0; i < optlen; i += 16) {
- tvb_memcpy(tvb, (guint8 *)&in6, off + i, sizeof(in6));
+ tvb_get_ipv6(tvb, off + i, &in6);
proto_tree_add_text(subtree, tvb, off + i,
- sizeof(in6), "NTP servers address: %s",
+ sizeof(in6), "SNTP servers address: %s",
ip6_to_str(&in6));
}
break;
case OPTION_TIME_ZONE:
if (optlen > 0) {
- proto_tree_add_text(subtree, tvb, off, optlen, "time-zone");
+ buf = tvb_get_ephemeral_string(tvb, off, optlen);
+ proto_tree_add_text(subtree, tvb, off, optlen, "time-zone: %s", buf);
+ }
+ break;
+ case OPTION_LIFETIME:
+ if (optlen != 4) {
+ proto_tree_add_text(subtree, tvb, off,
+ optlen, "LIFETIME: malformed option");
+ break;
+ }
+ proto_tree_add_text(subtree, tvb, off, 4,
+ "Lifetime: %d",
+ (guint32)tvb_get_ntohl(tvb, off));
+ break;
+ case OPTION_CLIENT_FQDN:
+ if (optlen < 1) {
+ proto_tree_add_text(subtree, tvb, off,
+ optlen, "FQDN: malformed option");
+ break;
}
+ /*
+ * +-----+-+-+-+
+ * | MBZ |N|O|S|
+ * +-----+-+-+-+
+ */
+ proto_tree_add_item(subtree, hf_fqdn_1, tvb, off, 1, FALSE);
+ proto_tree_add_item(subtree, hf_fqdn_2, tvb, off, 1, FALSE);
+ proto_tree_add_item(subtree, hf_fqdn_3, tvb, off, 1, FALSE);
+ proto_tree_add_item(subtree, hf_fqdn_4, tvb, off, 1, FALSE);
+/* proto_tree_add_text(subtree, tvb, off, 1, */
+/* "flags: %d", */
+/* (guint32)tvb_get_guint8(tvb, off)); */
+ dhcpv6_domain(subtree,tvb, off+1, (guint16) (optlen-1));
break;
+
case OPTION_IAPREFIX:
{
guint32 preferred_lifetime, valid_lifetime;
}
proto_tree_add_text(subtree, tvb, off + 8, 1,
"Prefix length: %d", prefix_length);
- tvb_memcpy(tvb, (guint8 *)&in6, off + 9 , sizeof(in6));
+ tvb_get_ipv6(tvb, off + 9, &in6);
proto_tree_add_text(subtree, tvb, off + 9,
16, "Prefix address: %s",
ip6_to_str(&in6));
temp_optlen = 25;
while ((optlen - temp_optlen) > 0) {
- temp_optlen += dhcpv6_option(tvb, subtree, off+temp_optlen,
- off + optlen, at_end);
+ temp_optlen += dhcpv6_option(tvb, pinfo, subtree, downstream,
+ off+temp_optlen, off + optlen, at_end);
if (*at_end) {
/* Bad option - just skip to the end */
temp_optlen = optlen;
}
}
break;
+ case OPTION_MIP6_HA:
+ if (optlen != 16) {
+ proto_tree_add_text(subtree, tvb, off, optlen,
+ "MIP6_HA: malformed option");
+ break;
+ }
+
+ tvb_get_ipv6(tvb, off, &in6);
+ proto_tree_add_text(subtree, tvb, off,
+ 16, "Home Agent: %s", ip6_to_str(&in6));
+ break;
+ case OPTION_MIP6_HOA:
+ if (optlen != 16) {
+ proto_tree_add_text(subtree, tvb, off, optlen,
+ "MIP6_HOA: malformed option");
+ break;
+ }
+
+ tvb_get_ipv6(tvb, off, &in6);
+ proto_tree_add_text(subtree, tvb, off,
+ 16, "Home Address: %s", ip6_to_str(&in6));
+ break;
+ case OPTION_NAI:
+ if (optlen < 4) {
+ proto_tree_add_text(subtree, tvb, off, optlen,
+ "NAI: malformed option");
+ break;
+ }
+ proto_tree_add_text(subtree, tvb, off, optlen,
+ "NAI : %s", tvb_get_ptr(tvb, off, optlen - 2));
+ break;
}
return 4 + optlen;
static void
dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
- gboolean downstream)
+ gboolean downstream, int off, int eoff)
{
proto_tree *bp_tree = NULL;
proto_item *ti;
guint8 msgtype, hop_count ;
guint32 xid;
- int off = 0;
- int eoff;
struct e_in6_addr in6;
gboolean at_end;
- gboolean relay_msg_option = FALSE;
- int length;
- eoff = tvb_reported_length(tvb);
downstream = 0; /* feature reserved */
- if (check_col(pinfo->cinfo, COL_PROTOCOL))
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
- if (check_col(pinfo->cinfo, COL_INFO))
- col_clear(pinfo->cinfo, COL_INFO);
msgtype = tvb_get_guint8(tvb, off);
bp_tree = proto_item_add_subtree(ti, ett_dhcpv6);
}
- while (msgtype == RELAY_FORW || msgtype == RELAY_REPLY) {
+ if (msgtype == RELAY_FORW || msgtype == RELAY_REPLY) {
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_set_str(pinfo->cinfo, COL_INFO,
- val_to_str(msgtype,
- msgtype_vals,
- "Message Type %u"));
- }
+ if (!off) {
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_set_str(pinfo->cinfo, COL_INFO,
+ val_to_str(msgtype,
+ msgtype_vals,
+ "Message Type %u"));
+ }
+ }
proto_tree_add_uint(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1, msgtype);
hop_count = tvb_get_guint8(tvb, off+1);
proto_tree_add_text(bp_tree, tvb, off+1, 1, "Hop count: %d", hop_count);
- tvb_memcpy(tvb, (guint8 *)&in6, off+2, sizeof(in6));
+ tvb_get_ipv6(tvb, off+2, &in6);
proto_tree_add_text(bp_tree, tvb, off+2, sizeof(in6),
"Link-address: %s",ip6_to_str(&in6));
- tvb_memcpy(tvb, (guint8 *)&in6, off+18, sizeof(in6));
+ tvb_get_ipv6(tvb, off+18, &in6);
proto_tree_add_text(bp_tree, tvb, off+18, sizeof(in6),
"Peer-address: %s",ip6_to_str(&in6));
off += 34;
- relay_msg_option = FALSE;
-
- while (!relay_msg_option && off < eoff) {
- length = dhcpv6_option(tvb, bp_tree, off, eoff, &at_end);
- if (at_end)
- return;
-
- if (tvb_get_ntohs(tvb, off) == OPTION_RELAY_MSG) {
- relay_msg_option = TRUE;
- off += 4;
- }
- else {
- if (length > 0)
- off += length;
- else {
- proto_tree_add_text(bp_tree, tvb, off, eoff, "Message: malformed");
- return;
- }
- }
- }
-
- msgtype = tvb_get_guint8(tvb, off);
- }
+ } else {
- xid = tvb_get_ntohl(tvb, off) & 0x00ffffff;
-
- if (!off) {
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_set_str(pinfo->cinfo, COL_INFO,
- val_to_str(msgtype,
- msgtype_vals,
- "Message Type %u"));
+ xid = tvb_get_ntohl(tvb, off) & 0x00ffffff;
+
+ if (!off) {
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_set_str(pinfo->cinfo, COL_INFO,
+ val_to_str(msgtype,
+ msgtype_vals,
+ "Message Type %u"));
+ }
}
- }
- if (tree) {
- proto_tree_add_uint(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1,
- msgtype);
- proto_tree_add_text(bp_tree, tvb, off+1, 3, "Transaction-ID: 0x%08x", xid);
+ if (tree) {
+ proto_tree_add_uint(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1,
+ msgtype);
+ proto_tree_add_text(bp_tree, tvb, off+1, 3, "Transaction-ID: 0x%08x", xid);
#if 0
- tvb_memcpy(tvb, (guint8 *)&in6, 4, sizeof(in6));
- proto_tree_add_text(bp_tree, tvb, 4, sizeof(in6),
- "Server address: %s", ip6_to_str(&in6));
+ tvb_get_ipv6(tvb, 4, &in6);
+ proto_tree_add_text(bp_tree, tvb, 4, sizeof(in6),
+ "Server address: %s", ip6_to_str(&in6));
#endif
- }
+ }
- off += 4;
+ off += 4;
+ }
at_end = FALSE;
while (off < eoff && !at_end)
- off += dhcpv6_option(tvb, bp_tree, off, eoff, &at_end);
+ off += dhcpv6_option(tvb, pinfo, bp_tree, downstream, off, eoff, &at_end);
}
static void
dissect_dhcpv6_downstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- dissect_dhcpv6(tvb, pinfo, tree, TRUE);
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_clear(pinfo->cinfo, COL_INFO);
+ dissect_dhcpv6(tvb, pinfo, tree, TRUE, 0, tvb_reported_length(tvb));
}
static void
dissect_dhcpv6_upstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- dissect_dhcpv6(tvb, pinfo, tree, FALSE);
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_clear(pinfo->cinfo, COL_INFO);
+ dissect_dhcpv6(tvb, pinfo, tree, FALSE, 0, tvb_reported_length(tvb));
}
proto_register_dhcpv6(void)
{
static hf_register_info hf[] = {
+
{ &hf_dhcpv6_msgtype,
{ "Message type", "dhcpv6.msgtype", FT_UINT8,
BASE_DEC, VALS(msgtype_vals), 0x0,
"", HFILL }},
+ { &hf_fqdn_1,
+ { "Reserved", "", FT_UINT8, BASE_HEX, NULL, 0xF8, "", HFILL}},
+ { &hf_fqdn_2,
+ { "N", "dhcpv6.msgtype.n", FT_BOOLEAN, 8, TFS(&fqdn_n), 0x4, "", HFILL}},
+ { &hf_fqdn_3,
+ { "O", "dhcpv6.msgtype.o", FT_BOOLEAN, 8, TFS(&fqdn_o), 0x2, "", HFILL}},
+ { &hf_fqdn_4,
+ { "S", "dhcpv6.msgtype.s", FT_BOOLEAN, 8, TFS(&fqdn_s), 0x1, "", HFILL}}
+
};
static gint *ett[] = {
&ett_dhcpv6,