- Reorder some functions to avoid as many forward declarations

as possible.
- Rename a few hf_ variables
- Display some values in the COL_INFO and options caption.

svn path=/trunk/; revision=31765
This commit is contained in:
Jörg Mayer 2010-02-01 22:31:37 +00:00
parent ba32bc6d54
commit da757e0833
1 changed files with 456 additions and 455 deletions

View File

@ -55,10 +55,10 @@
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 int hf_clientfqdn_reserved = -1;
static int hf_clientfqdn_n = -1;
static int hf_clientfqdn_o = -1;
static int hf_clientfqdn_s = -1;
static int hf_option_type = -1;
static int hf_option_length = -1;
static int hf_option_value = -1;
@ -157,10 +157,6 @@ static gint ett_dhcpv6_pkt_option = -1;
#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" },
@ -363,10 +359,405 @@ static const value_string sec_tcm_vals[] = {
{ 0, NULL },
};
static void dissect_cablelabs_specific_opts(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len);
static int dissect_packetcable_ccc_option(proto_tree *v_tree, tvbuff_t *tvb, int optoff, int optend);
/* May be called recursively */
static void
dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
gboolean downstream, int off, int eoff);
/* End CableLabs Vendor Specific Options */
static int
dissect_packetcable_ccc_option(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
int optend)
{
/** THE ENCODING OF THIS SUBOPTION HAS CHANGED FROM DHCPv4
the code and length fields have grown from a single octet to
two octets each. **/
int suboptoff = optoff;
guint16 subopt, subopt_len, sec_tcm;
guint8 fetch_tgt, timer_val, type;
proto_item *vti;
proto_tree *pkt_s_tree;
guint32 ipv4_address;
guchar kr_name; /** A character in the kerberos realm name option */
guint8 kr_value; /* The integer value of the character currently being tested */
int kr_fail_flag = 0; /* Flag indicating an invalid character was found */
int kr_pos = 0; /* The position of the first invalid character */
int i = 0;
char bit_fld[24];
subopt = tvb_get_ntohs(tvb, optoff);
suboptoff += 2;
subopt_len = tvb_get_ntohs(tvb, suboptoff);
suboptoff += 2;
/* There must be at least five octets left to be a valid sub element */
if (optend <= 0) {
proto_tree_add_text(v_tree, tvb, optoff, 1,
"Sub element %d: no room left in option for suboption length",
subopt);
return (optend);
}
/* g_print("dissect packetcable ccc option subopt_len=%d optend=%d\n\n", subopt_len, optend); */
vti = proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 4,
"Sub element %u: %s: ", subopt,
val_to_str(subopt, pkt_ccc_opt_vals, "unknown/reserved") );
switch (subopt) {
case PKT_CCC_PRI_DHCP: /* IPv4 address values */
case PKT_CCC_SEC_DHCP:
if (subopt_len == 4) {
ipv4_address = tvb_get_ipv4(tvb, suboptoff);
proto_item_append_text(vti, "%s (%u byte%s%s)",
ip_to_str((guint8 *)&ipv4_address), subopt_len,
plurality(subopt_len, "", "s"),
subopt_len != 4 ? " [Invalid]" : "");
}
else {
proto_tree_add_text(vti, tvb, suboptoff, subopt_len,
"Bogus length: %d", subopt_len);
}
suboptoff += subopt_len;
break;
case PKT_CCC_IETF_PROV_SRV :
type = tvb_get_guint8(tvb, suboptoff);
/** Type 0 is FQDN **/
if (type == 0) {
proto_item_append_text(vti, "%s (%u byte%s)",
tvb_format_stringzpad(tvb, suboptoff+1, subopt_len-1),
subopt_len,
plurality(subopt_len-1, "", "s") );
}
/** Type 0 is IPv4 **/
else if (type == 1) {
if (subopt_len == 5) {
ipv4_address = tvb_get_ipv4(tvb, suboptoff+1);
proto_item_append_text(vti, "%s (%u byte%s%s)",
ip_to_str((guint8 *)&ipv4_address), subopt_len,
plurality(subopt_len, "", "s"),
subopt_len != 5 ? " [Invalid]" : "");
}
else {
proto_item_append_text(vti, "Bogus length: %d", subopt_len);
}
}
else {
proto_item_append_text(vti, "Invalid type: %u (%u byte%s)",
type, subopt_len, plurality(subopt_len, "", "s"));
}
suboptoff += subopt_len;
break;
case PKT_CCC_IETF_AS_KRB :
case PKT_CCC_IETF_AP_KRB :
if (subopt_len == 12) {
pkt_s_tree = proto_item_add_subtree(vti, ett_dhcpv6_pkt_option);
proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
"Nominal Timeout : %u", tvb_get_ntohl(tvb, suboptoff));
proto_tree_add_text(pkt_s_tree, tvb, suboptoff+4, 4,
"Maximum Timeout : %u", tvb_get_ntohl(tvb, suboptoff+4));
proto_tree_add_text(pkt_s_tree, tvb, suboptoff+8, 4,
"Maximum Retry Count : %u", tvb_get_ntohl(tvb, suboptoff+8));
}
else {
proto_item_append_text(vti, "Bogus length: %d", subopt_len);
}
suboptoff += subopt_len;
break;
case PKT_CCC_KRB_REALM:
if (subopt_len > 0) {
/** The only allowable characters are
A-Z (upper case only) 65-90
'.', 46
'/', 47
'\', 92
'=', 61
'"', 34
',', 44
and
':' 58
so loop through and
make sure it conforms to the expected syntax.
**/
for (i=0; i < subopt_len; i++) {
kr_name = tvb_get_guint8(tvb, suboptoff + i);
kr_value = (int)kr_name;
if ((kr_value >= 65 && kr_value <= 90) ||
kr_value == 34 ||
kr_value == 44 ||
kr_value == 46 ||
kr_value == 47 ||
kr_value == 58 ||
kr_value == 61 ||
kr_value == 92) {
}
else if (!kr_fail_flag) {
kr_pos = i;
kr_fail_flag = 1;
}
proto_item_append_text(vti, "%c", kr_name);
}
if (kr_fail_flag) {
proto_item_append_text(vti, " (%u byte%s [Invalid at byte=%d]) ",
subopt_len,
plurality(subopt_len, "", "s"),
kr_pos);
}
else {
proto_item_append_text(vti, " (%u byte%s%s) ",
subopt_len,
plurality(subopt_len, "", "s"),
kr_fail_flag != 0 ? " [Invalid]" : "");
}
}
suboptoff += subopt_len;
break;
case PKT_CCC_TGT_FLAG:
fetch_tgt = tvb_get_guint8(tvb, suboptoff);
proto_item_append_text(vti, "%s (%u byte%s%s)",
fetch_tgt == 1 ? "True" : "False",
subopt_len,
plurality(subopt_len, "", "s"),
subopt_len != 1 ? " [Invalid]" : "");
suboptoff += subopt_len;
break;
case PKT_CCC_PROV_TIMER:
timer_val = tvb_get_guint8(tvb, suboptoff);
/* proto_item_append_text(vti, "%u%s (%u byte%s%s)", timer_val,
timer_val > 30 ? " [Invalid]" : "", */
proto_item_append_text(vti, "%u (%u byte%s%s)", timer_val,
subopt_len,
plurality(subopt_len, "", "s"),
subopt_len != 1 ? " [Invalid]" : "");
suboptoff += subopt_len;
break;
case PKT_CCC_IETF_SEC_TKT :
sec_tcm = tvb_get_ntohs(tvb, suboptoff);
proto_item_append_text(vti, "0x%04x (%u byte%s%s)",
sec_tcm, subopt_len, plurality(subopt_len, "", "s"),
subopt_len != 2 ? " [Invalid]" : "");
if (subopt_len == 2) {
pkt_s_tree = proto_item_add_subtree(vti, ett_dhcpv6_pkt_option);
for (i=0; i< 2; i++) {
if (sec_tcm & sec_tcm_vals[i].value) {
decode_bitfield_value(bit_fld, sec_tcm, sec_tcm_vals[i].value, 16);
proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 2, "%s %s",
bit_fld, sec_tcm_vals[i].strptr);
}
}
}
suboptoff += subopt_len;
break;
default:
suboptoff += subopt_len;
break;
}
/** Return the number of bytes processed **/
return (suboptoff - optoff);
}
static void
dissect_cablelabs_specific_opts(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len)
{
guint16 type;
guint16 tlv_len; /* holds the number of elements in the tlv */
guint16 opt_len; /* holds the length of the suboption */
guint16 sub_value;
int off = voff;
int sub_off; /** The offset for the sub-option */
proto_item *ti;
int i;
int field_len; /* holds the lenght of one occurrence of a field */
proto_tree *subtree;
struct e_in6_addr in6;
if (len > 4) {
while (off - voff < len) {
/* Type */
type = tvb_get_ntohs(tvb, off);
ti = proto_tree_add_text(v_tree, tvb, off, 2,
"Suboption %d: %s", type, val_to_str(type,
cl_vendor_subopt_values, "unknown"));
/* Length */
tlv_len = tvb_get_ntohs(tvb, off+2);
/* Values */
sub_off = off + 4;
switch(type) {
/* String types */
case CL_OPTION_DEVICE_TYPE :
case CL_OPTION_DEVICE_SERIAL_NUMBER :
case CL_OPTION_HARDWARE_VERSION_NUMBER :
case CL_OPTION_SOFTWARE_VERSION_NUMBER :
case CL_OPTION_BOOT_ROM_VERSION :
case CL_OPTION_MODEL_NUMBER :
case CL_OPTION_VENDOR_NAME :
case CL_OPTION_CONFIG_FILE_NAME :
case CL_OPTION_EMBEDDED_COMPONENT_LIST :
opt_len = tlv_len;
field_len = tlv_len;
proto_item_append_text(ti, "\"%s\"",
tvb_format_stringzpad(tvb, sub_off, field_len));
break;
case CL_OPTION_ORO :
field_len = 2;
opt_len = tlv_len;
if (opt_len > 0) {
for (i = 0; i < tlv_len; i += field_len) {
sub_value = tvb_get_ntohs(tvb, sub_off);
proto_item_append_text(ti, " %d", sub_value);
sub_off += field_len;
}
}
break;
/* List of IPv6 Address */
case CL_OPTION_TFTP_SERVERS :
case CL_OPTION_SYSLOG_SERVERS :
case CL_OPTION_RFC868_SERVERS :
field_len = 16;
opt_len = tlv_len;
subtree = proto_item_add_subtree(ti, ett_dhcpv6_vendor_option);
if ((tlv_len % field_len) == 0) {
for (i = 0; i < tlv_len/field_len; i++) {
tvb_get_ipv6(tvb, sub_off, &in6);
proto_tree_add_text(subtree, tvb, sub_off,
sizeof(in6), "IPv6 address %d: %s",
i+1, ip6_to_str(&in6));
sub_off += field_len;
}
}
break;
case CL_OPTION_VENDOR_OUI :
case CL_OPTION_DEVICE_ID :
opt_len = tlv_len;
field_len = tlv_len;
if (tlv_len != 6) {
proto_item_append_text(ti, "Bogus value length=%d",
tlv_len);
}
else {
proto_item_append_text(ti, "%s",
tvb_bytes_to_str(tvb, sub_off, field_len));
}
break;
case CL_OPTION_TLV5 :
opt_len = tlv_len;
field_len = tlv_len;
proto_item_append_text(ti, "%s",
tvb_bytes_to_str(tvb, sub_off, field_len));
break;
case CL_OPTION_TIME_OFFSET :
opt_len = tlv_len;
proto_item_append_text(ti, "%d", tvb_get_ntohl(tvb, sub_off));
break;
case CL_OPTION_DOCS_CMTS_CAP :
opt_len = tlv_len;
field_len = 0;
subtree = proto_item_add_subtree(ti, ett_dhcpv6_vendor_option);
/* tlv_len contains the total length of all the TLVs for this
option */
if (tlv_len > 0) {
for (i = 0; field_len < opt_len; i++) {
int tagLen = 0;
int tag = 0;
tag = tvb_get_guint8(tvb, sub_off);
sub_off++;
tagLen = tvb_get_guint8(tvb, sub_off);
sub_off++;
if (tag == CL_OPTION_DOCS_CMTS_TLV_VERS_NUM &&
tagLen == 2) {
int major = 0;
int minor = 0;
major = tvb_get_guint8(tvb, sub_off);
sub_off++;
minor = tvb_get_guint8(tvb, sub_off);
sub_off++;
proto_tree_add_text(subtree, tvb, sub_off,
sizeof(4), "DOCSIS Version Number %d.%d",
major, minor);
}
else
sub_off += tagLen;
field_len += tagLen + 2;
}
}
else
proto_tree_add_text(subtree, tvb, sub_off,
sizeof(0), "empty");
break;
case CL_CM_MAC_ADDR :
opt_len = tlv_len;
field_len = tlv_len;
if (tlv_len != 6) {
proto_item_append_text(ti, "Bogus value length=%d",
tlv_len);
}
else {
/*proto_item_append_text(ti, "CM MAC Address Option = %s", */
proto_item_append_text(ti, "%s",
bytes_to_str_punct(tvb_get_ptr(tvb, sub_off, opt_len), opt_len, ':'));
/* tvb_bytes_to_str(tvb, sub_off, opt_len)); */
}
sub_off += field_len;
break;
case CL_EROUTER_CONTAINER_OPTION :
opt_len = tlv_len;
field_len = tlv_len;
proto_item_append_text(ti, " %s (len=%d)",
tvb_bytes_to_str(tvb, sub_off, opt_len), tlv_len);
sub_off += field_len;
break;
case CL_OPTION_CCC :
opt_len = tlv_len;
field_len = 0;
subtree = proto_item_add_subtree(ti, ett_dhcpv6_vendor_option);
proto_item_append_text(ti, " (%d bytes)", opt_len);
while (field_len < opt_len) {
sub_value = dissect_packetcable_ccc_option(subtree, tvb,
sub_off, (opt_len - field_len));
sub_off += sub_value;
field_len += sub_value;
}
sub_off += field_len;
default:
opt_len = tlv_len;
break;
}
off += (opt_len + 4);
}
}
else {
proto_tree_add_text(v_tree, tvb, off, len-off,
"Bogus length: %d", len);
}
}
/* Adds domain */
static void
@ -478,12 +869,15 @@ dhcpv6_option(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bp_tree,
switch (opttype) {
case OPTION_CLIENTID:
col_append_fstr(pinfo->cinfo, COL_INFO, "CID: %s ", tvb_bytes_to_str(tvb, off, optlen));
/* Fall through */
case OPTION_SERVERID:
if (optlen < 2) {
proto_tree_add_text(subtree, tvb, off, optlen,
"DUID: malformed option");
break;
}
proto_item_append_text(ti, ": %s", tvb_bytes_to_str(tvb, off, optlen));
duidtype = tvb_get_ntohs(tvb, off);
proto_tree_add_text(subtree, tvb, off, 2,
"DUID type: %s (%u)",
@ -615,6 +1009,8 @@ dhcpv6_option(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bp_tree,
proto_tree_add_text(subtree, tvb, off,
sizeof(in6), "IPv6 address: %s",
ip6_to_str(&in6));
col_append_fstr(pinfo->cinfo, COL_INFO, "IAA: %s ", ip6_to_str(&in6));
proto_item_append_text(ti, ": %s", ip6_to_str(&in6));
preferred_lifetime = tvb_get_ntohl(tvb, off + 16);
valid_lifetime = tvb_get_ntohl(tvb, off + 20);
@ -950,21 +1346,23 @@ dhcpv6_option(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bp_tree,
if (optlen < 1) {
proto_tree_add_text(subtree, tvb, off,
optlen, "FQDN: malformed option");
break;
} else {
/*
* +-----+-+-+-+
* | MBZ |N|O|S|
* +-----+-+-+-+
*/
proto_tree_add_item(subtree, hf_clientfqdn_reserved, tvb, off, 1, FALSE);
proto_tree_add_item(subtree, hf_clientfqdn_n, tvb, off, 1, FALSE);
proto_tree_add_item(subtree, hf_clientfqdn_o, tvb, off, 1, FALSE);
proto_tree_add_item(subtree, hf_clientfqdn_s, tvb, off, 1, FALSE);
#if 0
proto_tree_add_text(subtree, tvb, off, 1,
"flags: %d",
(guint32)tvb_get_guint8(tvb, off));
#endif
dhcpv6_domain(subtree, tvb, off + 1, optlen - 1);
}
/*
* +-----+-+-+-+
* | 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_PANA_AGENT:
if (optlen % 16) {
@ -1186,30 +1584,25 @@ dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
proto_item *ti;
guint8 msgtype;
gboolean at_end;
downstream = 0; /* feature reserved */
struct e_in6_addr in6;
msgtype = tvb_get_guint8(tvb, off);
col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(msgtype, msgtype_vals, "Message Type %u"));
if (tree) {
ti = proto_tree_add_item(tree, proto_dhcpv6, tvb, off, eoff - off, FALSE);
bp_tree = proto_item_add_subtree(ti, ett_dhcpv6);
}
if (!off) {
if (check_col(pinfo->cinfo, COL_INFO)) {
col_add_str(pinfo->cinfo, COL_INFO,
val_to_str(msgtype,
msgtype_vals,
"Message Type %u"));
}
}
if (msgtype == RELAY_FORW || msgtype == RELAY_REPLY) {
if (tree) {
proto_tree_add_item(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1, FALSE);
proto_tree_add_item(bp_tree, hf_dhcpv6_hopcount, tvb, off + 1, 1, FALSE);
proto_tree_add_item(bp_tree, hf_dhcpv6_linkaddr, tvb, off + 2, 16, FALSE);
tvb_get_ipv6(tvb, off + 2, &in6);
col_append_fstr(pinfo->cinfo, COL_INFO, "L: %s ", ip6_to_str(&in6));
proto_tree_add_item(bp_tree, hf_dhcpv6_peeraddr, tvb, off + 18, 16, FALSE);
}
off += 34;
@ -1218,6 +1611,7 @@ dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
proto_tree_add_item(bp_tree, hf_dhcpv6_msgtype, tvb, off, 1, FALSE);
proto_tree_add_item(bp_tree, hf_dhcpv6_xid, tvb, off + 1, 3, FALSE);
}
col_append_fstr(pinfo->cinfo, COL_INFO, "XID: 0x%x ", tvb_get_ntoh24(tvb, off + 1));
off += 4;
}
@ -1248,32 +1642,9 @@ proto_register_dhcpv6(void)
{
static hf_register_info hf[] = {
/* DHCPv6 header */
{ &hf_dhcpv6_msgtype,
{ "Message type", "dhcpv6.msgtype", FT_UINT8,
BASE_DEC, VALS(msgtype_vals), 0x0,
NULL, HFILL }},
{ &hf_fqdn_1,
{ "Reserved", "dhcpv6.msgtype.reserved", FT_UINT8, BASE_HEX, NULL, 0xF8, NULL, HFILL}},
{ &hf_fqdn_2,
{ "N", "dhcpv6.msgtype.n", FT_BOOLEAN, 8, TFS(&fqdn_n), 0x4, NULL, HFILL}},
{ &hf_fqdn_3,
{ "O", "dhcpv6.msgtype.o", FT_BOOLEAN, 8, TFS(&fqdn_o), 0x2, NULL, HFILL}},
{ &hf_fqdn_4,
{ "S", "dhcpv6.msgtype.s", FT_BOOLEAN, 8, TFS(&fqdn_s), 0x1, NULL, HFILL}},
{ &hf_option_type,
{ "Option", "dhcpv6.option.type", FT_UINT16, BASE_DEC, VALS(opttype_vals), 0x0, NULL, HFILL}},
{ &hf_option_length,
{ "Length", "dhcpv6.option.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
{ &hf_option_value,
{ "Value", "dhcpv6.option.value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
{ &hf_remoteid_enterprise,
{ "Enterprise ID", "dhvpv6.remoteid.enterprise", FT_UINT32, BASE_DEC, VALS(sminmpec_values), 0, "RemoteID Enterprise Number", HFILL }},
{ &hf_vendoropts_enterprise,
{ "Enterprise ID", "dhvpv6.vendoropts.enterprise", FT_UINT32, BASE_DEC, VALS(sminmpec_values), 0, "Vendor opts Enterprise Number", HFILL }},
{ &hf_vendorclass_enterprise,
{ "Enterprise ID", "dhvpv6.vendorclass.enterprise", FT_UINT32, BASE_DEC, VALS(sminmpec_values), 0, "Vendor Class Enterprise Number", HFILL }},
{ &hf_duiden_enterprise,
{ "Enterprise ID", "dhvpv6.duiden.enterprise", FT_UINT32, BASE_DEC, VALS(sminmpec_values), 0, "DUID EN Enterprise Number", HFILL }},
{ "Message type", "dhcpv6.msgtype", FT_UINT8, BASE_DEC, VALS(msgtype_vals), 0x0, NULL, HFILL }},
{ &hf_dhcpv6_hopcount,
{ "Hopcount", "dhcpv6.hopcount", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL}},
{ &hf_dhcpv6_xid,
@ -1282,7 +1653,31 @@ proto_register_dhcpv6(void)
{ "Link address", "dhcpv6.linkaddr", FT_IPv6, BASE_NONE, NULL, 0, NULL, HFILL}},
{ &hf_dhcpv6_peeraddr,
{ "Peer address", "dhcpv6.peeraddr", FT_IPv6, BASE_NONE, NULL, 0, NULL, HFILL}},
/* Generic option stuff */
{ &hf_option_type,
{ "Option", "dhcpv6.option.type", FT_UINT16, BASE_DEC, VALS(opttype_vals), 0x0, NULL, HFILL}},
{ &hf_option_length,
{ "Length", "dhcpv6.option.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
{ &hf_option_value,
{ "Value", "dhcpv6.option.value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
/* Individual options */
{ &hf_clientfqdn_reserved,
{ "Reserved", "dhcpv6.clientfqdn.reserved", FT_UINT8, BASE_HEX, NULL, 0xF8, NULL, HFILL}},
{ &hf_clientfqdn_n,
{ "N", "dhcpv6.clientfqdn.n", FT_BOOLEAN, 8, TFS(&fqdn_n), 0x4, NULL, HFILL}},
{ &hf_clientfqdn_o,
{ "O", "dhcpv6.clientfqdn.o", FT_BOOLEAN, 8, TFS(&fqdn_o), 0x2, NULL, HFILL}},
{ &hf_clientfqdn_s,
{ "S", "dhcpv6.clientfqdn.s", FT_BOOLEAN, 8, TFS(&fqdn_s), 0x1, NULL, HFILL}},
{ &hf_remoteid_enterprise,
{ "Enterprise ID", "dhvpv6.remoteid.enterprise", FT_UINT32, BASE_DEC, VALS(sminmpec_values), 0, "RemoteID Enterprise Number", HFILL }},
{ &hf_vendoropts_enterprise,
{ "Enterprise ID", "dhvpv6.vendoropts.enterprise", FT_UINT32, BASE_DEC, VALS(sminmpec_values), 0, "Vendor opts Enterprise Number", HFILL }},
{ &hf_vendorclass_enterprise,
{ "Enterprise ID", "dhvpv6.vendorclass.enterprise", FT_UINT32, BASE_DEC, VALS(sminmpec_values), 0, "Vendor Class Enterprise Number", HFILL }},
{ &hf_duiden_enterprise,
{ "Enterprise ID", "dhvpv6.duiden.enterprise", FT_UINT32, BASE_DEC, VALS(sminmpec_values), 0, "DUID EN Enterprise Number", HFILL }},
};
static gint *ett[] = {
&ett_dhcpv6,
@ -1314,397 +1709,3 @@ proto_reg_handoff_dhcpv6(void)
dissector_add("udp.port", UDP_PORT_DHCPV6_UPSTREAM, dhcpv6_handle);
}
static void
dissect_cablelabs_specific_opts(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len)
{
guint16 type;
guint16 tlv_len; /* holds the number of elements in the tlv */
guint16 opt_len; /* holds the length of the suboption */
guint16 sub_value;
int off = voff;
int sub_off; /** The offset for the sub-option */
proto_item *ti;
int i;
int field_len; /* holds the lenght of one occurrence of a field */
proto_tree *subtree;
struct e_in6_addr in6;
if (len > 4) {
while (off - voff < len) {
/* Type */
type = tvb_get_ntohs(tvb, off);
ti = proto_tree_add_text(v_tree, tvb, off, 2,
"Suboption %d: %s", type, val_to_str(type,
cl_vendor_subopt_values, "unknown"));
/* Length */
tlv_len = tvb_get_ntohs(tvb, off+2);
/* Values */
sub_off = off + 4;
switch(type) {
/* String types */
case CL_OPTION_DEVICE_TYPE :
case CL_OPTION_DEVICE_SERIAL_NUMBER :
case CL_OPTION_HARDWARE_VERSION_NUMBER :
case CL_OPTION_SOFTWARE_VERSION_NUMBER :
case CL_OPTION_BOOT_ROM_VERSION :
case CL_OPTION_MODEL_NUMBER :
case CL_OPTION_VENDOR_NAME :
case CL_OPTION_CONFIG_FILE_NAME :
case CL_OPTION_EMBEDDED_COMPONENT_LIST :
opt_len = tlv_len;
field_len = tlv_len;
proto_item_append_text(ti, "\"%s\"",
tvb_format_stringzpad(tvb, sub_off, field_len));
break;
case CL_OPTION_ORO :
field_len = 2;
opt_len = tlv_len;
if (opt_len > 0) {
for (i = 0; i < tlv_len; i += field_len) {
sub_value = tvb_get_ntohs(tvb, sub_off);
proto_item_append_text(ti, " %d", sub_value);
sub_off += field_len;
}
}
break;
/* List of IPv6 Address */
case CL_OPTION_TFTP_SERVERS :
case CL_OPTION_SYSLOG_SERVERS :
case CL_OPTION_RFC868_SERVERS :
field_len = 16;
opt_len = tlv_len;
subtree = proto_item_add_subtree(ti, ett_dhcpv6_vendor_option);
if ((tlv_len % field_len) == 0) {
for (i = 0; i < tlv_len/field_len; i++) {
tvb_get_ipv6(tvb, sub_off, &in6);
proto_tree_add_text(subtree, tvb, sub_off,
sizeof(in6), "IPv6 address %d: %s",
i+1, ip6_to_str(&in6));
sub_off += field_len;
}
}
break;
case CL_OPTION_VENDOR_OUI :
case CL_OPTION_DEVICE_ID :
opt_len = tlv_len;
field_len = tlv_len;
if (tlv_len != 6) {
proto_item_append_text(ti, "Bogus value length=%d",
tlv_len);
}
else {
proto_item_append_text(ti, "%s",
tvb_bytes_to_str(tvb, sub_off, field_len));
}
break;
case CL_OPTION_TLV5 :
opt_len = tlv_len;
field_len = tlv_len;
proto_item_append_text(ti, "%s",
tvb_bytes_to_str(tvb, sub_off, field_len));
break;
case CL_OPTION_TIME_OFFSET :
opt_len = tlv_len;
proto_item_append_text(ti, "%d", tvb_get_ntohl(tvb, sub_off));
break;
case CL_OPTION_DOCS_CMTS_CAP :
opt_len = tlv_len;
field_len = 0;
subtree = proto_item_add_subtree(ti, ett_dhcpv6_vendor_option);
/* tlv_len contains the total length of all the TLVs for this
option */
if (tlv_len > 0) {
for (i = 0; field_len < opt_len; i++) {
int tagLen = 0;
int tag = 0;
tag = tvb_get_guint8(tvb, sub_off);
sub_off++;
tagLen = tvb_get_guint8(tvb, sub_off);
sub_off++;
if (tag == CL_OPTION_DOCS_CMTS_TLV_VERS_NUM &&
tagLen == 2) {
int major = 0;
int minor = 0;
major = tvb_get_guint8(tvb, sub_off);
sub_off++;
minor = tvb_get_guint8(tvb, sub_off);
sub_off++;
proto_tree_add_text(subtree, tvb, sub_off,
sizeof(4), "DOCSIS Version Number %d.%d",
major, minor);
}
else
sub_off += tagLen;
field_len += tagLen + 2;
}
}
else
proto_tree_add_text(subtree, tvb, sub_off,
sizeof(0), "empty");
break;
case CL_CM_MAC_ADDR :
opt_len = tlv_len;
field_len = tlv_len;
if (tlv_len != 6) {
proto_item_append_text(ti, "Bogus value length=%d",
tlv_len);
}
else {
/*proto_item_append_text(ti, "CM MAC Address Option = %s", */
proto_item_append_text(ti, "%s",
bytes_to_str_punct(tvb_get_ptr(tvb, sub_off, opt_len), opt_len, ':'));
/* tvb_bytes_to_str(tvb, sub_off, opt_len)); */
}
sub_off += field_len;
break;
case CL_EROUTER_CONTAINER_OPTION :
opt_len = tlv_len;
field_len = tlv_len;
proto_item_append_text(ti, " %s (len=%d)",
tvb_bytes_to_str(tvb, sub_off, opt_len), tlv_len);
sub_off += field_len;
break;
case CL_OPTION_CCC :
opt_len = tlv_len;
field_len = 0;
subtree = proto_item_add_subtree(ti, ett_dhcpv6_vendor_option);
proto_item_append_text(ti, " (%d bytes)", opt_len);
while (field_len < opt_len) {
sub_value = dissect_packetcable_ccc_option(subtree, tvb,
sub_off, (opt_len - field_len));
sub_off += sub_value;
field_len += sub_value;
}
sub_off += field_len;
default:
opt_len = tlv_len;
break;
}
off += (opt_len + 4);
}
}
else {
proto_tree_add_text(v_tree, tvb, off, len-off,
"Bogus length: %d", len);
}
}
static int
dissect_packetcable_ccc_option(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
int optend)
{
/** THE ENCODING OF THIS SUBOPTION HAS CHANGED FROM DHCPv4
the code and length fields have grown from a single octet to
two octets each. **/
int suboptoff = optoff;
guint16 subopt, subopt_len, sec_tcm;
guint8 fetch_tgt, timer_val, type;
proto_item *vti;
proto_tree *pkt_s_tree;
guint32 ipv4_address;
guchar kr_name; /** A character in the kerberos realm name option */
guint8 kr_value; /* The integer value of the character currently being tested */
int kr_fail_flag = 0; /* Flag indicating an invalid character was found */
int kr_pos = 0; /* The position of the first invalid character */
int i = 0;
char bit_fld[24];
subopt = tvb_get_ntohs(tvb, optoff);
suboptoff += 2;
subopt_len = tvb_get_ntohs(tvb, suboptoff);
suboptoff += 2;
/* There must be at least five octets left to be a valid sub element */
if (optend <= 0) {
proto_tree_add_text(v_tree, tvb, optoff, 1,
"Sub element %d: no room left in option for suboption length",
subopt);
return (optend);
}
/* g_print("dissect packetcable ccc option subopt_len=%d optend=%d\n\n", subopt_len, optend); */
vti = proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 4,
"Sub element %u: %s: ", subopt,
val_to_str(subopt, pkt_ccc_opt_vals, "unknown/reserved") );
switch (subopt) {
case PKT_CCC_PRI_DHCP: /* IPv4 address values */
case PKT_CCC_SEC_DHCP:
if (subopt_len == 4) {
ipv4_address = tvb_get_ipv4(tvb, suboptoff);
proto_item_append_text(vti, "%s (%u byte%s%s)",
ip_to_str((guint8 *)&ipv4_address), subopt_len,
plurality(subopt_len, "", "s"),
subopt_len != 4 ? " [Invalid]" : "");
}
else {
proto_tree_add_text(vti, tvb, suboptoff, subopt_len,
"Bogus length: %d", subopt_len);
}
suboptoff += subopt_len;
break;
case PKT_CCC_IETF_PROV_SRV :
type = tvb_get_guint8(tvb, suboptoff);
/** Type 0 is FQDN **/
if (type == 0) {
proto_item_append_text(vti, "%s (%u byte%s)",
tvb_format_stringzpad(tvb, suboptoff+1, subopt_len-1),
subopt_len,
plurality(subopt_len-1, "", "s") );
}
/** Type 0 is IPv4 **/
else if (type == 1) {
if (subopt_len == 5) {
ipv4_address = tvb_get_ipv4(tvb, suboptoff+1);
proto_item_append_text(vti, "%s (%u byte%s%s)",
ip_to_str((guint8 *)&ipv4_address), subopt_len,
plurality(subopt_len, "", "s"),
subopt_len != 5 ? " [Invalid]" : "");
}
else {
proto_item_append_text(vti, "Bogus length: %d", subopt_len);
}
}
else {
proto_item_append_text(vti, "Invalid type: %u (%u byte%s)",
type, subopt_len, plurality(subopt_len, "", "s"));
}
suboptoff += subopt_len;
break;
case PKT_CCC_IETF_AS_KRB :
case PKT_CCC_IETF_AP_KRB :
if (subopt_len == 12) {
pkt_s_tree = proto_item_add_subtree(vti, ett_dhcpv6_pkt_option);
proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
"Nominal Timeout : %u", tvb_get_ntohl(tvb, suboptoff));
proto_tree_add_text(pkt_s_tree, tvb, suboptoff+4, 4,
"Maximum Timeout : %u", tvb_get_ntohl(tvb, suboptoff+4));
proto_tree_add_text(pkt_s_tree, tvb, suboptoff+8, 4,
"Maximum Retry Count : %u", tvb_get_ntohl(tvb, suboptoff+8));
}
else {
proto_item_append_text(vti, "Bogus length: %d", subopt_len);
}
suboptoff += subopt_len;
break;
case PKT_CCC_KRB_REALM:
if (subopt_len > 0) {
/** The only allowable characters are
A-Z (upper case only) 65-90
'.', 46
'/', 47
'\', 92
'=', 61
'"', 34
',', 44
and
':' 58
so loop through and
make sure it conforms to the expected syntax.
**/
for (i=0; i < subopt_len; i++) {
kr_name = tvb_get_guint8(tvb, suboptoff + i);
kr_value = (int)kr_name;
if ((kr_value >= 65 && kr_value <= 90) ||
kr_value == 34 ||
kr_value == 44 ||
kr_value == 46 ||
kr_value == 47 ||
kr_value == 58 ||
kr_value == 61 ||
kr_value == 92) {
}
else if (!kr_fail_flag) {
kr_pos = i;
kr_fail_flag = 1;
}
proto_item_append_text(vti, "%c",
kr_name);
}
if (kr_fail_flag) {
proto_item_append_text(vti, " (%u byte%s [Invalid at byte=%d]) ",
subopt_len,
plurality(subopt_len, "", "s"),
kr_pos);
}
else {
proto_item_append_text(vti, " (%u byte%s%s) ",
subopt_len,
plurality(subopt_len, "", "s"),
kr_fail_flag != 0 ? " [Invalid]" : "");
}
}
suboptoff += subopt_len;
break;
case PKT_CCC_TGT_FLAG:
fetch_tgt = tvb_get_guint8(tvb, suboptoff);
proto_item_append_text(vti, "%s (%u byte%s%s)",
fetch_tgt == 1 ? "True" : "False",
subopt_len,
plurality(subopt_len, "", "s"),
subopt_len != 1 ? " [Invalid]" : "");
suboptoff += subopt_len;
break;
case PKT_CCC_PROV_TIMER:
timer_val = tvb_get_guint8(tvb, suboptoff);
/* proto_item_append_text(vti, "%u%s (%u byte%s%s)", timer_val,
timer_val > 30 ? " [Invalid]" : "", */
proto_item_append_text(vti, "%u (%u byte%s%s)", timer_val,
subopt_len,
plurality(subopt_len, "", "s"),
subopt_len != 1 ? " [Invalid]" : "");
suboptoff += subopt_len;
break;
case PKT_CCC_IETF_SEC_TKT :
sec_tcm = tvb_get_ntohs(tvb, suboptoff);
proto_item_append_text(vti, "0x%04x (%u byte%s%s)",
sec_tcm, subopt_len, plurality(subopt_len, "", "s"),
subopt_len != 2 ? " [Invalid]" : "");
if (subopt_len == 2) {
pkt_s_tree = proto_item_add_subtree(vti, ett_dhcpv6_pkt_option);
for (i=0; i< 2; i++) {
if (sec_tcm & sec_tcm_vals[i].value) {
decode_bitfield_value(bit_fld, sec_tcm, sec_tcm_vals[i].value, 16);
proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 2, "%s %s",
bit_fld, sec_tcm_vals[i].strptr);
}
}
}
suboptoff += subopt_len;
break;
default:
suboptoff += subopt_len;
break;
}
/** Return the number of bytes processed **/
return (suboptoff - optoff);
}