diff options
author | Gerald Combs <gerald@wireshark.org> | 2004-10-05 17:44:53 +0000 |
---|---|---|
committer | Gerald Combs <gerald@wireshark.org> | 2004-10-05 17:44:53 +0000 |
commit | 853fad671ba5261f1e1e32ac181ceb9179fea849 (patch) | |
tree | a3b07ef6ba6dcca34f10bf9c9fbcf89c4b877b83 /epan/dissectors/packet-bootp.c | |
parent | d2de064046c2abb3ee68799eec881ece0746cda8 (diff) |
Decode cable modem and MTA device capabilities. Make the CableLabs
Client Configuration option number configurable. Add an option to switch
between the CCC versions defined in PKT-SP-PROV-I05-021127, IETF draft 5,
and RFC 3495. Code contributed by CableLabs.
Remove an unneeded macro.
svn path=/trunk/; revision=12208
Diffstat (limited to 'epan/dissectors/packet-bootp.c')
-rw-r--r-- | epan/dissectors/packet-bootp.c | 982 |
1 files changed, 852 insertions, 130 deletions
diff --git a/epan/dissectors/packet-bootp.c b/epan/dissectors/packet-bootp.c index 88e8afeb07..595be832bb 100644 --- a/epan/dissectors/packet-bootp.c +++ b/epan/dissectors/packet-bootp.c @@ -20,6 +20,11 @@ * RFC 3594: PacketCable Security Ticket Control Sub-Option (122.9) * BOOTP and DHCP Parameters * http://www.iana.org/assignments/bootp-dhcp-parameters + * PacketCable(TM) MTA Device Provisioning Specification + * http://www.packetcable.com/downloads/specs/PKT-SP-PROV-I05-021127.pdf + * http://www.packetcable.com/downloads/specs/PKT-SP-PROV-I09-040402.pdf + * CableHome(TM) 1.1 Specification + * http://www.cablelabs.com/projects/cablehome/downloads/specs/CH-SP-CH1.1-I04-040409.pdf * * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -40,6 +45,17 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* + * Some of the development of the BOOTP/DHCP protocol decoder was sponsored by + * Cable Television Laboratories, Inc. ("CableLabs") based upon proprietary + * CableLabs' specifications. Your license and use of this protocol decoder + * does not mean that you are licensed to use the CableLabs' + * specifications. If you have questions about this protocol, contact + * jf.mule [AT] cablelabs.com or c.stuart [AT] cablelabs.com for additional + * information. + */ + + #ifdef HAVE_CONFIG_H # include "config.h" #endif @@ -52,7 +68,8 @@ #include <epan/prefs.h> #include <epan/tap.h> - +#include <epan/strutil.h> + static int bootp_dhcp_tap = -1; static int proto_bootp = -1; static int hf_bootp_type = -1; @@ -74,6 +91,8 @@ static int hf_bootp_file = -1; static int hf_bootp_cookie = -1; static int hf_bootp_vendor = -1; static int hf_bootp_dhcp = -1; +static int hf_bootp_pkt_mdc_len = -1; +static int hf_bootp_pkt_cm_len = -1; static gint ett_bootp = -1; static gint ett_bootp_flags = -1; @@ -87,8 +106,6 @@ gboolean novell_string = FALSE; #define BOOTP_BC 0x8000 #define BOOTP_MBZ 0x7FFF -#define PLURALIZE(n) (((n) > 1) ? "s" : "") - enum field_type { none, ipv4, string, toggle, yes_no, special, opaque, time_in_secs, val_u_byte, val_u_short, val_u_le_short, val_u_long, @@ -105,16 +122,41 @@ static const true_false_string flag_set_broadcast = { }; +/* PacketCable definitions */ +#define PACKETCABLE_MTA_CAP10 "pktc1.0:" +#define PACKETCABLE_CM_CAP11 "docsis1.1:" +#define PACKETCABLE_CM_CAP20 "docsis2.0:" + +#define PACKETCABLE_CCC_I05 1 +#define PACKETCABLE_CCC_DRAFT5 2 +#define PACKETCABLE_CCC_RFC_3495 3 + +static enum_val_t pkt_ccc_protocol_versions[] = { + { "ccc_i05", "PKT-SP-PROV-I05-021127", PACKETCABLE_CCC_I05 }, + { "ccc_draft_5", "IETF Draft 5", PACKETCABLE_CCC_DRAFT5 }, + { "rfc_3495", "RFC 3495", PACKETCABLE_CCC_RFC_3495 }, + { NULL, 0 } +}; + +static gint pkt_ccc_protocol_version = PACKETCABLE_CCC_RFC_3495; +static gint pkt_ccc_option = 122; + + static int dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp); static int dissect_vendor_cablelabs_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp); -static int dissect_cablelabs_clientconfig_suboption(proto_tree *v_tree, tvbuff_t *tvb, - int optp); static int dissect_netware_ip_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp); static int bootp_dhcp_decode_agent_info(proto_tree *v_tree, tvbuff_t *tvb, int optp); +static void dissect_packetcable_mta_cap(proto_tree *v_tree, tvbuff_t *tvb, + int voff, int len); +static void dissect_packetcable_cm_cap(proto_tree *v_tree, tvbuff_t *tvb, + int voff, int len); +static int dissect_packetcable_i05_ccc(proto_tree *v_tree, tvbuff_t *tvb, int optp); +static int dissect_packetcable_ietf_ccc(proto_tree *v_tree, tvbuff_t *tvb, int optp, int revision); + static const char * get_dhcp_type(guint8 byte) @@ -182,6 +224,7 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff, guint8 rdm; int o52voff, o52eoff; gboolean o52at_end; + gboolean skip_opaque = FALSE; static const value_string nbnt_vals[] = { {0x1, "B-node" }, @@ -343,7 +386,7 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff, /* 119 */ { "Domain Search", opaque }, /* 120 */ { "SIP Servers", opaque }, /* 121 */ { "Classless Static Route", opaque }, - /* 122 */ { "CableLabs Client Configuration", special }, + /* 122 */ { "CableLabs Client Configuration", opaque }, /* 123 */ { "Unassigned", opaque }, /* 124 */ { "Unassigned", opaque }, /* 125 */ { "Unassigned", opaque }, @@ -595,9 +638,9 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff, optp = dissect_vendor_pxeclient_suboption(v_tree, tvb, optp); } - } else if (*vendor_class_id_p != NULL && - ((strncmp(*vendor_class_id_p, "pktc", strlen("pktc")) == 0) || - (strncmp(*vendor_class_id_p, "docsis", strlen("docsis")) == 0) || + } else if (*vendor_class_id_p != NULL && + ((strncmp(*vendor_class_id_p, "pktc", strlen("pktc")) == 0) || + (strncmp(*vendor_class_id_p, "docsis", strlen("docsis")) == 0) || (strncmp(*vendor_class_id_p, "CableHome", strlen("CableHome")) == 0))) { /* CableLabs standard - see www.cablelabs.com/projects */ vti = proto_tree_add_text(bp_tree, tvb, voff, @@ -629,7 +672,7 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff, "Option %d: %s = %s", code, text, val_to_str(byte, opt_overload_vals, "Unknown (0x%02x)")); - + /* Just in case we find an option 52 in sname or file */ if (voff > VENDOR_INFO_OFFSET && byte >= 1 && byte <= 3) { o52tree = proto_item_add_subtree(vti, ett_bootp_option); @@ -649,7 +692,7 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff, } if (byte == 2 || byte == 3) { /* 'sname' */ vti = proto_tree_add_text (o52tree, tvb, - SERVER_NAME_OFFSET, SERVER_NAME_LEN, + SERVER_NAME_OFFSET, SERVER_NAME_LEN, "Server host name option overload"); v_tree = proto_item_add_subtree(vti, ett_bootp_option); o52voff = SERVER_NAME_OFFSET; @@ -690,9 +733,17 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff, break; case 60: /* Vendor class identifier */ - proto_tree_add_text(bp_tree, tvb, voff, consumed, + vti = proto_tree_add_text(bp_tree, tvb, voff, consumed, "Option %d: %s = \"%.*s\"", code, text, vlen, tvb_get_ptr(tvb, voff+2, consumed-2)); + if (tvb_memeql(tvb, voff+2, PACKETCABLE_MTA_CAP10, strlen(PACKETCABLE_MTA_CAP10)) == 0) { + v_tree = proto_item_add_subtree(vti, ett_bootp_option); + dissect_packetcable_mta_cap(v_tree, tvb, voff+2, vlen); + } else if (tvb_memeql(tvb, voff+2, PACKETCABLE_CM_CAP11, strlen(PACKETCABLE_CM_CAP11)) == 0 || + tvb_memeql(tvb, voff+2, PACKETCABLE_CM_CAP20, strlen(PACKETCABLE_CM_CAP20)) == 0 ) { + v_tree = proto_item_add_subtree(vti, ett_bootp_option); + dissect_packetcable_cm_cap(v_tree, tvb, voff+2, vlen); + } break; case 61: /* Client Identifier */ @@ -802,16 +853,6 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff, } break; - case 122: /* CableLabs Client Configuration */ - vti = proto_tree_add_text(bp_tree, tvb, voff, - vlen + 2, "Option %d: %s", code, text); - v_tree = proto_item_add_subtree(vti, ett_bootp_option); - optp = voff+2; - while (optp < voff+consumed) { - optp = dissect_cablelabs_clientconfig_suboption(v_tree, tvb, optp); - } - break; - case 90: /* DHCP Authentication */ case 210: /* Was this used for authentication at one time? */ vti = proto_tree_add_text(bp_tree, tvb, voff, @@ -891,6 +932,31 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff, break; default: /* not special */ + /* The PacketCable CCC option number can vary. If this is a CCC option, + handle it and skip the "opaque" case below. + */ + if (code == pkt_ccc_option) { + skip_opaque = TRUE; + vti = proto_tree_add_text(bp_tree, tvb, voff, consumed, + "Option %d: CableLabs Client Configuration (%d bytes)", + code, vlen); + v_tree = proto_item_add_subtree(vti, ett_bootp_option); + optp = voff+2; + while (optp < voff+consumed) { + switch (pkt_ccc_protocol_version) { + case PACKETCABLE_CCC_I05: + optp = dissect_packetcable_i05_ccc(v_tree, tvb, optp); + break; + case PACKETCABLE_CCC_DRAFT5: + case PACKETCABLE_CCC_RFC_3495: + optp = dissect_packetcable_ietf_ccc(v_tree, tvb, optp, pkt_ccc_protocol_version); + break; + default: /* XXX Should we do something here? */ + break; + } + } + } + break; } @@ -932,9 +998,11 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff, break; case opaque: - proto_tree_add_text(bp_tree, tvb, voff, consumed, - "Option %d: %s (%d bytes)", - code, text, vlen); + if (! skip_opaque) { /* Currently used by PacketCable CCC */ + proto_tree_add_text(bp_tree, tvb, voff, consumed, + "Option %d: %s (%d bytes)", + code, text, vlen); + } break; case val_u_short: @@ -1035,7 +1103,7 @@ bootp_dhcp_decode_agent_info(proto_tree *v_tree, tvbuff_t *tvb, int optp) break; default: proto_tree_add_text(v_tree, tvb, optp, subopt_len + 2, - "Invalid agent suboption %d (%d bytes)", + "Invalid agent suboption %d (%d bytes)", subopt, subopt_len); break; } @@ -1100,11 +1168,11 @@ dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp) proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, "Suboption %d: %s (%d byte%s)" , subopt, "PXE boot item", - subopt_len, PLURALIZE(subopt_len)); + subopt_len, plurality(subopt_len, "", "s")); } else if ((subopt < 1 ) || (subopt > array_length(o43pxeclient_opt))) { proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, "Unknown suboption %d (%d byte%s)", subopt, subopt_len, - PLURALIZE(subopt_len)); + plurality(subopt_len, "", "s")); } else { switch (o43pxeclient_opt[subopt].ft) { @@ -1118,7 +1186,7 @@ dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp) proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, "Suboption %d: %s (%d byte%s)" , subopt, o43pxeclient_opt[subopt].text, - subopt_len, PLURALIZE(subopt_len)); + subopt_len, plurality(subopt_len, "", "s")); break; case val_u_le_short: @@ -1161,10 +1229,11 @@ dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp) return optp; } + static int dissect_vendor_cablelabs_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp) { - guint8 subopt; + guint8 subopt, byte_val; guint8 subopt_len; struct o43cablelabs_opt_info { @@ -1181,7 +1250,7 @@ dissect_vendor_cablelabs_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp) /* 5 */ {"Hardware Version", string}, /* 6 */ {"Software Version", string}, /* 7 */ {"Boot ROM version", string}, - /* 8 */ {"Organizational Unique Identifier", bytes}, + /* 8 */ {"Organizationally Unique Identifier", special}, /* 9 */ {"Model Number", string}, /* 10 */ {"Vendor Name", string}, /* *** 11-30: CableHome *** */ @@ -1206,7 +1275,7 @@ dissect_vendor_cablelabs_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp) /* 29 */ {"Unassigned (CableHome)", special}, /* 30 */ {"Unassigned (CableHome)", special}, /* *** 31-50: PacketCable *** */ - /* 31 */ {"MTA MAC Address", string}, + /* 31 */ {"MTA MAC Address", special}, /* 32 */ {"Correlation ID", string}, /* 33-50 {"Unassigned (PacketCable)", special}, */ /* *** 51-127: CableLabs *** */ @@ -1216,13 +1285,19 @@ dissect_vendor_cablelabs_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp) /* 255 {"end options", special} */ }; + static const value_string packetcable_subopt11_vals[] = { + { 1, "PS WAN-Man" }, + { 2, "PS WAN-Data" }, + { 0, NULL } + }; + subopt = tvb_get_guint8(tvb, optp); if (subopt == 0 ) { proto_tree_add_text(v_tree, tvb, optp, 1, "Padding"); return (optp+1); } else if (subopt == 255) { /* End Option */ - proto_tree_add_text(v_tree, tvb, optp, 1, "End option"); + proto_tree_add_text(v_tree, tvb, optp, 1, "End CableLabs option"); /* Make sure we skip any junk left this option */ return (optp+255); } @@ -1232,29 +1307,45 @@ dissect_vendor_cablelabs_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp) if ( (subopt < 1 ) || (subopt > array_length(o43cablelabs_opt)) ) { proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, "Suboption %d: Unassigned (%d byte%s)", subopt, subopt_len, - PLURALIZE(subopt_len)); + plurality(subopt_len, "", "s")); } else { switch (o43cablelabs_opt[subopt].ft) { case string: proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, - "Suboption %d: %s = \"%.*s\"", subopt, + "Suboption %d: %s = \"%.*s\"", subopt, o43cablelabs_opt[subopt].text, subopt_len, tvb_get_ptr(tvb, optp+2, subopt_len)); break; case bytes: proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, - "Suboption %d: %s = 0x%s", subopt, + "Suboption %d: %s = 0x%s", subopt, o43cablelabs_opt[subopt].text, tvb_bytes_to_str(tvb, optp+2, subopt_len)); break; - + case special: - proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, - "Suboption %d: %s (%d byte%s)" , - subopt, o43cablelabs_opt[subopt].text, - subopt_len, PLURALIZE(subopt_len)); + if ( subopt == 8 ) { /* OUI */ + proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, + "Suboption %d: OUI = %s" , + subopt, bytes_to_str_punct(tvb_get_ptr(tvb, optp+2, 3), 3, ':')); + } else if ( subopt == 11 ) { /* Address Realm */ + byte_val = tvb_get_guint8(tvb, optp + 2); + proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, + "Suboption %d: Address Realm = 0x%02x (%s)" , + subopt, byte_val, + val_to_str(byte_val, packetcable_subopt11_vals, "Unknown")); + } else if ( subopt == 31 ) { /* MTA MAC address */ + proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, + "Suboption %d: MTA MAC address = %s" , + subopt, bytes_to_str_punct(tvb_get_ptr(tvb, optp+2, 6), 6, ':')); + } else { + proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, + "Suboption %d: %s (%d byte%s)" , + subopt, o43cablelabs_opt[subopt].text, + subopt_len, plurality(subopt_len, "", "s")); + } break; default: @@ -1266,6 +1357,8 @@ dissect_vendor_cablelabs_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp) return optp; } + + static int dissect_netware_ip_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp) { @@ -1363,113 +1456,718 @@ dissect_netware_ip_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp) return optp; } -static int -dissect_cablelabs_clientconfig_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp) + +/* PakcetCable Multimedia Terminal Adapter device capabilities (option 60). + Ref: PKT-SP-I05-021127 sections 8.2 and 10 */ + +#define PKT_MDC_TLV_OFF 10 + + +/* These are ASCII-encoded hexadecimal digits. We use the raw hex equivalent for + convenience. */ +#define PKT_MDC_VERSION 0x3031 /* "01" */ +#define PKT_MDC_TEL_END 0x3032 /* "02" */ +#define PKT_MDC_TGT 0x3033 /* "03" */ +#define PKT_MDC_HTTP_ACC 0x3034 /* "04" */ +#define PKT_MDC_SYSLOG 0x3035 /* "05" */ +#define PKT_MDC_NCS 0x3036 /* "06" */ +#define PKT_MDC_PRI_LINE 0x3037 /* "07" */ +#define PKT_MDC_VENDOR_TLV 0x3038 /* "08" */ +#define PKT_MDC_NVRAM_STOR 0x3039 /* "09" */ +#define PKT_MDC_PROV_REP 0x3041 /* "0A" */ +#define PKT_MDC_PROV_REP_LC 0x3061 /* "0A" */ +#define PKT_MDC_SUPP_CODECS 0x3042 /* "0B" */ +#define PKT_MDC_SUPP_CODECS_LC 0x3062 /* "0b" */ +#define PKT_MDC_SILENCE 0x3043 /* "0C" */ +#define PKT_MDC_SILENCE_LC 0x3063 /* "0c" */ +#define PKT_MDC_ECHO_CANCEL 0x3044 /* "0D" */ +#define PKT_MDC_ECHO_CANCEL_LC 0x3064 /* "0d" */ +#define PKT_MDC_RSVP 0x3145 /* "0E" */ +#define PKT_MDC_RSVP_LC 0x3165 /* "0e" */ +#define PKT_MDC_UGS_AD 0x3146 /* "0F" */ +#define PKT_MDC_UGS_AD_LC 0x3166 /* "0f" */ +#define PKT_MDC_IF_INDEX 0x3130 /* "10" */ +#define PKT_MDC_FLOW_LOG 0x3131 /* "11" */ +#define PKT_MDC_PROV_FLOWS 0x3132 /* "12" */ + +static const value_string pkt_mdc_type_vals[] = { + { PKT_MDC_VERSION, "PacketCable Version" }, + { PKT_MDC_TEL_END, "Number Of Telephony Endpoints" }, + { PKT_MDC_TGT, "TGT Support" }, + { PKT_MDC_HTTP_ACC, "HTTP Download File Access Method Support" }, + { PKT_MDC_SYSLOG, "MTA-24 Event SYSLOG Notification Support" }, + { PKT_MDC_NCS, "NCS Service Flow Support" }, + { PKT_MDC_PRI_LINE, "Primary Line Support" }, + { PKT_MDC_VENDOR_TLV, "Vendor Specific TLV Type(s)" }, + { PKT_MDC_NVRAM_STOR, "NVRAM Ticket/Session Keys Storage Support" }, + { PKT_MDC_PROV_REP, "Provisioning Event Reporting Support" }, + { PKT_MDC_PROV_REP_LC, "Provisioning Event Reporting Support" }, + { PKT_MDC_SUPP_CODECS, "Supported CODEC(s)" }, + { PKT_MDC_SUPP_CODECS_LC, "Supported CODEC(s)" }, + { PKT_MDC_SILENCE, "Silence Suppression Support" }, + { PKT_MDC_SILENCE_LC, "Silence Suppression Support" }, + { PKT_MDC_ECHO_CANCEL, "Echo Cancellation Support" }, + { PKT_MDC_ECHO_CANCEL_LC, "Echo Cancellation Support" }, + { PKT_MDC_RSVP, "RSVP Support" }, + { PKT_MDC_RSVP_LC, "RSVP Support" }, + { PKT_MDC_UGS_AD, "UGS-AD Support" }, + { PKT_MDC_UGS_AD_LC, "UGS-AD Support" }, + { PKT_MDC_IF_INDEX, "MTA's \"ifIndex\" starting number in \"ifTable\"" }, + { PKT_MDC_FLOW_LOG, "Provisioning Flow Logging Support" }, + { PKT_MDC_PROV_FLOWS, "Supported Provisioning Flows" }, + { 0, NULL } +}; + +static const value_string pkt_mdc_version_vals[] = { + { 0x3030, "PacketCable 1.0" }, + { 0x3031, "PacketCable 1.1" }, + { 0x3032, "PacketCable 1.2" }, + { 0x3033, "PacketCable 1.3" }, + { 0, NULL } +}; + +static const value_string pkt_mdc_boolean_vals[] = { + { 0x3030, "No" }, + { 0x3031, "Yes" }, + { 0, NULL } +}; + +static const value_string pkt_mdc_codec_vals[] = { + { 0x3031, "other" }, + { 0x3032, "unknown" }, + { 0x3033, "G.729" }, + { 0x3034, "reserved" }, + { 0x3035, "G.729E" }, + { 0x3036, "PCMU" }, + { 0x3037, "G.726-32" }, + { 0x3038, "G.728" }, + { 0x3039, "PCMA" }, + { 0x3041, "G.726-16" }, + { 0x3042, "G.726-24" }, + { 0x3043, "G.726-40" }, + { 0, NULL } +}; + +/* PacketCable Cable Modem device capabilities (option 60). */ +#define PKT_CM_TLV_OFF 12 + +#define PKT_CM_CONCAT_SUP 0x3031 /* "01" */ +#define PKT_CM_DOCSIS_VER 0x3032 /* "02" */ +#define PKT_CM_FRAG_SUP 0x3033 /* "03" */ +#define PKT_CM_PHS_SUP 0x3034 /* "04" */ +#define PKT_CM_IGMP_SUP 0x3035 /* "05" */ +#define PKT_CM_PRIV_SUP 0x3036 /* "06" */ +#define PKT_CM_DSAID_SUP 0x3037 /* "07" */ +#define PKT_CM_USID_SUP 0x3038 /* "08" */ +#define PKT_CM_FILT_SUP 0x3039 /* "09" */ +#define PKT_CM_TET_MI 0x3041 /* "0A" */ +#define PKT_CM_TET_MI_LC 0x3061 /* "0a" */ +#define PKT_CM_TET 0x3042 /* "0B" */ +#define PKT_CM_TET_LC 0x3062 /* "0b" */ +#define PKT_CM_DCC_SUP 0x3043 /* "0C" */ +#define PKT_CM_DCC_SUP_LC 0x3063 /* "0c" */ + +static const value_string pkt_cm_type_vals[] = { + { PKT_CM_CONCAT_SUP, "Concatenation Support" }, + { PKT_CM_DOCSIS_VER, "DOCSIS Version" }, + { PKT_CM_FRAG_SUP, "Fragmentation Support" }, + { PKT_CM_PHS_SUP, "PHS Support" }, + { PKT_CM_IGMP_SUP, "IGMP Support" }, + { PKT_CM_PRIV_SUP, "Privacy Support" }, + { PKT_CM_DSAID_SUP, "Downstream SAID Support" }, + { PKT_CM_USID_SUP, "Upstream SID Support" }, + { PKT_CM_FILT_SUP, "Optional Filtering Support" }, + { PKT_CM_TET_MI, "Transmit Equalizer Taps per Modulation Interval" }, + { PKT_CM_TET_MI_LC, "Transmit Equalizer Taps per Modulation Interval" }, + { PKT_CM_TET, "Number of Transmit Equalizer Taps" }, + { PKT_CM_TET_LC, "Number of Transmit Equalizer Taps" }, + { PKT_CM_DCC_SUP, "DCC Support" }, + { PKT_CM_DCC_SUP_LC, "DCC Support" } +}; + +static const value_string pkt_cm_version_vals[] = { + { 0x3030, "DOCSIS 1.1" }, + { 0x3031, "DOCSIS 2.0" }, + { 0, NULL } +}; + +static const value_string pkt_cm_privacy_vals[] = { + { 0x3030, "BPI Support" }, + { 0x3031, "BPI Plus Support" }, + { 0, NULL } +}; + + +static const value_string pkt_mdc_supp_flow_vals[] = { + { 1 << 0, "Secure Flow (Full Secure Provisioning Flow)" }, + { 1 << 1, "Hybrid Flow" }, + { 1 << 2, "Basic Flow" }, + { 0, NULL } +}; + + +static void +dissect_packetcable_mta_cap(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len) { - guint8 subopt; - guint8 subopt_len; - guint8 flag; - char dname[MAXDNAME]; - int dname_len; + guint16 raw_val; + long flow_val; + guint off = PKT_MDC_TLV_OFF + voff; + guint tlv_len, i; + guint8 asc_val[3] = " ", flow_val_str[5]; + static GString *tlv_str = NULL; + char *fmt_str = "%s.xxxxxxxx"; + char bit_fld[64]; + proto_item *ti; + proto_tree *subtree; + + if (! tlv_str) + tlv_str = g_string_new(""); + + tvb_memcpy (tvb, asc_val, off, 2); + if (sscanf(asc_val, "%uhx", &tlv_len) != 1) { + proto_tree_add_text(v_tree, tvb, off, len - off, + "Bogus length: %s", asc_val); + return; + } else { + proto_tree_add_uint_format(v_tree, hf_bootp_pkt_mdc_len, tvb, off, 2, + tlv_len, "MTA DC Length: %d", tlv_len); + off += 2; + + while ((int) off - voff < len) { + /* Type */ + raw_val = tvb_get_ntohs (tvb, off); + g_string_sprintf(tlv_str, "Type: %s (0x%.2s), ", + val_to_str(raw_val, pkt_mdc_type_vals, "unknown"), + tvb_get_ptr(tvb, off, 2)); + + /* Length */ + tvb_memcpy(tvb, asc_val, off + 2, 2); + if (sscanf(asc_val, "%uhx", &tlv_len) != 1) { + proto_tree_add_text(v_tree, tvb, off, len - off, + "Bogus length: %s", asc_val); + return; + } else { + /* Value(s) */ + g_string_sprintfa(tlv_str, "Length: %d, Value: ", tlv_len); + + switch (raw_val) { + case PKT_MDC_VERSION: + raw_val = tvb_get_ntohs(tvb, off + 4); + g_string_sprintfa(tlv_str, "%s (%.2s)", + val_to_str(raw_val, pkt_mdc_version_vals, "Reserved"), + tvb_get_ptr(tvb, off + 4, 2) ); + break; + case PKT_MDC_TEL_END: + case PKT_MDC_IF_INDEX: + g_string_sprintfa(tlv_str, "%.2s", + tvb_get_ptr(tvb, off + 4, 2) ); + break; + case PKT_MDC_TGT: + case PKT_MDC_HTTP_ACC: + case PKT_MDC_SYSLOG: + case PKT_MDC_NCS: + case PKT_MDC_PRI_LINE: + case PKT_MDC_NVRAM_STOR: + case PKT_MDC_PROV_REP: + case PKT_MDC_PROV_REP_LC: + case PKT_MDC_SILENCE: + case PKT_MDC_SILENCE_LC: + case PKT_MDC_ECHO_CANCEL: + case PKT_MDC_ECHO_CANCEL_LC: + case PKT_MDC_RSVP: + case PKT_MDC_RSVP_LC: + case PKT_MDC_UGS_AD: + case PKT_MDC_UGS_AD_LC: + case PKT_MDC_FLOW_LOG: + raw_val = tvb_get_ntohs(tvb, off + 4); + g_string_sprintfa(tlv_str, "%s (%.2s)", + val_to_str(raw_val, pkt_mdc_boolean_vals, "unknown"), + tvb_get_ptr(tvb, off + 4, 2) ); + break; + case PKT_MDC_SUPP_CODECS: + case PKT_MDC_SUPP_CODECS_LC: + for (i = 0; i < tlv_len; i++) { + raw_val = tvb_get_ntohs(tvb, off + 4 + (i * 2) ); + g_string_sprintfa(tlv_str, "%s%s (%.2s)", + plurality(i + 1, "", ", "), + val_to_str(raw_val, pkt_mdc_codec_vals, "unknown"), + tvb_get_ptr(tvb, off + 4 + (i * 2), 2) ); + } + break; + case PKT_MDC_PROV_FLOWS: + tvb_memcpy(tvb, flow_val_str, off + 4, 4); + flow_val_str[4] = '\0'; + flow_val = strtoul(flow_val_str, NULL, 16); + g_string_sprintfa(tlv_str, "0x%04x", flow_val); + break; + case PKT_MDC_VENDOR_TLV: + default: + sprintf (fmt_str, "%%.%us", tlv_len * 2); + g_string_sprintfa(tlv_str, fmt_str, + tvb_get_ptr(tvb, off + 4, tlv_len * 2) ); + break; + } + } + ti = proto_tree_add_text(v_tree, tvb, off, (tlv_len * 2) + 4, tlv_str->str); + subtree = proto_item_add_subtree(ti, ett_bootp_option); + if (raw_val == PKT_MDC_PROV_FLOWS) { + for (i = 0 ; i < 3; i++) { + if (flow_val & pkt_mdc_supp_flow_vals[i].value) { + decode_bitfield_value(bit_fld, flow_val, pkt_mdc_supp_flow_vals[i].value, 16); + proto_tree_add_text(ti, tvb, off + 4, 4, "%s%s", + bit_fld, pkt_mdc_supp_flow_vals[i].strptr); + } + } + } + off += (tlv_len * 2) + 4; + } + } +} - struct o122cablelabs_opt_info { - char *text; - enum field_type ft; - }; +static void +dissect_packetcable_cm_cap(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len) +{ + long raw_val; + guint off = PKT_CM_TLV_OFF + voff; + guint tlv_len, i; + guint8 asc_val[3] = " "; + static GString *tlv_str = NULL; + char *fmt_str = "%s.xxxxxxxx"; + + if (! tlv_str) + tlv_str = g_string_new(""); + + tvb_memcpy (tvb, asc_val, off, 2); + if (sscanf(asc_val, "%uhx", &tlv_len) != 1) { + proto_tree_add_text(v_tree, tvb, off, len - off, + "Bogus length: %s", asc_val); + return; + } else { + proto_tree_add_uint_format(v_tree, hf_bootp_pkt_cm_len, tvb, off, 2, + tlv_len, "CM DC Length: %d", tlv_len); + off += 2; + + while ((int) off - voff < len) { + /* Type */ + raw_val = tvb_get_ntohs (tvb, off); + g_string_sprintf(tlv_str, "Type: %s (%.2s), ", + val_to_str(raw_val, pkt_cm_type_vals, "unknown"), + tvb_get_ptr(tvb, off, 2)); + + /* Length */ + tvb_memcpy(tvb, asc_val, off + 2, 2); + if (sscanf(asc_val, "%uhx", &tlv_len) != 1) { + proto_tree_add_text(v_tree, tvb, off, len - off, + "Bogus length: %s", asc_val); + return; + } else { + /* Value(s) */ + g_string_sprintfa(tlv_str, "Length: %d, Value%s: ", tlv_len, + plurality(tlv_len, "", "s") ); + + switch (raw_val) { + case PKT_CM_CONCAT_SUP: + case PKT_CM_FRAG_SUP: + case PKT_CM_PHS_SUP: + case PKT_CM_IGMP_SUP: + case PKT_CM_DCC_SUP: + case PKT_CM_DCC_SUP_LC: + for (i = 0; i < tlv_len; i++) { + raw_val = tvb_get_ntohs(tvb, off + 4 + (i * 2) ); + g_string_sprintfa(tlv_str, "%s%s (%.2s)", + plurality(i + 1, "", ", "), + val_to_str(raw_val, pkt_mdc_boolean_vals, "unknown"), + tvb_get_ptr(tvb, off + 4 + (i * 2), 2) ); + } + break; + case PKT_CM_DOCSIS_VER: + raw_val = tvb_get_ntohs(tvb, off + 4); + g_string_sprintfa(tlv_str, "%s (%.2s)", + val_to_str(raw_val, pkt_cm_version_vals, "Reserved"), + tvb_get_ptr(tvb, off + 4, 2) ); + break; + case PKT_CM_PRIV_SUP: + raw_val = tvb_get_ntohs(tvb, off + 4); + g_string_sprintfa(tlv_str, "%s (%.2s)", + val_to_str(raw_val, pkt_cm_privacy_vals, "Reserved"), + tvb_get_ptr(tvb, off + 4, 2) ); + break; + case PKT_CM_DSAID_SUP: + case PKT_CM_USID_SUP: + case PKT_CM_TET_MI: + case PKT_CM_TET_MI_LC: + case PKT_CM_TET: + case PKT_CM_TET_LC: + tvb_memcpy (tvb, asc_val, off + 4, 2); + raw_val = strtoul(asc_val, NULL, 16); + g_string_sprintfa(tlv_str, "%u", raw_val); + break; + case PKT_CM_FILT_SUP: + tvb_memcpy (tvb, asc_val, off + 4, 2); + raw_val = strtoul(asc_val, NULL, 16); + if (raw_val & 0x01) + g_string_append(tlv_str, "802.1P filtering"); + if (raw_val & 0x02) { + if (raw_val & 0x01) + g_string_append(tlv_str, ", "); + g_string_append(tlv_str, "802.1Q filtering"); + } + if (! raw_val & 0x03) + g_string_append(tlv_str, "None"); + g_string_sprintfa(tlv_str, " (0x%02x)", raw_val); + break; + } + } + proto_tree_add_text(v_tree, tvb, off, (tlv_len * 2) + 4, tlv_str->str); + off += (tlv_len * 2) + 4; + } + } +} - static struct o122cablelabs_opt_info o122cablelabs_opt[]= { - /* 0 */ {"nop", special}, /* dummy */ - /* 1 */ {"TSP's Primary DHCP Server Address", ipv4}, - /* 2 */ {"TSP's Secondary DHCP Server Address", ipv4}, - /* 3 */ {"TSP's Provisioning Server Address", ipv4_or_fqdn}, - /* 4 */ {"TSP's AS-REQ/AS-REP Backoff and Retry", special}, - /* 5 */ {"TSP's AP-REQ/AP-REP Backoff and Retry", special}, - /* 6 */ {"TSP's Kerberos Realm Name", fqdn}, - /* 7 */ {"TSP's Ticket Granting Server Utilization", special}, - /* 8 */ {"TSP's Provisioning Timer Value", special}, - /* 9 */ {"PacketCable Security Ticket Control", special}, - /* *** 10-255: Reserved for future use *** */ - }; + +/* Definitions specific to PKT-SP-PROV-I05-021127 begin with "PKT_CCC_I05". + Definitions specific to IETF draft 5 and RFC 3495 begin with "PKT_CCC_IETF". + Shared definitions begin with "PKT_CCC". + */ +#define PKT_CCC_PRI_DHCP 1 +#define PKT_CCC_SEC_DHCP 2 +#define PKT_CCC_I05_SNMP 3 +#define PKT_CCC_IETF_PROV_SRV 3 +#define PKT_CCC_I05_PRI_DNS 4 +#define PKT_CCC_IETF_AS_KRB 4 +#define PKT_CCC_I05_SEC_DNS 5 +#define PKT_CCC_IETF_AP_KRB 5 +#define PKT_CCC_KRB_REALM 6 +#define PKT_CCC_TGT_FLAG 7 +#define PKT_CCC_PROV_TIMER 8 +#define PKT_CCC_CMS_FQDN 9 +#define PKT_CCC_IETF_SEC_TKT 9 +#define PKT_CCC_AS_KRB 10 +#define PKT_CCC_AP_KRB 11 +#define PKT_CCC_MTA_KRB_CLEAR 12 + +static const value_string pkt_i05_ccc_opt_vals[] = { + { PKT_CCC_PRI_DHCP, "Primary DHCP Server" }, + { PKT_CCC_SEC_DHCP, "Secondary DHCP Server" }, + { PKT_CCC_I05_SNMP, "SNMP Entity" }, + { PKT_CCC_I05_PRI_DNS, "Primary DNS Server" }, + { PKT_CCC_I05_SEC_DNS, "Secondary DNS Server" }, + { PKT_CCC_KRB_REALM, "Kerberos Realm" }, + { PKT_CCC_TGT_FLAG, "MTA should fetch TGT?" }, + { PKT_CCC_PROV_TIMER, "Provisioning Timer" }, + { PKT_CCC_CMS_FQDN, "CMS FQDN" }, + { PKT_CCC_AS_KRB, "AS-REQ/AS-REP Backoff and Retry" }, + { PKT_CCC_AP_KRB, "AP-REQ/AP-REP Backoff and Retry" }, + { PKT_CCC_MTA_KRB_CLEAR, "MTA should clear Kerberos tickets?" }, + { 0, NULL }, +}; + +static const value_string pkt_draft5_ccc_opt_vals[] = { + { PKT_CCC_PRI_DHCP, "Primary DHCP Server" }, + { PKT_CCC_SEC_DHCP, "Secondary DHCP Server" }, + { PKT_CCC_IETF_PROV_SRV, "Provisioning Server" }, + { PKT_CCC_IETF_AS_KRB, "AS-REQ/AS-REP Backoff and Retry" }, + { PKT_CCC_IETF_AP_KRB, "AP-REQ/AP-REP Backoff and Retry" }, + { PKT_CCC_KRB_REALM, "Kerberos Realm" }, + { PKT_CCC_TGT_FLAG, "MTA should fetch TGT?" }, + { PKT_CCC_PROV_TIMER, "Provisioning Timer" }, + { PKT_CCC_IETF_SEC_TKT, "Security Ticket Control" }, + { 0, NULL }, +}; + +static const value_string pkt_i05_ccc_ticket_ctl_vals[] = { + { 1, "Invalidate Provisioning Application Server's ticket" }, + { 2, "Invalidate all CMS Application Server tickets" }, + { 3, "Invalidate all Application Server tickets" }, + { 0, NULL }, +}; + +static int +dissect_packetcable_i05_ccc(proto_tree *v_tree, tvbuff_t *tvb, int optp) +{ + guint8 subopt, subopt_len, fetch_tgt, timer_val, ticket_ctl; + guint32 nom_to, max_to, max_ret; + proto_tree *pkt_s_tree; + proto_item *vti; + static GString *opt_str = NULL; + char *fmt_str = "%s.xxxxxxxx (%u bytes)"; + + if (! opt_str) + opt_str = g_string_new(""); subopt = tvb_get_guint8(tvb, optp); - subopt_len = tvb_get_guint8(tvb, optp+1); + subopt_len = tvb_get_guint8(tvb, optp + 1); + optp += 2; - if ((subopt < 1 ) || (subopt > array_length(o122cablelabs_opt))) { - proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, - "Suboption %d: Unassigned (%d byte%s)", subopt, subopt_len, - PLURALIZE(subopt_len)); - } else { - switch (o122cablelabs_opt[subopt].ft) { + g_string_sprintf(opt_str, "Suboption %u: %s: ", subopt, + val_to_str(subopt, pkt_i05_ccc_opt_vals, "unknown/reserved") ); - case string: - proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, - "Suboption %d: %s = \"%.*s\"", subopt, - o122cablelabs_opt[subopt].text, subopt_len, - tvb_get_ptr(tvb, optp+2, subopt_len)); + switch (subopt) { + case PKT_CCC_PRI_DHCP: /* String values */ + case PKT_CCC_SEC_DHCP: + case PKT_CCC_I05_SNMP: + case PKT_CCC_I05_PRI_DNS: + case PKT_CCC_I05_SEC_DNS: + case PKT_CCC_KRB_REALM: + case PKT_CCC_CMS_FQDN: + sprintf (fmt_str, "%%.%us (%%u byte%%s)", subopt_len); + g_string_sprintfa(opt_str, fmt_str, + tvb_get_ptr(tvb, optp, subopt_len), + subopt_len, + plurality(subopt_len, "", "s") ); + proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + optp += subopt_len; break; - - case special: - proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, - "Suboption %d: %s (%d byte%s)" , - subopt, o122cablelabs_opt[subopt].text, - subopt_len, PLURALIZE(subopt_len)); + + case PKT_CCC_TGT_FLAG: + fetch_tgt = tvb_get_guint8(tvb, optp); + g_string_sprintfa(opt_str, "%s (%u byte%s%s)", + fetch_tgt ? "Yes" : "No", + subopt_len, + plurality(subopt_len, "", "s"), + subopt_len != 1 ? " [Invalid]" : ""); + proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + optp += 1; break; - case ipv4: - proto_tree_add_text(v_tree, tvb, optp, 6, - "Suboption %d: %s = %s", - subopt, o122cablelabs_opt[subopt].text, - ip_to_str(tvb_get_ptr(tvb, optp+2, 4))); + + case PKT_CCC_PROV_TIMER: + timer_val = tvb_get_guint8(tvb, optp); + g_string_sprintfa(opt_str, "%u%s (%u byte%s)", timer_val, + timer_val > 30 ? " [Invalid]" : "", + subopt_len, + plurality(subopt_len, "", "s"), + subopt_len != 1 ? " [Invalid]" : ""); + proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + optp += 1; break; - case fqdn: - dname_len = get_dns_name(tvb, optp+2, optp+2, dname, sizeof(dname)); - proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, - "Suboption %d: %s = %.*s", subopt, - o122cablelabs_opt[subopt].text, - dname_len, dname); - break; - case ipv4_or_fqdn: - flag = tvb_get_guint8(tvb, optp+2); - if (flag == 0) { /* FQDN */ - dname_len = get_dns_name(tvb, optp+3, optp+3, dname, sizeof(dname)); - proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, - "Suboption %d: %s = %.*s", subopt, - o122cablelabs_opt[subopt].text, - dname_len, dname); - } else if (flag == 1) { /* IPv4 */ - proto_tree_add_text(v_tree, tvb, optp, 6, - "Suboption %d: %s = %s", - subopt, o122cablelabs_opt[subopt].text, - ip_to_str(tvb_get_ptr(tvb, optp+3, 4))); - } else { - proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, - "Suboption %d: %s = Invalid Value (%d byte%s)", - subopt, o122cablelabs_opt[subopt].text, - subopt_len, PLURALIZE(subopt_len)); + + case PKT_CCC_AS_KRB: + nom_to = tvb_get_ntohl(tvb, optp); + max_to = tvb_get_ntohl(tvb, optp + 4); + max_ret = tvb_get_ntohl(tvb, optp + 8); + g_string_sprintfa(opt_str, "(%u byte%s%s)", subopt_len, + plurality(subopt_len, "", "s"), + subopt_len != 12 ? " [Invalid]" : ""); + vti = proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option); + proto_tree_add_text(pkt_s_tree, tvb, optp, 4, + "pktcMtaDevRealmUnsolicitedKeyNomTimeout: %u", nom_to); + proto_tree_add_text(pkt_s_tree, tvb, optp + 4, 4, + "pktcMtaDevRealmUnsolicitedKeyMaxTimeout: %u", max_to); + proto_tree_add_text(pkt_s_tree, tvb, optp + 8, 4, + "pktcMtaDevRealmUnsolicitedKeyMaxRetries: %u", max_ret); + optp += 12; + break; + + case PKT_CCC_AP_KRB: + nom_to = tvb_get_ntohl(tvb, optp); + max_to = tvb_get_ntohl(tvb, optp + 4); + max_ret = tvb_get_ntohl(tvb, optp + 8); + g_string_sprintfa(opt_str, "(%u byte%s%s)", subopt_len, + plurality(subopt_len, "", "s"), + subopt_len != 12 ? " [Invalid]" : ""); + vti = proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option); + proto_tree_add_text(pkt_s_tree, tvb, optp, 4, + "pktcMtaDevProvUnsolicitedKeyNomTimeout: %u", nom_to); + proto_tree_add_text(pkt_s_tree, tvb, optp + 4, 4, + "pktcMtaDevProvUnsolicitedKeyMaxTimeout: %u", max_to); + proto_tree_add_text(pkt_s_tree, tvb, optp + 8, 4, + "pktcMtaDevProvUnsolicitedKeyMaxRetries: %u", max_ret); + optp += 12; + break; + + case PKT_CCC_MTA_KRB_CLEAR: + ticket_ctl = tvb_get_guint8(tvb, optp); + g_string_sprintfa(opt_str, "%s (%u)%s (%u byte%s%s)", + val_to_str (ticket_ctl, pkt_i05_ccc_ticket_ctl_vals, "unknown/invalid"), + ticket_ctl, + subopt_len, + plurality(subopt_len, "", "s"), + subopt_len != 1 ? " [Invalid]" : ""); + proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + optp += 1; + break; + + default: + proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + break; + + } + return optp; +} + + +static const value_string sec_tcm_vals[] = { + { 1 << 0, "PacketCable Provisioning Server" }, + { 1 << 1, "All PacketCable Call Managers" }, + { 0, NULL } +}; + +static int +dissect_packetcable_ietf_ccc(proto_tree *v_tree, tvbuff_t *tvb, int optp, + int revision) +{ + guint8 subopt, subopt_len, ipv4_addr[4]; + guint8 prov_type, fetch_tgt, timer_val; + guint16 sec_tcm; + guint32 nom_to, max_to, max_ret; + proto_tree *pkt_s_tree; + proto_item *vti; + static GString *opt_str = NULL; + char *fmt_str = "%s.xxxxxxxx (%u bytes)"; + int max_timer_val = 255, i; + char dns_name[255], bit_fld[24]; + + if (! opt_str) + opt_str = g_string_new(""); + + subopt = tvb_get_guint8(tvb, optp); + subopt_len = tvb_get_guint8(tvb, optp + 1); + optp += 2; + + g_string_sprintf(opt_str, "Suboption %u: %s: ", subopt, + val_to_str(subopt, pkt_draft5_ccc_opt_vals, "unknown/reserved") ); + + switch (subopt) { + case PKT_CCC_PRI_DHCP: /* IPv4 values */ + case PKT_CCC_SEC_DHCP: + tvb_memcpy(tvb, ipv4_addr, optp, 4); + g_string_sprintfa(opt_str, "%u.%u.%u.%u (%u byte%s%s)", + ipv4_addr[0], ipv4_addr[1], ipv4_addr[2], ipv4_addr[3], + subopt_len, + plurality(subopt_len, "", "s"), + subopt_len != 4 ? " [Invalid]" : ""); + proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + optp += subopt_len; + break; + + case PKT_CCC_IETF_PROV_SRV: + prov_type = tvb_get_guint8(tvb, optp); + optp += 1; + switch (prov_type) { + case 0: + get_dns_name(tvb, optp, optp + 1, dns_name, + sizeof(dns_name)); + g_string_sprintfa(opt_str, "%s (%u byte%s)", dns_name, + subopt_len - 1, plurality(subopt_len, "", "s") ); + proto_tree_add_text(v_tree, tvb, optp - 3, subopt_len + 2, opt_str->str); + optp += subopt_len - 1; + break; + case 1: + tvb_memcpy(tvb, ipv4_addr, optp, 4); + g_string_sprintfa(opt_str, "%u.%u.%u.%u (%u byte%s%s)", + ipv4_addr[0], ipv4_addr[1], ipv4_addr[2], ipv4_addr[3], + subopt_len, + plurality(subopt_len, "", "s"), + subopt_len != 5 ? " [Invalid]" : ""); + proto_tree_add_text(v_tree, tvb, optp - 3, subopt_len + 2, opt_str->str); + optp += subopt_len - 1; + break; + default: + g_string_sprintfa(opt_str, "Invalid type: %u (%u byte%s)", + tvb_get_guint8(tvb, optp), + subopt_len, + plurality(subopt_len, "", "s") ); + proto_tree_add_text(v_tree, tvb, optp - 3, subopt_len + 2, opt_str->str); + optp += subopt_len - 1; + break; } break; - case yes_no: - flag = tvb_get_guint8(tvb, optp+2); - if (flag == 0 || flag == 1) { - proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, - "Suboption %d: %s = %s", subopt, - o122cablelabs_opt[subopt].text, - flag == 0 ? "No" : "Yes"); - } else { - proto_tree_add_text(v_tree, tvb, optp, subopt_len+2, - "Suboption %d: %s = Invalid Value %d", - subopt, o122cablelabs_opt[subopt].text, flag); + + case PKT_CCC_IETF_AS_KRB: + nom_to = tvb_get_ntohl(tvb, optp); + max_to = tvb_get_ntohl(tvb, optp + 4); + max_ret = tvb_get_ntohl(tvb, optp + 8); + g_string_sprintfa(opt_str, "(%u byte%s%s)", subopt_len, + plurality(subopt_len, "", "s"), + subopt_len != 12 ? " [Invalid]" : ""); + vti = proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option); + proto_tree_add_text(pkt_s_tree, tvb, optp, 4, + "pktcMtaDevRealmUnsolicitedKeyNomTimeout: %u", nom_to); + proto_tree_add_text(pkt_s_tree, tvb, optp + 4, 4, + "pktcMtaDevRealmUnsolicitedKeyMaxTimeout: %u", max_to); + proto_tree_add_text(pkt_s_tree, tvb, optp + 8, 4, + "pktcMtaDevRealmUnsolicitedKeyMaxRetries: %u", max_ret); + optp += 12; + break; + + case PKT_CCC_IETF_AP_KRB: + nom_to = tvb_get_ntohl(tvb, optp); + max_to = tvb_get_ntohl(tvb, optp + 4); + max_ret = tvb_get_ntohl(tvb, optp + 8); + g_string_sprintfa(opt_str, "(%u byte%s%s)", subopt_len, + plurality(subopt_len, "", "s"), + subopt_len != 12 ? " [Invalid]" : ""); + vti = proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option); + proto_tree_add_text(pkt_s_tree, tvb, optp, 4, + "pktcMtaDevProvUnsolicitedKeyNomTimeout: %u", nom_to); + proto_tree_add_text(pkt_s_tree, tvb, optp + 4, 4, + "pktcMtaDevProvUnsolicitedKeyMaxTimeout: %u", max_to); + proto_tree_add_text(pkt_s_tree, tvb, optp + 8, 4, + "pktcMtaDevProvUnsolicitedKeyMaxRetries: %u", max_ret); + optp += 12; + break; + + case PKT_CCC_KRB_REALM: /* String values */ + get_dns_name(tvb, optp, optp + 1, dns_name, sizeof(dns_name)); + g_string_sprintfa(opt_str, "%s (%u byte%s)", dns_name, + subopt_len, plurality(subopt_len, "", "s") ); + proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + optp += subopt_len; + break; + + case PKT_CCC_TGT_FLAG: + fetch_tgt = tvb_get_guint8(tvb, optp); + g_string_sprintfa(opt_str, "%s (%u byte%s%s)", + fetch_tgt ? "Yes" : "No", + subopt_len, + plurality(subopt_len, "", "s"), + subopt_len != 1 ? " [Invalid]" : ""); + proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + optp += 1; + break; + + case PKT_CCC_PROV_TIMER: + if (revision == PACKETCABLE_CCC_DRAFT5) + max_timer_val = 30; + timer_val = tvb_get_guint8(tvb, optp); + g_string_sprintfa(opt_str, "%u%s (%u byte%s%s)", timer_val, + timer_val > max_timer_val ? " [Invalid]" : "", + subopt_len, + plurality(subopt_len, "", "s"), + subopt_len != 1 ? " [Invalid]" : ""); + proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + optp += 1; + break; + + case PKT_CCC_IETF_SEC_TKT: + sec_tcm = tvb_get_ntohs(tvb, optp); + g_string_sprintfa(opt_str, "0x%04x (%u byte%s%s)", sec_tcm, subopt_len, + plurality(subopt_len, "", "s"), + subopt_len != 2 ? " [Invalid]" : ""); + vti = proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); + pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_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, optp, 2, "%sInvalidate %s", + bit_fld, sec_tcm_vals[i].strptr); + } } + optp += 2; break; + default: - proto_tree_add_text(v_tree, tvb, optp, subopt_len+2,"ERROR, please report: Unknown subopt type handler %d", subopt); + proto_tree_add_text(v_tree, tvb, optp - 2, subopt_len + 2, opt_str->str); break; - } + } - optp += (subopt_len + 2); return optp; } - #define BOOTREQUEST 1 #define BOOTREPLY 2 @@ -1588,12 +2286,12 @@ dissect_bootp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) /* The server host name is optional */ if (tvb_get_guint8(tvb, 44) != '\0') { proto_tree_add_item(bp_tree, hf_bootp_server, tvb, - SERVER_NAME_OFFSET, + SERVER_NAME_OFFSET, SERVER_NAME_LEN, FALSE); } else { proto_tree_add_string_format(bp_tree, hf_bootp_server, tvb, - SERVER_NAME_OFFSET, + SERVER_NAME_OFFSET, SERVER_NAME_LEN, tvb_get_ptr(tvb, SERVER_NAME_OFFSET, 1), "Server host name not given"); @@ -1790,6 +2488,15 @@ proto_register_bootp(void) { "Bootp Vendor Options", "bootp.vendor", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }}, + + { &hf_bootp_pkt_mdc_len, + { "MTA DC Length", "bootp.vendor.pkt.mdc_len", + FT_UINT8, BASE_DEC, NULL, 0x0, + "PacketCable MTA Device Capabilities Length", HFILL }}, + { &hf_bootp_pkt_cm_len, + { "CM DC Length", "bootp.vendor.pkt.cm_len", + FT_UINT8, BASE_DEC, NULL, 0x0, + "PacketCable Cable Modem Device Capabilities Length", HFILL }}, }; static gint *ett[] = { &ett_bootp, @@ -1811,6 +2518,21 @@ proto_register_bootp(void) "Decode Option 85 as String", "Novell Servers option 85 can be configured as a string instead of address", &novell_string); + + prefs_register_enum_preference(bootp_module, "pkt.ccc.protocol_version", + "PacketCable CCC protocol version", + "The PacketCable CCC protocol version", + &pkt_ccc_protocol_version, + pkt_ccc_protocol_versions, + FALSE); + + prefs_register_uint_preference(bootp_module, "pkt.ccc.option", + "PacketCable CCC option", + "Option Number for PacketCable CableLabs Client Configuration", + 10, + &pkt_ccc_option); + + } void |