aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-cops.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-cops.c')
-rw-r--r--epan/dissectors/packet-cops.c2637
1 files changed, 2637 insertions, 0 deletions
diff --git a/epan/dissectors/packet-cops.c b/epan/dissectors/packet-cops.c
new file mode 100644
index 0000000000..8db35e43ed
--- /dev/null
+++ b/epan/dissectors/packet-cops.c
@@ -0,0 +1,2637 @@
+/* packet-cops.c
+ * Routines for the COPS (Common Open Policy Service) protocol dissection
+ * RFC2748 & COPS-PR extension RFC3084
+ *
+ * Copyright 2000, Heikki Vatiainen <hessu@cs.tut.fi>
+ *
+ * Added PacketCable specifications by Dick Gooris <gooris@lucent.com>
+ *
+ * Taken from PacketCable specifications :
+ * PacketCable Dynamic Quality-of-Service Specification
+ * Based on PKT-SP-DQOS-I09-040402 (April 2, 2004)
+ * www.packetcable.com
+ *
+ * Implemented in ethereal at April 7-8, 2004
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <glib.h>
+
+#include "isprint.h"
+
+#include <epan/packet.h>
+#include "packet-ipv6.h"
+#include "packet-tcp.h"
+
+#ifdef HAVE_SOME_SNMP
+#ifdef HAVE_NET_SNMP
+# include <net-snmp/net-snmp-config.h>
+# include <net-snmp/mib_api.h>
+# include <net-snmp/library/default_store.h>
+# include <net-snmp/config_api.h>
+#else /* HAVE_NET_SNMP */
+# include <ucd-snmp/ucd-snmp-config.h>
+# include <ucd-snmp/asn1.h>
+# include <ucd-snmp/snmp_api.h>
+# include <ucd-snmp/snmp_impl.h>
+# include <ucd-snmp/mib.h>
+# include <ucd-snmp/default_store.h>
+# include <ucd-snmp/read_config.h>
+# include <ucd-snmp/tools.h>
+#endif /* HAVE_NET_SNMP */
+#endif /* HAVE_SOME_SNMP */
+
+#include "asn1.h"
+#include "format-oid.h"
+#include "prefs.h"
+
+/* For PacketCable, port 2126 */
+#define TCP_PORT_COPS 3288
+
+/* Preference: Variable to hold the tcp port preference */
+static guint global_cops_tcp_port = TCP_PORT_COPS;
+
+/* Preference: desegmentation of COPS */
+static gboolean cops_desegment = TRUE;
+
+/* Variable to allow for proper deletion of dissector registration
+ * when the user changes port from the gui
+ */
+
+static guint cops_tcp_port = 0;
+
+/*Some local globals needed to read COPS-PR ASN.1 Types from PIB-MIBs */
+/*MAX_OID_LEN from NET-SNMP's asn1.h*/
+
+#ifdef HAVE_NET_SNMP
+static subid_t last_decoded_prid_oid[MAX_OID_LEN]={0};
+static subid_t last_decoded_prid_oid_length=0;
+extern struct tree *tree_head;
+
+/* Preference: COPS-PR ASN.1 type decoding based on PIB/MIB or data in packet */
+static gboolean cops_typefrommib = FALSE;
+
+#endif /* HAVE_NET_SNMP */
+
+#define COPS_OBJECT_HDR_SIZE 4
+
+/* Null string of type "guchar[]". */
+static const guchar nullstring[] = "";
+
+#define SAFE_STRING(s) (((s) != NULL) ? (s) : nullstring)
+
+/* COPS PR Tags */
+
+#define COPS_IPA 0 /* IP Address */
+#define COPS_U32 2 /* Unsigned 32*/
+#define COPS_TIT 3 /* TimeTicks */
+#define COPS_OPQ 4 /* Opaque */
+#define COPS_I64 10 /* Integer64 */
+#define COPS_U64 11 /* Uinteger64 */
+
+/* COPS PR Types */
+
+#define COPS_NULL 0
+#define COPS_INTEGER 1 /* l */
+#define COPS_OCTETSTR 2 /* c */
+#define COPS_OBJECTID 3 /* ul */
+#define COPS_IPADDR 4 /* uc */
+#define COPS_UNSIGNED32 5 /* ul */
+#define COPS_TIMETICKS 7 /* ul */
+#define COPS_OPAQUE 8 /* c */
+#define COPS_INTEGER64 10 /* ll */
+#define COPS_UNSIGNED64 11 /* ull */
+
+
+typedef struct _COPS_CNV COPS_CNV;
+
+struct _COPS_CNV
+{
+ guint class;
+ guint tag;
+ gint syntax;
+ gchar *name;
+};
+
+static COPS_CNV CopsCnv [] =
+{
+ {ASN1_UNI, ASN1_NUL, COPS_NULL, "NULL"},
+ {ASN1_UNI, ASN1_INT, COPS_INTEGER, "INTEGER"},
+ {ASN1_UNI, ASN1_OTS, COPS_OCTETSTR, "OCTET STRING"},
+ {ASN1_UNI, ASN1_OJI, COPS_OBJECTID, "OBJECTID"},
+ {ASN1_APL, COPS_IPA, COPS_IPADDR, "IPADDR"},
+ {ASN1_APL, COPS_U32, COPS_UNSIGNED32,"UNSIGNED32"},
+ {ASN1_APL, COPS_TIT, COPS_TIMETICKS, "TIMETICKS"},
+ {ASN1_APL, COPS_OPQ, COPS_OPAQUE, "OPAQUE"},
+ {ASN1_APL, COPS_I64, COPS_INTEGER64, "INTEGER64"},
+ {ASN1_APL, COPS_U64, COPS_UNSIGNED64, "UNSIGNED64"},
+ {0, 0, -1, NULL}
+};
+
+static gchar *
+cops_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
+{
+ COPS_CNV *cnv;
+
+ cnv = CopsCnv;
+ while (cnv->syntax != -1)
+ {
+ if (cnv->tag == tag && cnv->class == cls)
+ {
+ *syntax = cnv->syntax;
+ return cnv->name;
+ }
+ cnv++;
+ }
+ return NULL;
+}
+
+static const value_string cops_flags_vals[] = {
+ { 0x00, "None" },
+ { 0x01, "Solicited Message Flag Bit" },
+ { 0, NULL },
+};
+
+/* The different COPS message types */
+enum cops_op_code {
+ COPS_NO_MSG, /* Not a COPS Message type */
+
+ COPS_MSG_REQ, /* Request (REQ) */
+ COPS_MSG_DEC, /* Decision (DEC) */
+ COPS_MSG_RPT, /* Report State (RPT) */
+ COPS_MSG_DRQ, /* Delete Request State (DRQ) */
+ COPS_MSG_SSQ, /* Synchronize State Req (SSQ) */
+ COPS_MSG_OPN, /* Client-Open (OPN) */
+ COPS_MSG_CAT, /* Client-Accept (CAT) */
+ COPS_MSG_CC, /* Client-Close (CC) */
+ COPS_MSG_KA, /* Keep-Alive (KA) */
+ COPS_MSG_SSC, /* Synchronize Complete (SSC) */
+
+ COPS_LAST_OP_CODE /* For error checking */
+};
+
+static const value_string cops_op_code_vals[] = {
+ { COPS_MSG_REQ, "Request (REQ)" },
+ { COPS_MSG_DEC, "Decision (DEC)" },
+ { COPS_MSG_RPT, "Report State (RPT)" },
+ { COPS_MSG_DRQ, "Delete Request State (DRQ)" },
+ { COPS_MSG_SSQ, "Synchronize State Req (SSQ)" },
+ { COPS_MSG_OPN, "Client-Open (OPN)" },
+ { COPS_MSG_CAT, "Client-Accept (CAT)" },
+ { COPS_MSG_CC, "Client-Close (CC)" },
+ { COPS_MSG_KA, "Keep-Alive (KA)" },
+ { COPS_MSG_SSC, "Synchronize Complete (SSC)" },
+ { 0, NULL },
+};
+
+
+/* The different objects in COPS messages */
+enum cops_c_num {
+ COPS_NO_OBJECT, /* Not a COPS Object type */
+
+ COPS_OBJ_HANDLE, /* Handle Object (Handle) */
+ COPS_OBJ_CONTEXT, /* Context Object (Context) */
+ COPS_OBJ_IN_INT, /* In-Interface Object (IN-Int) */
+ COPS_OBJ_OUT_INT, /* Out-Interface Object (OUT-Int) */
+ COPS_OBJ_REASON, /* Reason Object (Reason) */
+ COPS_OBJ_DECISION, /* Decision Object (Decision) */
+ COPS_OBJ_LPDPDECISION, /* LPDP Decision Object (LPDPDecision) */
+ COPS_OBJ_ERROR, /* Error Object (Error) */
+ COPS_OBJ_CLIENTSI, /* Client Specific Information Object (ClientSI) */
+ COPS_OBJ_KATIMER, /* Keep-Alive Timer Object (KATimer) */
+ COPS_OBJ_PEPID, /* PEP Identification Object (PEPID) */
+ COPS_OBJ_REPORT_TYPE, /* Report-Type Object (Report-Type) */
+ COPS_OBJ_PDPREDIRADDR, /* PDP Redirect Address Object (PDPRedirAddr) */
+ COPS_OBJ_LASTPDPADDR, /* Last PDP Address (LastPDPaddr) */
+ COPS_OBJ_ACCTTIMER, /* Accounting Timer Object (AcctTimer) */
+ COPS_OBJ_INTEGRITY, /* Message Integrity Object (Integrity) */
+ COPS_LAST_C_NUM /* For error checking */
+};
+
+static const value_string cops_c_num_vals[] = {
+ { COPS_OBJ_HANDLE, "Handle Object (Handle)" },
+ { COPS_OBJ_CONTEXT, "Context Object (Context)" },
+ { COPS_OBJ_IN_INT, "In-Interface Object (IN-Int)" },
+ { COPS_OBJ_OUT_INT, "Out-Interface Object (OUT-Int)" },
+ { COPS_OBJ_REASON, "Reason Object (Reason)" },
+ { COPS_OBJ_DECISION, "Decision Object (Decision)" },
+ { COPS_OBJ_LPDPDECISION, "LPDP Decision Object (LPDPDecision)" },
+ { COPS_OBJ_ERROR, "Error Object (Error)" },
+ { COPS_OBJ_CLIENTSI, "Client Specific Information Object (ClientSI)" },
+ { COPS_OBJ_KATIMER, "Keep-Alive Timer Object (KATimer)" },
+ { COPS_OBJ_PEPID, "PEP Identification Object (PEPID)" },
+ { COPS_OBJ_REPORT_TYPE, "Report-Type Object (Report-Type)" },
+ { COPS_OBJ_PDPREDIRADDR, "PDP Redirect Address Object (PDPRedirAddr)" },
+ { COPS_OBJ_LASTPDPADDR, "Last PDP Address (LastPDPaddr)" },
+ { COPS_OBJ_ACCTTIMER, "Accounting Timer Object (AcctTimer)" },
+ { COPS_OBJ_INTEGRITY, "Message Integrity Object (Integrity)" },
+ { 0, NULL },
+};
+
+
+/* The different objects in COPS-PR messages */
+enum cops_s_num {
+ COPS_NO_PR_OBJECT, /* Not a COPS-PR Object type */
+ COPS_OBJ_PRID, /* Provisioning Instance Identifier (PRID) */
+ COPS_OBJ_PPRID, /* Prefix Provisioning Instance Identifier (PPRID) */
+ COPS_OBJ_EPD, /* Encoded Provisioning Instance Data (EPD) */
+ COPS_OBJ_GPERR, /* Global Provisioning Error Object (GPERR) */
+ COPS_OBJ_CPERR, /* PRC Class Provisioning Error Object (CPERR) */
+ COPS_OBJ_ERRPRID, /* Error Provisioning Instance Identifier (ErrorPRID)*/
+
+ COPS_LAST_S_NUM /* For error checking */
+};
+
+
+static const value_string cops_s_num_vals[] = {
+ { COPS_OBJ_PRID, "Provisioning Instance Identifier (PRID)" },
+ { COPS_OBJ_PPRID, "Prefix Provisioning Instance Identifier (PPRID)" },
+ { COPS_OBJ_EPD, "Encoded Provisioning Instance Data (EPD)" },
+ { COPS_OBJ_GPERR, "Global Provisioning Error Object (GPERR)" },
+ { COPS_OBJ_CPERR, "PRC Class Provisioning Error Object (CPERR)" },
+ { COPS_OBJ_ERRPRID, "Error Provisioning Instance Identifier (ErrorPRID)" },
+ { 0, NULL },
+
+};
+
+/* R-Type is carried within the Context Object */
+static const value_string cops_r_type_vals[] = {
+ { 0x01, "Incoming-Message/Admission Control request" },
+ { 0x02, "Resource-Allocation request" },
+ { 0x04, "Outgoing-Message request" },
+ { 0x08, "Configuration request" },
+ { 0, NULL },
+};
+/* S-Type is carried within the ClientSI Object for COPS-PR*/
+static const value_string cops_s_type_vals[] = {
+ { 0x01, "BER" },
+ { 0, NULL },
+};
+
+/* Reason-Code is carried within the Reason object */
+static const value_string cops_reason_vals[] = {
+ { 1, "Unspecified" },
+ { 2, "Management" },
+ { 3, "Preempted (Another request state takes precedence)" },
+ { 4, "Tear (Used to communicate a signaled state removal)" },
+ { 5, "Timeout (Local state has timed-out)" },
+ { 6, "Route Change (Change invalidates request state)" },
+ { 7, "Insufficient Resources (No local resource available)" },
+ { 8, "PDP's Directive (PDP decision caused the delete)" },
+ { 9, "Unsupported decision (PDP decision not supported)" },
+ { 10, "Synchronize Handle Unknown" },
+ { 11, "Transient Handle (stateless event)" },
+ { 12, "Malformed Decision (could not recover)" },
+ { 13, "Unknown COPS Object from PDP" },
+ { 0, NULL },
+};
+
+/* Command-Code is carried within the Decision object if C-Type is 1 */
+static const value_string cops_dec_cmd_code_vals[] = {
+ { 0, "NULL Decision (No configuration data available)" },
+ { 1, "Install (Admit request/Install configuration)" },
+ { 2, "Remove (Remove request/Remove configuration)" },
+ { 0, NULL },
+};
+
+/* Decision flags are also carried with the Decision object if C-Type is 1 */
+static const value_string cops_dec_cmd_flag_vals[] = {
+ { 0x00, "<None set>" },
+ { 0x01, "Trigger Error (Trigger error message if set)" },
+ { 0, NULL },
+};
+
+/* Error-Code from Error object */
+static const value_string cops_error_vals[] = {
+ {1, "Bad handle" },
+ {2, "Invalid handle reference" },
+ {3, "Bad message format (Malformed Message)" },
+ {4, "Unable to process (server gives up on query)" },
+ {5, "Mandatory client-specific info missing" },
+ {6, "Unsupported client" },
+ {7, "Mandatory COPS object missing" },
+ {8, "Client Failure" },
+ {9, "Communication Failure" },
+ {10, "Unspecified" },
+ {11, "Shutting down" },
+ {12, "Redirect to Preferred Server" },
+ {13, "Unknown COPS Object" },
+ {14, "Authentication Failure" },
+ {15, "Authentication Required" },
+ {0, NULL },
+};
+/* Error-Code from GPERR object */
+static const value_string cops_gperror_vals[] = {
+ {1, "AvailMemLow" },
+ {2, "AvailMemExhausted" },
+ {3, "unknownASN.1Tag" },
+ {4, "maxMsgSizeExceeded" },
+ {5, "unknownError" },
+ {6, "maxRequestStatesOpen" },
+ {7, "invalidASN.1Length" },
+ {8, "invalidObjectPad" },
+ {9, "unknownPIBData" },
+ {10, "unknownCOPSPRObject" },
+ {11, "malformedDecision" },
+ {0, NULL },
+};
+
+/* Error-Code from CPERR object */
+static const value_string cops_cperror_vals[] = {
+ {1, "priSpaceExhausted" },
+ {2, "priInstanceInvalid" },
+ {3, "attrValueInvalid" },
+ {4, "attrValueSupLimited" },
+ {5, "attrEnumSupLimited" },
+ {6, "attrMaxLengthExceeded" },
+ {7, "attrReferenceUnknown" },
+ {8, "priNotifyOnly" },
+ {9, "unknownPrc" },
+ {10, "tooFewAttrs" },
+ {11, "invalidAttrType" },
+ {12, "deletedInRef" },
+ {13, "priSpecificError" },
+ {0, NULL },
+};
+
+
+/* Report-Type from Report-Type object */
+static const value_string cops_report_type_vals[] = {
+ {1, " Success : Decision was successful at the PEP" },
+ {2, " Failure : Decision could not be completed by PEP" },
+ {3, " Accounting: Accounting update for an installed state" },
+ {0, NULL },
+};
+
+/* The next tables are for PacketCable */
+
+/* Transaction ID table */
+static const value_string table_cops_transaction_id[] =
+{
+ { 0x1, "Gate Alloc" },
+ { 0x2, "Gate Alloc Ack" },
+ { 0x3, "Gate Alloc Err" },
+ { 0x4, "Gate Set" },
+ { 0x5, "Gate Set Ack" },
+ { 0x6, "Gate Set Err" },
+ { 0x7, "Gate Info" },
+ { 0x8, "Gate Info Ack" },
+ { 0x9, "Gate Info Err" },
+ { 0xa, "Gate Delete" },
+ { 0xb, "Gate Delete Ack" },
+ { 0xc, "Gate Delete Err" },
+ { 0xd, "Gate Open" },
+ { 0xe, "Gate Close" },
+ { 0xFF, NULL },
+};
+
+/* Direction */
+static const value_string table_cops_direction[] =
+{
+ { 0x0, "Downstream gate" },
+ { 0x1, "Upstream gate" },
+ { 0xFF, NULL },
+};
+
+/* Session Class */
+static const value_string table_cops_session_class[] =
+{
+ { 0x0, "Unspecified" },
+ { 0x1, "Normal priority VoIP session" },
+ { 0x2, "High priority VoIP session" },
+ { 0x3, "Reserved" },
+ { 0xFF, NULL },
+};
+
+/* Reason Code */
+static const value_string table_cops_reason_code[] =
+{
+ { 0x0, "Gate Delete Operation" },
+ { 0x1, "Gate Close Operation" },
+ { 0xFF, NULL },
+};
+
+/* Reason Sub Code - Delete */
+static const value_string table_cops_reason_subcode_delete[] =
+{
+ { 0x0, "Normal Operation" },
+ { 0x1, "Local Gate-coordination not completed" },
+ { 0x2, "Remote Gate-coordination not completed" },
+ { 0x3, "Authorization revoked" },
+ { 0x4, "Unexpected Gate-Open" },
+ { 0x5, "Local Gate-Close failure" },
+ { 0x127,"Unspecified error" },
+ { 0xFF, NULL },
+};
+
+/* Reason Sub Code - Close */
+static const value_string table_cops_reason_subcode_close[] =
+{
+ { 0x0, "Client initiated release (normal operation)" },
+ { 0x1, "Reservation reassignment" },
+ { 0x2, "Lack of reservation maintenance" },
+ { 0x3, "Lack of Docsis Mac-layer responses" },
+ { 0x4, "Timer T0 expiration; no Gate-Set received from CMS" },
+ { 0x5, "Timer T1 expiration; no Commit received from MTA" },
+ { 0x6, "Timer T7 expiration; Service Flow reservation timeout" },
+ { 0x7, "Timer T8 expiration; Service Flow inactivity in the upstream direction" },
+ { 0x127,"Unspecified error" },
+ { 0xFF, NULL },
+};
+
+/* PacketCable Error */
+static const value_string table_cops_packetcable_error[] =
+{
+ { 0x1, "No gates urrently available" },
+ { 0x2, "Unknown Gate ID" },
+ { 0x3, "Illegal Session Class value" },
+ { 0x4, "Subscriber exceeded gate limit" },
+ { 0x5, "Gate already set" },
+ { 0x6, "Missing Required Object" },
+ { 0x7, "Invalid Object" },
+ { 0x127,"Unspecified error" },
+ { 0xFF, NULL },
+};
+
+/* End of PacketCable Tables */
+
+
+/* Initialize the protocol and registered fields */
+static gint proto_cops = -1;
+static gint hf_cops_ver_flags = -1;
+static gint hf_cops_version = -1;
+static gint hf_cops_flags = -1;
+
+static gint hf_cops_op_code = -1;
+static gint hf_cops_client_type = -1;
+static gint hf_cops_msg_len = -1;
+
+static gint hf_cops_obj_len = -1;
+static gint hf_cops_obj_c_num = -1;
+static gint hf_cops_obj_c_type = -1;
+
+static gint hf_cops_obj_s_num = -1;
+static gint hf_cops_obj_s_type = -1;
+
+static gint hf_cops_r_type_flags = -1;
+static gint hf_cops_m_type_flags = -1;
+
+static gint hf_cops_in_int_ipv4 = -1;
+static gint hf_cops_in_int_ipv6 = -1;
+static gint hf_cops_out_int_ipv4 = -1;
+static gint hf_cops_out_int_ipv6 = -1;
+static gint hf_cops_int_ifindex = -1;
+
+static gint hf_cops_reason = -1;
+static gint hf_cops_reason_sub = -1;
+
+static gint hf_cops_dec_cmd_code = -1;
+static gint hf_cops_dec_flags = -1;
+
+static gint hf_cops_error = -1;
+static gint hf_cops_error_sub = -1;
+
+static gint hf_cops_gperror = -1;
+static gint hf_cops_gperror_sub = -1;
+
+static gint hf_cops_cperror = -1;
+static gint hf_cops_cperror_sub = -1;
+
+static gint hf_cops_katimer = -1;
+
+static gint hf_cops_pepid = -1;
+
+static gint hf_cops_report_type = -1;
+
+static gint hf_cops_pdprediraddr_ipv4 = -1;
+static gint hf_cops_pdprediraddr_ipv6 = -1;
+static gint hf_cops_lastpdpaddr_ipv4 = -1;
+static gint hf_cops_lastpdpaddr_ipv6 = -1;
+static gint hf_cops_pdp_tcp_port = -1;
+
+static gint hf_cops_accttimer = -1;
+
+static gint hf_cops_key_id = -1;
+static gint hf_cops_seq_num = -1;
+
+/* For PacketCable */
+static gint hf_cops_subtree = -1;
+static gint hf_cops_pc_activity_count = -1;
+static gint hf_cops_pc_algorithm = -1;
+static gint hf_cops_pc_close_subcode = -1;
+static gint hf_cops_pc_cmts_ip = -1;
+static gint hf_cops_pc_cmts_ip_port = -1;
+static gint hf_cops_pc_prks_ip = -1;
+static gint hf_cops_pc_prks_ip_port = -1;
+static gint hf_cops_pc_srks_ip = -1;
+static gint hf_cops_pc_srks_ip_port = -1;
+static gint hf_cops_pc_delete_subcode = -1;
+static gint hf_cops_pc_dest_ip = -1;
+static gint hf_cops_pc_dest_port = -1;
+static gint hf_cops_pc_direction = -1;
+static gint hf_cops_pc_ds_field = -1;
+static gint hf_cops_pc_gate_id = -1;
+static gint hf_cops_pc_gate_spec_flags = -1;
+static gint hf_cops_pc_gate_command_type = -1;
+static gint hf_cops_pc_key = -1;
+static gint hf_cops_pc_max_packet_size = -1;
+static gint hf_cops_pc_min_policed_unit = -1;
+static gint hf_cops_pc_packetcable_err_code = -1;
+static gint hf_cops_pc_packetcable_sub_code = -1;
+static gint hf_cops_pc_peak_data_rate = -1;
+static gint hf_cops_pc_protocol_id = -1;
+static gint hf_cops_pc_reason_code = -1;
+static gint hf_cops_pc_remote_flags = -1;
+static gint hf_cops_pc_remote_gate_id = -1;
+static gint hf_cops_pc_reserved = -1;
+static gint hf_cops_pc_session_class = -1;
+static gint hf_cops_pc_slack_term = -1;
+static gint hf_cops_pc_spec_rate = -1;
+static gint hf_cops_pc_src_ip = -1;
+static gint hf_cops_pc_src_port = -1;
+static gint hf_cops_pc_subscriber_id = -1;
+static gint hf_cops_pc_t1_value = -1;
+static gint hf_cops_pc_t7_value = -1;
+static gint hf_cops_pc_t8_value = -1;
+static gint hf_cops_pc_token_bucket_rate = -1;
+static gint hf_cops_pc_token_bucket_size = -1;
+static gint hf_cops_pc_transaction_id = -1;
+static gint hf_cops_pc_bcid_ts = -1;
+static gint hf_cops_pc_bcid = -1;
+static gint hf_cops_pc_bcid_ev = -1;
+static gint hf_cops_pc_dfcdc_ip = -1;
+static gint hf_cops_pc_dfccc_ip = -1;
+static gint hf_cops_pc_dfcdc_ip_port = -1;
+static gint hf_cops_pc_dfccc_ip_port = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_cops = -1;
+static gint ett_cops_ver_flags = -1;
+static gint ett_cops_obj = -1;
+static gint ett_cops_pr_obj = -1;
+static gint ett_cops_obj_data = -1;
+static gint ett_cops_r_type_flags = -1;
+static gint ett_cops_itf = -1;
+static gint ett_cops_reason = -1;
+static gint ett_cops_decision = -1;
+static gint ett_cops_error = -1;
+static gint ett_cops_clientsi = -1;
+static gint ett_cops_asn1 = -1;
+static gint ett_cops_gperror = -1;
+static gint ett_cops_cperror = -1;
+static gint ett_cops_pdp = -1;
+
+/* For PacketCable */
+static gint ett_cops_subtree = -1;
+
+void proto_reg_handoff_cops(void);
+
+static guint get_cops_pdu_len(tvbuff_t *tvb, int offset);
+static void dissect_cops_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+
+static int dissect_cops_object(tvbuff_t *tvb, guint32 offset, proto_tree *tree);
+static void dissect_cops_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
+ guint8 c_num, guint8 c_type, guint16 len);
+
+static void dissect_cops_pr_objects(tvbuff_t *tvb, guint32 offset, proto_tree *tree, guint16 pr_len);
+static int dissect_cops_pr_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
+ guint8 s_num, guint8 s_type, guint16 len);
+
+/* Added for PacketCable */
+proto_tree *info_to_cops_subtree(tvbuff_t *, proto_tree *, int, int, char *);
+void info_to_display(tvbuff_t *, proto_item *, int, int, char *, const value_string *, int, gint *);
+void cops_transaction_id(tvbuff_t *, proto_tree *, guint, guint32);
+void cops_subscriber_id_v4(tvbuff_t *, proto_tree *, guint, guint32);
+void cops_gate_id(tvbuff_t *, proto_tree *, guint, guint32);
+void cops_activity_count(tvbuff_t *, proto_tree *, guint, guint32);
+void cops_gate_specs(tvbuff_t *, proto_tree *, guint, guint32);
+void cops_remote_gate_info(tvbuff_t *, proto_tree *, guint, guint32);
+void cops_packetcable_reason(tvbuff_t *, proto_tree *, guint, guint32);
+void cops_packetcable_error(tvbuff_t *, proto_tree *, guint, guint32);
+void cops_analyze_packetcable_obj(tvbuff_t *, proto_tree *, guint32);
+void cops_event_generation_info(tvbuff_t *, proto_tree *, guint, guint32);
+void cops_surveillance_parameters(tvbuff_t *, proto_tree *, guint, guint32);
+
+static packet_info *cpinfo;
+static guint8 opcode_idx;
+static gboolean cops_packetcable = TRUE;
+/* End of addition for PacketCable */
+
+
+/* Code to actually dissect the packets */
+static void
+dissect_cops(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ tcp_dissect_pdus(tvb, pinfo, tree, cops_desegment, 8,
+ get_cops_pdu_len, dissect_cops_pdu);
+}
+
+static guint
+get_cops_pdu_len(tvbuff_t *tvb, int offset)
+{
+ /*
+ * Get the length of the COPS message.
+ */
+ return tvb_get_ntohl(tvb, offset + 4);
+}
+
+static void
+dissect_cops_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ guint8 op_code;
+ int object_len;
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "COPS");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_clear(pinfo->cinfo, COL_INFO);
+
+ op_code = tvb_get_guint8(tvb, 1);
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_fstr(pinfo->cinfo, COL_INFO, "COPS %s",
+ val_to_str(op_code, cops_op_code_vals, "Unknown Op Code"));
+
+ /* PacketCable: Remember the next two values to manipulate the info field in the Gui */
+ cpinfo = pinfo;
+ opcode_idx = op_code;
+
+ if (tree) {
+ proto_item *ti, *tv;
+ proto_tree *cops_tree, *ver_flags_tree;
+ guint32 msg_len;
+ guint32 offset = 0;
+ guint8 ver_flags;
+ gint garbage;
+
+ ti = proto_tree_add_item(tree, proto_cops, tvb, offset, -1, FALSE);
+ cops_tree = proto_item_add_subtree(ti, ett_cops);
+
+ /* Version and flags share the same byte, put them in a subtree */
+ ver_flags = tvb_get_guint8(tvb, offset);
+ tv = proto_tree_add_uint_format(cops_tree, hf_cops_ver_flags, tvb, offset, 1,
+ ver_flags, "Version: %u, Flags: %s",
+ hi_nibble(ver_flags),
+ val_to_str(lo_nibble(ver_flags), cops_flags_vals, "Unknown"));
+ ver_flags_tree = proto_item_add_subtree(tv, ett_cops_ver_flags);
+ proto_tree_add_uint(ver_flags_tree, hf_cops_version, tvb, offset, 1, ver_flags);
+ proto_tree_add_uint(ver_flags_tree, hf_cops_flags, tvb, offset, 1, ver_flags);
+ offset++;
+
+ proto_tree_add_item(cops_tree, hf_cops_op_code, tvb, offset, 1, FALSE);
+ offset ++;
+ proto_tree_add_item(cops_tree, hf_cops_client_type, tvb, offset, 2, FALSE);
+ offset += 2;
+
+ msg_len = tvb_get_ntohl(tvb, offset);
+ proto_tree_add_uint(cops_tree, hf_cops_msg_len, tvb, offset, 4, msg_len);
+ offset += 4;
+
+ while (tvb_reported_length_remaining(tvb, offset) >= COPS_OBJECT_HDR_SIZE) {
+ object_len = dissect_cops_object(tvb, offset, cops_tree);
+ if (object_len < 0)
+ return;
+ offset += object_len;
+ }
+
+ garbage = tvb_length_remaining(tvb, offset);
+ if (garbage > 0)
+ proto_tree_add_text(cops_tree, tvb, offset, garbage,
+ "Trailing garbage: %d byte%s", garbage,
+ plurality(garbage, "", "s"));
+ }
+}
+
+static char *cops_c_type_to_str(guint8 c_num, guint8 c_type)
+{
+ switch (c_num) {
+ case COPS_OBJ_HANDLE:
+ if (c_type == 1)
+ return "Client Handle";
+ break;
+ case COPS_OBJ_IN_INT:
+ case COPS_OBJ_OUT_INT:
+ if (c_type == 1)
+ return "IPv4 Address + Interface";
+ else if (c_type == 2)
+ return "IPv6 Address + Interface";
+ break;
+ case COPS_OBJ_DECISION:
+ case COPS_OBJ_LPDPDECISION:
+ if (c_type == 1)
+ return "Decision Flags (Mandatory)";
+ else if (c_type == 2)
+ return "Stateless Data";
+ else if (c_type == 3)
+ return "Replacement Data";
+ else if (c_type == 4)
+ return "Client Specific Decision Data";
+ else if (c_type == 5)
+ return "Named Decision Data";
+ break;
+ case COPS_OBJ_CLIENTSI:
+ if (c_type == 1)
+ return "Signaled ClientSI";
+ else if (c_type == 2)
+ return "Named ClientSI";
+ break;
+ case COPS_OBJ_KATIMER:
+ if (c_type == 1)
+ return "Keep-alive timer value";
+ break;
+ case COPS_OBJ_PDPREDIRADDR:
+ case COPS_OBJ_LASTPDPADDR:
+ if (c_type == 1)
+ return "IPv4 Address + TCP Port";
+ else if (c_type == 2)
+ return "IPv6 Address + TCP Port";
+ break;
+ case COPS_OBJ_ACCTTIMER:
+ if (c_type == 1)
+ return "Accounting timer value";
+ break;
+ case COPS_OBJ_INTEGRITY:
+ if (c_type == 1)
+ return "HMAC digest";
+ break;
+ }
+
+ return "";
+}
+
+static int dissect_cops_object(tvbuff_t *tvb, guint32 offset, proto_tree *tree)
+{
+ guint16 object_len, contents_len;
+ guint8 c_num, c_type;
+ proto_item *ti;
+ proto_tree *obj_tree;
+ char *type_str;
+
+ object_len = tvb_get_ntohs(tvb, offset);
+ if (object_len < COPS_OBJECT_HDR_SIZE) {
+ /* Bogus! */
+ proto_tree_add_text(tree, tvb, offset, 2,
+ "Bad COPS object length: %u, should be at least %u",
+ object_len, COPS_OBJECT_HDR_SIZE);
+ return -1;
+ }
+ c_num = tvb_get_guint8(tvb, offset + 2);
+ c_type = tvb_get_guint8(tvb, offset + 3);
+
+ ti = proto_tree_add_uint_format(tree, hf_cops_obj_c_num, tvb, offset, object_len, c_num,
+ "%s: %s", val_to_str(c_num, cops_c_num_vals, "Unknown"),
+ cops_c_type_to_str(c_num, c_type));
+ obj_tree = proto_item_add_subtree(ti, ett_cops_obj);
+
+ proto_tree_add_uint(obj_tree, hf_cops_obj_len, tvb, offset, 2, object_len);
+ offset += 2;
+
+ proto_tree_add_uint(obj_tree, hf_cops_obj_c_num, tvb, offset, 1, c_num);
+ offset++;
+
+ type_str = cops_c_type_to_str(c_num, c_type);
+ proto_tree_add_text(obj_tree, tvb, offset, 1, "C-Type: %s%s%u%s",
+ type_str,
+ strlen(type_str) ? " (" : "",
+ c_type,
+ strlen(type_str) ? ")" : "");
+ offset++;
+
+ contents_len = object_len - COPS_OBJECT_HDR_SIZE;
+ dissect_cops_object_data(tvb, offset, obj_tree, c_num, c_type, contents_len);
+
+ /* Pad to 32bit boundary */
+ if (object_len % sizeof (guint32))
+ object_len += (sizeof (guint32) - object_len % sizeof (guint32));
+
+ return object_len;
+}
+
+static void dissect_cops_pr_objects(tvbuff_t *tvb, guint32 offset, proto_tree *tree, guint16 pr_len)
+{
+ guint16 object_len, contents_len;
+ guint8 s_num, s_type;
+ char *type_str;
+ int ret;
+ proto_tree *cops_pr_tree, *obj_tree;
+ proto_item *ti;
+
+ cops_pr_tree = proto_item_add_subtree(tree, ett_cops_pr_obj);
+
+ while (pr_len >= COPS_OBJECT_HDR_SIZE) {
+ object_len = tvb_get_ntohs(tvb, offset);
+ if (object_len < COPS_OBJECT_HDR_SIZE) {
+ /* Bogus! */
+ proto_tree_add_text(tree, tvb, offset, 2,
+ "Bad COPS PR object length: %u, should be at least %u",
+ object_len, COPS_OBJECT_HDR_SIZE);
+ return;
+ }
+ s_num = tvb_get_guint8(tvb, offset + 2);
+
+ ti = proto_tree_add_uint_format(cops_pr_tree, hf_cops_obj_s_num, tvb, offset, object_len, s_num,
+ "%s", val_to_str(s_num, cops_s_num_vals, "Unknown"));
+ obj_tree = proto_item_add_subtree(cops_pr_tree, ett_cops_pr_obj);
+
+ proto_tree_add_uint(obj_tree, hf_cops_obj_len, tvb, offset, 2, object_len);
+ offset += 2;
+ pr_len -= 2;
+
+ proto_tree_add_uint(obj_tree, hf_cops_obj_s_num, tvb, offset, 1, s_num);
+ offset++;
+ pr_len--;
+
+ s_type = tvb_get_guint8(tvb, offset);
+ type_str = val_to_str(s_type, cops_s_type_vals, "Unknown");
+ proto_tree_add_text(obj_tree, tvb, offset, 1, "S-Type: %s%s%u%s",
+ type_str,
+ strlen(type_str) ? " (" : "",
+ s_type,
+ strlen(type_str) ? ")" : "");
+ offset++;
+ pr_len--;
+
+ contents_len = object_len - COPS_OBJECT_HDR_SIZE;
+ ret = dissect_cops_pr_object_data(tvb, offset, obj_tree, s_num, s_type, contents_len);
+ if (ret < 0)
+ break;
+
+ /*Pad to 32bit boundary */
+ if (object_len % sizeof (guint32))
+ object_len += (sizeof (guint32) - object_len % sizeof (guint32));
+
+ pr_len -= object_len - COPS_OBJECT_HDR_SIZE;
+ offset += object_len - COPS_OBJECT_HDR_SIZE;
+ }
+}
+
+static void dissect_cops_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
+ guint8 c_num, guint8 c_type, guint16 len)
+{
+ proto_item *ti;
+ proto_tree *r_type_tree, *itf_tree, *reason_tree, *dec_tree, *error_tree, *clientsi_tree, *pdp_tree;
+ guint16 r_type, m_type, reason, reason_sub, cmd_code, cmd_flags, error, error_sub, tcp_port;
+ guint32 ipv4addr, ifindex;
+ struct e_in6_addr ipv6addr;
+
+ switch (c_num) {
+ case COPS_OBJ_CONTEXT:
+ r_type = tvb_get_ntohs(tvb, offset);
+ m_type = tvb_get_ntohs(tvb, offset + 2);
+ ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: R-Type: %s, M-Type: %u",
+ val_to_str(r_type, cops_r_type_vals, "Unknown"),
+ m_type);
+
+ r_type_tree = proto_item_add_subtree(ti, ett_cops_r_type_flags);
+ proto_tree_add_uint(r_type_tree, hf_cops_r_type_flags, tvb, offset, 2, r_type);
+ offset += 2;
+ proto_tree_add_uint(r_type_tree, hf_cops_m_type_flags, tvb, offset, 2, m_type);
+
+ break;
+ case COPS_OBJ_IN_INT:
+ case COPS_OBJ_OUT_INT:
+ if (c_type == 1) { /* IPv4 */
+ tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset, 4);
+ ifindex = tvb_get_ntohl(tvb, offset + 4);
+ ti = proto_tree_add_text(tree, tvb, offset, 8, "Contents: IPv4 address %s, ifIndex: %u",
+ ip_to_str((guint8 *)&ipv4addr), ifindex);
+ itf_tree = proto_item_add_subtree(ti, ett_cops_itf);
+ proto_tree_add_ipv4(itf_tree,
+ (c_num == COPS_OBJ_IN_INT) ? hf_cops_in_int_ipv4 : hf_cops_out_int_ipv4,
+ tvb, offset, 4, ipv4addr);
+ offset += 4;
+ } else if (c_type == 2) { /* IPv6 */
+ tvb_memcpy(tvb, (guint8 *)&ipv6addr, offset, sizeof ipv6addr);
+ ifindex = tvb_get_ntohl(tvb, offset + sizeof ipv6addr);
+ ti = proto_tree_add_text(tree, tvb, offset, 20, "Contents: IPv6 address %s, ifIndex: %u",
+ ip6_to_str(&ipv6addr), ifindex);
+ itf_tree = proto_item_add_subtree(ti, ett_cops_itf);
+ proto_tree_add_ipv6(itf_tree,
+ (c_num == COPS_OBJ_IN_INT) ? hf_cops_in_int_ipv6 : hf_cops_out_int_ipv6,
+ tvb, offset, 16, (guint8 *)&ipv6addr);
+ offset += 16;
+ } else {
+ break;
+ }
+ proto_tree_add_uint(itf_tree, hf_cops_int_ifindex, tvb, offset, 4, ifindex);
+
+ break;
+ case COPS_OBJ_REASON:
+ reason = tvb_get_ntohs(tvb, offset);
+ reason_sub = tvb_get_ntohs(tvb, offset + 2);
+ ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Reason-Code: %s, Reason Sub-code: 0x%04x",
+ val_to_str(reason, cops_reason_vals, "<Unknown value>"), reason_sub);
+ reason_tree = proto_item_add_subtree(ti, ett_cops_reason);
+ proto_tree_add_uint(reason_tree, hf_cops_reason, tvb, offset, 2, reason);
+ offset += 2;
+ if (reason == 13) {
+ proto_tree_add_text(reason_tree, tvb, offset, 2, "Reason Sub-code: "
+ "Unknown object's C-Num %u, C-Type %u",
+ tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
+ } else
+ proto_tree_add_uint(reason_tree, hf_cops_reason_sub, tvb, offset, 2, reason_sub);
+
+ break;
+ case COPS_OBJ_DECISION:
+ case COPS_OBJ_LPDPDECISION:
+ if (c_type == 1) {
+ cmd_code = tvb_get_ntohs(tvb, offset);
+ cmd_flags = tvb_get_ntohs(tvb, offset + 2);
+ ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Command-Code: %s, Flags: %s",
+ val_to_str(cmd_code, cops_dec_cmd_code_vals, "<Unknown value>"),
+ val_to_str(cmd_flags, cops_dec_cmd_flag_vals, "<Unknown flag>"));
+ dec_tree = proto_item_add_subtree(ti, ett_cops_decision);
+ proto_tree_add_uint(dec_tree, hf_cops_dec_cmd_code, tvb, offset, 2, cmd_code);
+ offset += 2;
+ proto_tree_add_uint(dec_tree, hf_cops_dec_flags, tvb, offset, 2, cmd_flags);
+ } else if (c_type == 5) { /*COPS-PR Data*/
+ ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: %u bytes", len);
+ dec_tree = proto_item_add_subtree(ti, ett_cops_decision);
+ dissect_cops_pr_objects(tvb, offset, dec_tree, len);
+ }
+
+ /* PacketCable : Analyze the remaining data if available */
+ cops_analyze_packetcable_obj(tvb, tree, offset);
+
+ break;
+ case COPS_OBJ_ERROR:
+ if (c_type != 1)
+ break;
+
+ error = tvb_get_ntohs(tvb, offset);
+ error_sub = tvb_get_ntohs(tvb, offset + 2);
+ ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
+ val_to_str(error, cops_error_vals, "<Unknown value>"), error_sub);
+ error_tree = proto_item_add_subtree(ti, ett_cops_error);
+ proto_tree_add_uint(error_tree, hf_cops_error, tvb, offset, 2, error);
+ offset += 2;
+ if (error == 13) {
+ proto_tree_add_text(error_tree, tvb, offset, 2, "Error Sub-code: "
+ "Unknown object's C-Num %u, C-Type %u",
+ tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
+ } else
+ proto_tree_add_uint(error_tree, hf_cops_error_sub, tvb, offset, 2, error_sub);
+
+ break;
+ case COPS_OBJ_CLIENTSI:
+
+ /* For PacketCable */
+ if (c_type == 1) {
+ cops_analyze_packetcable_obj(tvb, tree, offset);
+ break;
+ }
+
+ if (c_type != 2) /*Not COPS-PR data*/
+ break;
+
+ ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: %u bytes", len);
+ clientsi_tree = proto_item_add_subtree(ti, ett_cops_clientsi);
+
+ dissect_cops_pr_objects(tvb, offset, clientsi_tree, len);
+
+ break;
+ case COPS_OBJ_KATIMER:
+ if (c_type != 1)
+ break;
+
+ proto_tree_add_item(tree, hf_cops_katimer, tvb, offset + 2, 2, FALSE);
+ if (tvb_get_ntohs(tvb, offset + 2) == 0)
+ proto_tree_add_text(tree, tvb, offset, 0, "Value of zero implies infinity.");
+
+ break;
+ case COPS_OBJ_PEPID:
+ if (c_type != 1)
+ break;
+
+ if (tvb_strnlen(tvb, offset, len) == -1)
+ proto_tree_add_text(tree, tvb, offset, len, "<PEP Id is not a NUL terminated ASCII string>");
+ else
+ proto_tree_add_item(tree, hf_cops_pepid, tvb, offset,
+ tvb_strnlen(tvb, offset, len) + 1, FALSE);
+
+ break;
+ case COPS_OBJ_REPORT_TYPE:
+ if (c_type != 1)
+ break;
+
+ proto_tree_add_item(tree, hf_cops_report_type, tvb, offset, 2, FALSE);
+
+ break;
+ case COPS_OBJ_PDPREDIRADDR:
+ case COPS_OBJ_LASTPDPADDR:
+ if (c_type == 1) { /* IPv4 */
+ tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset, 4);
+ tcp_port = tvb_get_ntohs(tvb, offset + 4 + 2);
+ ti = proto_tree_add_text(tree, tvb, offset, 8, "Contents: IPv4 address %s, TCP Port Number: %u",
+ ip_to_str((guint8 *)&ipv4addr), tcp_port);
+ pdp_tree = proto_item_add_subtree(ti, ett_cops_pdp);
+ proto_tree_add_ipv4(pdp_tree,
+ (c_num == COPS_OBJ_PDPREDIRADDR) ? hf_cops_pdprediraddr_ipv4 : hf_cops_lastpdpaddr_ipv4,
+ tvb, offset, 4, ipv4addr);
+ offset += 4;
+ } else if (c_type == 2) { /* IPv6 */
+ tvb_memcpy(tvb, (guint8 *)&ipv6addr, offset, sizeof ipv6addr);
+ tcp_port = tvb_get_ntohs(tvb, offset + sizeof ipv6addr + 2);
+ ti = proto_tree_add_text(tree, tvb, offset, 20, "Contents: IPv6 address %s, TCP Port Number: %u",
+ ip6_to_str(&ipv6addr), tcp_port);
+ pdp_tree = proto_item_add_subtree(ti, ett_cops_pdp);
+ proto_tree_add_ipv6(pdp_tree,
+ (c_num == COPS_OBJ_PDPREDIRADDR) ? hf_cops_pdprediraddr_ipv6 : hf_cops_lastpdpaddr_ipv6,
+ tvb, offset, 16, (guint8 *)&ipv6addr);
+ offset += 16;
+ } else {
+ break;
+ }
+ offset += 2;
+ proto_tree_add_uint(pdp_tree, hf_cops_pdp_tcp_port, tvb, offset, 2, tcp_port);
+
+ break;
+ case COPS_OBJ_ACCTTIMER:
+ if (c_type != 1)
+ break;
+
+ proto_tree_add_item(tree, hf_cops_accttimer, tvb, offset + 2, 2, FALSE);
+ if (tvb_get_ntohs(tvb, offset + 2) == 0)
+ proto_tree_add_text(tree, tvb, offset, 0, "Value of zero means "
+ "there SHOULD be no unsolicited accounting updates.");
+
+ break;
+ case COPS_OBJ_INTEGRITY:
+ if (c_type != 1)
+ break; /* Not HMAC digest */
+
+ proto_tree_add_item(tree, hf_cops_key_id, tvb, offset, 4, FALSE);
+ proto_tree_add_item(tree, hf_cops_seq_num, tvb, offset + 4, 4, FALSE);
+ proto_tree_add_text(tree, tvb, offset + 8 , len - 8, "Contents: Keyed Message Digest");
+
+ break;
+ default:
+ proto_tree_add_text(tree, tvb, offset, len, "Contents: %u bytes", len);
+
+ break;
+ }
+}
+
+#ifdef HAVE_NET_SNMP
+static guchar*format_asn_value (struct variable_list *variable, subid_t *variable_oid,
+ guint variable_oid_length, u_char type_from_packet)
+{
+ struct tree *subtree=tree_head;
+
+ guchar *buf=NULL;
+ size_t buf_len=0;
+ size_t out_len=0;
+
+ /*Get the ASN.1 type etc. from the PIB-MIB. If unsuccessful use the type from packet*/
+ subtree = get_tree(variable_oid,variable_oid_length, subtree);
+
+ if (subtree->type == 0)
+ variable->type= type_from_packet;
+
+ buf_len = SPRINT_MAX_LEN; /*defined in NET-SNMP's snmp-impl.h*/
+ buf = g_malloc(buf_len);
+ *buf = '\0';
+ out_len = 0;
+
+ /*If the ASN.1 type was found from PIB-MIB, use it for decoding*/
+ if (!variable->type)
+ variable->type=mib_to_asn_type(subtree->type);
+
+ if (!sprint_realloc_by_type(&buf, &buf_len, &out_len, TRUE, variable, subtree->enums, subtree->hint, NULL))
+ sprintf(buf,"%s","sprint_realloc_by_type failed");
+
+ return buf;
+}
+#endif /* HAVE_NET_SNMP */
+
+static int decode_cops_pr_asn1_data(tvbuff_t *tvb, guint32 offset,
+ proto_tree *tree, guint asnlen, guint8 cops_pr_obj
+#ifndef HAVE_NET_SNMP
+ _U_
+#endif
+ )
+{
+ ASN1_SCK asn1;
+ int start;
+ gboolean def;
+ guint length;
+
+ guint vb_length;
+ gushort vb_type;
+ gchar *vb_type_name;
+
+ int ret;
+ guint cls, con, tag;
+ subid_t epd_attribute_index=0;
+
+ gint32 vb_integer_value;
+ guint32 vb_uinteger_value;
+
+ guint8 *vb_octet_string;
+
+ subid_t *vb_oid;
+ guint vb_oid_length;
+
+ gchar *vb_display_string;
+ gchar *vb_display_string2;
+
+#ifdef HAVE_NET_SNMP
+ struct variable_list variable;
+ long value;
+#endif /* HAVE_NET_SNMP */
+
+ unsigned int i;
+ gchar *buf;
+ int len;
+
+ while (asnlen > 0) { /*while there is ASN stuff to be decoded*/
+
+ epd_attribute_index++;
+#ifdef HAVE_NET_SNMP
+ last_decoded_prid_oid[last_decoded_prid_oid_length-1]=epd_attribute_index;
+#endif /* HAVE_NET_SNMP */
+ asn1_open(&asn1, tvb, offset);
+
+ /* parse the type of the object */
+
+ start = asn1.offset;
+
+ ret = asn1_header_decode (&asn1, &cls, &con, &tag, &def, &vb_length);
+ if (ret != ASN1_ERR_NOERROR)
+ return 0;
+ if (!def)
+ return ASN1_ERR_LENGTH_NOT_DEFINITE;
+
+ /* Convert the class, constructed flag, and tag to a type. */
+ vb_type_name = cops_tag_cls2syntax(tag, cls, &vb_type);
+ if (vb_type_name == NULL) {
+ /*
+ * Unsupported type.
+ * Dissect the value as an opaque string of octets.
+ */
+ vb_type_name = "unsupported type";
+ vb_type = COPS_OPAQUE;
+ }
+
+ /* parse the value */
+
+ switch (vb_type) {
+
+ case COPS_INTEGER:
+ ret = asn1_int32_value_decode(&asn1, vb_length, &vb_integer_value);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ length = asn1.offset - start;
+ if (tree) {
+#ifdef HAVE_NET_SNMP
+ if (cops_typefrommib == TRUE)
+ {
+ variable.type = 0;
+ value = vb_integer_value;
+ variable.val.integer = &value;
+ variable.val_len = vb_length ;
+ vb_display_string=format_asn_value(&variable,
+ last_decoded_prid_oid,last_decoded_prid_oid_length,ASN_INTEGER);
+
+ proto_tree_add_text(tree, asn1.tvb, offset, length,
+ "Value: %s", vb_display_string);
+ g_free(vb_display_string);
+ }
+ else
+#endif /* HAVE_NET_SNMP */
+ proto_tree_add_text(tree, asn1.tvb, offset, length,
+ "Value: %s: %d (%#x)", vb_type_name,
+ vb_integer_value, vb_integer_value);
+ }
+ break;
+
+ case COPS_UNSIGNED32:
+ case COPS_TIMETICKS:
+ ret = asn1_uint32_value_decode(&asn1, vb_length, &vb_uinteger_value);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ length = asn1.offset - start;
+ if (tree) {
+#ifdef HAVE_NET_SNMP
+ if (cops_typefrommib == TRUE)
+ {
+ variable.type = 0;
+ value = vb_uinteger_value;
+ variable.val.integer = &value;
+ variable.val_len = vb_length;
+
+ vb_display_string=format_asn_value(&variable,
+ last_decoded_prid_oid,last_decoded_prid_oid_length,ASN_UINTEGER);
+
+ proto_tree_add_text(tree, asn1.tvb, offset, length, "Value %s: %s",vb_type_name, vb_display_string);
+
+ g_free(vb_display_string);
+ }
+ else
+#endif /* HAVE_NET_SNMP */
+ proto_tree_add_text(tree, asn1.tvb, offset, length,
+ "Value: %s: %u (%#x)", vb_type_name,
+ vb_uinteger_value, vb_uinteger_value);
+ }
+ break;
+
+ case COPS_OCTETSTR:
+ case COPS_IPADDR:
+ case COPS_OPAQUE:
+ case COPS_UNSIGNED64:
+ case COPS_INTEGER64:
+ ret = asn1_string_value_decode (&asn1, vb_length, &vb_octet_string);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ length = asn1.offset - start;
+ if (tree) {
+#ifdef HAVE_NET_SNMP
+ if (cops_typefrommib == TRUE)
+ {
+ variable.type = 0;
+ variable.val.string = vb_octet_string;
+ variable.val_len = vb_length;
+ vb_display_string = format_asn_value(&variable,
+ last_decoded_prid_oid,last_decoded_prid_oid_length,ASN_OCTET_STR);
+ proto_tree_add_text(tree, asn1.tvb, offset, length,
+ "Value: %s (ASN.1 type from packet: %s)", vb_display_string, vb_type_name);
+
+ g_free(vb_display_string);
+ }
+ else
+ {
+#endif /* HAVE_NET_SNMP */
+ for (i = 0; i < vb_length; i++) {
+ if (!(isprint(vb_octet_string[i]) ||isspace(vb_octet_string[i])))
+ break;
+ }
+
+ /*
+ * If some characters are not printable, display the string as bytes.
+ */
+ if (i < vb_length) {
+ /*
+ * We stopped, due to a non-printable character, before we got
+ * to the end of the string.
+ */
+ vb_display_string = g_malloc(4*vb_length);
+ buf = &vb_display_string[0];
+ len = sprintf(buf, "%03u", vb_octet_string[0]);
+ buf += len;
+ for (i = 1; i < vb_length; i++) {
+ len = sprintf(buf, ".%03u", vb_octet_string[i]);
+ buf += len;
+ }
+ proto_tree_add_text(tree, asn1.tvb, offset, length,
+ "Value: %s: %s", vb_type_name, vb_display_string);
+ g_free(vb_display_string);
+ } else {
+ proto_tree_add_text(tree, asn1.tvb, offset, length,
+ "Value: %s: %.*s", vb_type_name, (int)vb_length,
+ SAFE_STRING(vb_octet_string));
+ }
+#ifdef HAVE_NET_SNMP
+ }
+#endif /* HAVE_NET_SNMP */
+ }
+ g_free(vb_octet_string);
+ break;
+
+ case COPS_NULL:
+ ret = asn1_null_decode (&asn1, vb_length);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ length = asn1.offset - start;
+ if (tree)
+ proto_tree_add_text(tree, asn1.tvb, offset, length, "Value: %s", vb_type_name);
+ break;
+
+ case COPS_OBJECTID:
+ ret = asn1_oid_value_decode (&asn1, vb_length, &vb_oid, &vb_oid_length);
+ if (ret != ASN1_ERR_NOERROR)
+ return ret;
+ length = asn1.offset - start;
+
+ if (tree) {
+ if (cops_pr_obj == COPS_OBJ_PPRID){
+ /*we're decoding Prefix PRID, that doesn't have a instance Id,
+ *Use full length of the OID when decoding it.
+ */
+ new_format_oid(vb_oid,vb_oid_length,&vb_display_string,&vb_display_string2);
+
+ if (!vb_display_string2) /*if OID couldn't be decoded, print only numeric format*/
+ proto_tree_add_text(tree, asn1.tvb, offset, length,
+ "Value: %s: %s", vb_type_name, vb_display_string);
+ else
+ proto_tree_add_text(tree, asn1.tvb, offset, length,
+ "Value: %s: %s (%s)", vb_type_name,
+ vb_display_string,
+ vb_display_string2);
+ }
+ else { /*we're decoding PRID, Error PRID or EPD*/
+ /*strip the instance Id from the OIDs before decoding and paste it back during printing*/
+ new_format_oid(vb_oid,vb_oid_length-1,&vb_display_string,&vb_display_string2);
+
+ if (!vb_display_string2) /*if OID couldn't be decoded, print only numeric format*/
+ proto_tree_add_text(tree, asn1.tvb, offset, length,
+ "Value: %s: %s.%lu", vb_type_name,
+ vb_display_string,
+ (unsigned long)vb_oid[vb_oid_length-1]);
+ else
+ proto_tree_add_text(tree, asn1.tvb, offset, length,
+ "Value: %s: %s.%lu (%s.%lu)", vb_type_name,
+ vb_display_string,
+ (unsigned long)vb_oid[vb_oid_length-1],
+ vb_display_string2,
+ (unsigned long)vb_oid[vb_oid_length-1]);
+ }
+#ifdef HAVE_NET_SNMP
+ if (cops_pr_obj != COPS_OBJ_EPD) {
+ /* we're not decoding EPD, so let's store the OID of the PRID so that later
+ when we're decoding this PRID's EPD we can finetune the output.*/
+ memcpy(last_decoded_prid_oid,vb_oid,vb_oid_length*sizeof(subid_t));
+ last_decoded_prid_oid_length=vb_oid_length;
+ }
+#endif /* HAVE_NET_SNMP */
+
+ g_free(vb_display_string);
+ if(vb_display_string2)
+ g_free(vb_display_string2);
+ }
+ g_free(vb_oid);
+ break;
+
+ default:
+ g_assert_not_reached();
+ return ASN1_ERR_WRONG_TYPE;
+ }
+
+ asn1_close(&asn1,&offset);
+
+ asnlen -= length;
+ }
+ epd_attribute_index=0;
+ return 0;
+}
+
+static int dissect_cops_pr_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
+ guint8 s_num, guint8 s_type, guint16 len)
+{
+ proto_item *ti;
+ proto_tree *asn1_object_tree, *gperror_tree, *cperror_tree;
+ guint16 gperror=0, gperror_sub=0, cperror=0, cperror_sub=0;
+
+ switch (s_num){
+ case COPS_OBJ_PRID:
+ if (s_type != 1) /* Not Provisioning Instance Identifier (PRID) */
+ break;
+
+ ti=proto_tree_add_text(tree, tvb, offset, len, "Contents:");
+ asn1_object_tree = proto_item_add_subtree(ti, ett_cops_asn1);
+
+ decode_cops_pr_asn1_data(tvb, offset, asn1_object_tree, len, COPS_OBJ_PRID);
+
+ break;
+ case COPS_OBJ_PPRID:
+ if (s_type != 1) /* Not Prefix Provisioning Instance Identifier (PPRID) */
+ break;
+
+ ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
+ asn1_object_tree = proto_item_add_subtree(ti, ett_cops_asn1);
+
+ decode_cops_pr_asn1_data(tvb, offset, asn1_object_tree, len, COPS_OBJ_PPRID);
+
+ break;
+ case COPS_OBJ_EPD:
+ if (s_type != 1) /* Not Encoded Provisioning Instance Data (EPD) */
+ break;
+
+ ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
+ asn1_object_tree = proto_item_add_subtree(ti, ett_cops_asn1);
+
+ decode_cops_pr_asn1_data(tvb, offset, asn1_object_tree, len, COPS_OBJ_EPD);
+
+ break;
+ case COPS_OBJ_GPERR:
+ if (s_type != 1) /* Not Global Provisioning Error Object (GPERR) */
+ break;
+
+ gperror = tvb_get_ntohs(tvb, offset);
+ gperror_sub = tvb_get_ntohs(tvb, offset + 2);
+ ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
+ val_to_str(gperror, cops_gperror_vals, "<Unknown value>"), gperror_sub);
+ gperror_tree = proto_item_add_subtree(ti, ett_cops_gperror);
+ proto_tree_add_uint(gperror_tree, hf_cops_gperror, tvb, offset, 2, gperror);
+ offset += 2;
+ if (cperror == 13) {
+ proto_tree_add_text(gperror_tree, tvb, offset, 2, "Error Sub-code: "
+ "Unknown object's C-Num %u, C-Type %u",
+ tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
+ } else
+ proto_tree_add_uint(gperror_tree, hf_cops_gperror_sub, tvb, offset, 2, gperror_sub);
+
+ break;
+ case COPS_OBJ_CPERR:
+ if (s_type != 1) /*Not PRC Class Provisioning Error Object (CPERR) */
+ break;
+
+ break;
+
+ cperror = tvb_get_ntohs(tvb, offset);
+ cperror_sub = tvb_get_ntohs(tvb, offset + 2);
+ ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
+ val_to_str(cperror, cops_cperror_vals, "<Unknown value>"), cperror_sub);
+ cperror_tree = proto_item_add_subtree(ti, ett_cops_cperror);
+ proto_tree_add_uint(cperror_tree, hf_cops_cperror, tvb, offset, 2, cperror);
+ offset += 2;
+ if (cperror == 13) {
+ proto_tree_add_text(cperror_tree, tvb, offset, 2, "Error Sub-code: "
+ "Unknown object's S-Num %u, C-Type %u",
+ tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
+ } else
+ proto_tree_add_uint(cperror_tree, hf_cops_cperror_sub, tvb, offset, 2, cperror_sub);
+
+ break;
+ case COPS_OBJ_ERRPRID:
+ if (s_type != 1) /*Not Error Provisioning Instance Identifier (ErrorPRID)*/
+ break;
+
+ ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
+ asn1_object_tree = proto_item_add_subtree(ti, ett_cops_asn1);
+
+ decode_cops_pr_asn1_data(tvb, offset, asn1_object_tree, len, COPS_OBJ_ERRPRID);
+
+ break;
+ default:
+ proto_tree_add_text(tree, tvb, offset, len, "Contents: %u bytes", len);
+ break;
+ }
+
+ return 0;
+}
+
+
+/* Register the protocol with Ethereal */
+void proto_register_cops(void)
+{
+ /* Setup list of header fields */
+ static hf_register_info hf[] = {
+ { &hf_cops_ver_flags,
+ { "Version and Flags", "cops.ver_flags",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "Version and Flags in COPS Common Header", HFILL }
+ },
+ { &hf_cops_version,
+ { "Version", "cops.version",
+ FT_UINT8, BASE_DEC, NULL, 0xF0,
+ "Version in COPS Common Header", HFILL }
+ },
+ { &hf_cops_flags,
+ { "Flags", "cops.flags",
+ FT_UINT8, BASE_HEX, VALS(cops_flags_vals), 0x0F,
+ "Flags in COPS Common Header", HFILL }
+ },
+ { &hf_cops_op_code,
+ { "Op Code", "cops.op_code",
+ FT_UINT8, BASE_DEC, VALS(cops_op_code_vals), 0x0,
+ "Op Code in COPS Common Header", HFILL }
+ },
+ { &hf_cops_client_type,
+ { "Client Type", "cops.client_type",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Client Type in COPS Common Header", HFILL }
+ },
+ { &hf_cops_msg_len,
+ { "Message Length", "cops.msg_len",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Message Length in COPS Common Header", HFILL }
+ },
+ { &hf_cops_obj_len,
+ { "Object Length", "cops.obj.len",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Object Length in COPS Object Header", HFILL }
+ },
+ { &hf_cops_obj_c_num,
+ { "C-Num", "cops.c_num",
+ FT_UINT8, BASE_DEC, VALS(cops_c_num_vals), 0x0,
+ "C-Num in COPS Object Header", HFILL }
+ },
+ { &hf_cops_obj_c_type,
+ { "C-Type", "cops.c_type",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "C-Type in COPS Object Header", HFILL }
+ },
+
+ { &hf_cops_obj_s_num,
+ { "S-Num", "cops.s_num",
+ FT_UINT8, BASE_DEC, VALS(cops_s_num_vals), 0x0,
+ "S-Num in COPS-PR Object Header", HFILL }
+ },
+ { &hf_cops_obj_s_type,
+ { "S-Type", "cops.s_type",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "S-Type in COPS-PR Object Header", HFILL }
+ },
+
+ { &hf_cops_r_type_flags,
+ { "R-Type", "cops.context.r_type",
+ FT_UINT16, BASE_HEX, VALS(cops_r_type_vals), 0xFFFF,
+ "R-Type in COPS Context Object", HFILL }
+ },
+ { &hf_cops_m_type_flags,
+ { "M-Type", "cops.context.m_type",
+ FT_UINT16, BASE_HEX, NULL, 0xFFFF,
+ "M-Type in COPS Context Object", HFILL }
+ },
+ { &hf_cops_in_int_ipv4,
+ { "IPv4 address", "cops.in-int.ipv4",
+ FT_IPv4, 0, NULL, 0xFFFF,
+ "IPv4 address in COPS IN-Int object", HFILL }
+ },
+ { &hf_cops_in_int_ipv6,
+ { "IPv6 address", "cops.in-int.ipv6",
+ FT_IPv6, 0, NULL, 0xFFFF,
+ "IPv6 address in COPS IN-Int object", HFILL }
+ },
+ { &hf_cops_out_int_ipv4,
+ { "IPv4 address", "cops.out-int.ipv4",
+ FT_IPv4, 0, NULL, 0xFFFF,
+ "IPv4 address in COPS OUT-Int object", HFILL }
+ },
+ { &hf_cops_out_int_ipv6,
+ { "IPv6 address", "cops.out-int.ipv6",
+ FT_IPv6, 0, NULL, 0xFFFF,
+ "IPv6 address in COPS OUT-Int", HFILL }
+ },
+ { &hf_cops_int_ifindex,
+ { "ifIndex", "cops.in-out-int.ifindex",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "If SNMP is supported, corresponds to MIB-II ifIndex", HFILL }
+ },
+ { &hf_cops_reason,
+ { "Reason", "cops.reason",
+ FT_UINT16, BASE_DEC, VALS(cops_reason_vals), 0,
+ "Reason in Reason object", HFILL }
+ },
+ { &hf_cops_reason_sub,
+ { "Reason Sub-code", "cops.reason_sub",
+ FT_UINT16, BASE_HEX, NULL, 0,
+ "Reason Sub-code in Reason object", HFILL }
+ },
+ { &hf_cops_dec_cmd_code,
+ { "Command-Code", "cops.decision.cmd",
+ FT_UINT16, BASE_DEC, VALS(cops_dec_cmd_code_vals), 0,
+ "Command-Code in Decision/LPDP Decision object", HFILL }
+ },
+ { &hf_cops_dec_flags,
+ { "Flags", "cops.decision.flags",
+ FT_UINT16, BASE_HEX, VALS(cops_dec_cmd_flag_vals), 0xffff,
+ "Flags in Decision/LPDP Decision object", HFILL }
+ },
+ { &hf_cops_error,
+ { "Error", "cops.error",
+ FT_UINT16, BASE_DEC, VALS(cops_error_vals), 0,
+ "Error in Error object", HFILL }
+ },
+ { &hf_cops_error_sub,
+ { "Error Sub-code", "cops.error_sub",
+ FT_UINT16, BASE_HEX, NULL, 0,
+ "Error Sub-code in Error object", HFILL }
+ },
+ { &hf_cops_katimer,
+ { "Contents: KA Timer Value", "cops.katimer.value",
+ FT_UINT16, BASE_DEC, NULL, 0,
+ "Keep-Alive Timer Value in KATimer object", HFILL }
+ },
+ { &hf_cops_pepid,
+ { "Contents: PEP Id", "cops.pepid.id",
+ FT_STRING, BASE_NONE, NULL, 0,
+ "PEP Id in PEPID object", HFILL }
+ },
+ { &hf_cops_report_type,
+ { "Contents: Report-Type", "cops.report_type",
+ FT_UINT16, BASE_DEC, VALS(cops_report_type_vals), 0,
+ "Report-Type in Report-Type object", HFILL }
+ },
+ { &hf_cops_pdprediraddr_ipv4,
+ { "IPv4 address", "cops.pdprediraddr.ipv4",
+ FT_IPv4, 0, NULL, 0xFFFF,
+ "IPv4 address in COPS PDPRedirAddr object", HFILL }
+ },
+ { &hf_cops_pdprediraddr_ipv6,
+ { "IPv6 address", "cops.pdprediraddr.ipv6",
+ FT_IPv6, 0, NULL, 0xFFFF,
+ "IPv6 address in COPS PDPRedirAddr object", HFILL }
+ },
+ { &hf_cops_lastpdpaddr_ipv4,
+ { "IPv4 address", "cops.lastpdpaddr.ipv4",
+ FT_IPv4, 0, NULL, 0xFFFF,
+ "IPv4 address in COPS LastPDPAddr object", HFILL }
+ },
+ { &hf_cops_lastpdpaddr_ipv6,
+ { "IPv6 address", "cops.lastpdpaddr.ipv6",
+ FT_IPv6, 0, NULL, 0xFFFF,
+ "IPv6 address in COPS LastPDPAddr object", HFILL }
+ },
+ { &hf_cops_pdp_tcp_port,
+ { "TCP Port Number", "cops.pdp.tcp_port",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "TCP Port Number of PDP in PDPRedirAddr/LastPDPAddr object", HFILL }
+ },
+ { &hf_cops_accttimer,
+ { "Contents: ACCT Timer Value", "cops.accttimer.value",
+ FT_UINT16, BASE_DEC, NULL, 0,
+ "Accounting Timer Value in AcctTimer object", HFILL }
+ },
+ { &hf_cops_key_id,
+ { "Contents: Key ID", "cops.integrity.key_id",
+ FT_UINT32, BASE_DEC, NULL, 0,
+ "Key ID in Integrity object", HFILL }
+ },
+ { &hf_cops_seq_num,
+ { "Contents: Sequence Number", "cops.integrity.seq_num",
+ FT_UINT32, BASE_DEC, NULL, 0,
+ "Sequence Number in Integrity object", HFILL }
+ },
+ { &hf_cops_gperror,
+ { "Error", "cops.gperror",
+ FT_UINT16, BASE_DEC, VALS(cops_gperror_vals), 0,
+ "Error in Error object", HFILL }
+ },
+ { &hf_cops_gperror_sub,
+ { "Error Sub-code", "cops.gperror_sub",
+ FT_UINT16, BASE_HEX, NULL, 0,
+ "Error Sub-code in Error object", HFILL }
+ },
+ { &hf_cops_cperror,
+ { "Error", "cops.cperror",
+ FT_UINT16, BASE_DEC, VALS(cops_cperror_vals), 0,
+ "Error in Error object", HFILL }
+ },
+ { &hf_cops_cperror_sub,
+ { "Error Sub-code", "cops.cperror_sub",
+ FT_UINT16, BASE_HEX, NULL, 0,
+ "Error Sub-code in Error object", HFILL }
+ },
+
+ /* Added for PacketCable */
+
+ { &hf_cops_subtree,
+ { "Object Subtree", "cops.pc_subtree",
+ FT_UINT16, BASE_HEX, NULL, 0,
+ "Object Subtree", HFILL }
+ },
+ { &hf_cops_pc_ds_field,
+ { "DS Field (DSCP or TOS)", "cops.pc_ds_field",
+ FT_UINT8, BASE_HEX, NULL, 0x00,
+ "DS Field (DSCP or TOS)", HFILL }
+ },
+ { &hf_cops_pc_direction,
+ { "Direction", "cops.pc_direction",
+ FT_UINT8, BASE_HEX, NULL, 0x00,
+ "Direction", HFILL }
+ },
+ { &hf_cops_pc_gate_spec_flags,
+ { "Flags", "cops.pc_gate_spec_flags",
+ FT_UINT8, BASE_HEX, NULL, 0x00,
+ "Flags", HFILL }
+ },
+ { &hf_cops_pc_protocol_id,
+ { "Protocol ID", "cops.pc_protocol_id",
+ FT_UINT8, BASE_HEX, NULL, 0x00,
+ "Protocol ID", HFILL }
+ },
+ { &hf_cops_pc_session_class,
+ { "Session Class", "cops.pc_session_class",
+ FT_UINT8, BASE_HEX, NULL, 0x00,
+ "Session Class", HFILL }
+ },
+ { &hf_cops_pc_algorithm,
+ { "Algorithm", "cops.pc_algorithm",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Algorithm", HFILL }
+ },
+ { &hf_cops_pc_cmts_ip_port,
+ { "CMTS IP Port", "cops.pc_cmts_ip_port",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "CMTS IP Port", HFILL }
+ },
+ { &hf_cops_pc_prks_ip_port,
+ { "PRKS IP Port", "cops.pc_prks_ip_port",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "PRKS IP Port", HFILL }
+ },
+ { &hf_cops_pc_srks_ip_port,
+ { "SRKS IP Port", "cops.pc_srks_ip_port",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "SRKS IP Port", HFILL }
+ },
+ { &hf_cops_pc_dest_port,
+ { "Destination IP Port", "cops.pc_dest_port",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Destination IP Port", HFILL }
+ },
+ { &hf_cops_pc_packetcable_err_code,
+ { "Error Code", "cops.pc_packetcable_err_code",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Error Code", HFILL }
+ },
+ { &hf_cops_pc_packetcable_sub_code,
+ { "Error Sub Code", "cops.pc_packetcable_sub_code",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Error Sub Code", HFILL }
+ },
+ { &hf_cops_pc_remote_flags,
+ { "Flags", "cops.pc_remote_flags",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Flags", HFILL }
+ },
+ { &hf_cops_pc_close_subcode,
+ { "Reason Sub Code", "cops.pc_close_subcode",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Reason Sub Code", HFILL }
+ },
+ { &hf_cops_pc_gate_command_type,
+ { "Gate Command Type", "cops.pc_gate_command_type",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Gate Command Type", HFILL }
+ },
+ { &hf_cops_pc_reason_code,
+ { "Reason Code", "cops.pc_reason_code",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Reason Code", HFILL }
+ },
+ { &hf_cops_pc_delete_subcode,
+ { "Reason Sub Code", "cops.pc_delete_subcode",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Reason Sub Code", HFILL }
+ },
+ { &hf_cops_pc_src_port,
+ { "Source IP Port", "cops.pc_src_port",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Source IP Port", HFILL }
+ },
+ { &hf_cops_pc_t1_value,
+ { "Timer T1 Value (sec)", "cops.pc_t1_value",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Timer T1 Value (sec)", HFILL }
+ },
+ { &hf_cops_pc_t7_value,
+ { "Timer T7 Value (sec)", "cops.pc_t7_value",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Timer T7 Value (sec)", HFILL }
+ },
+ { &hf_cops_pc_t8_value,
+ { "Timer T8 Value (sec)", "cops.pc_t8_value",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Timer T8 Value (sec)", HFILL }
+ },
+ { &hf_cops_pc_transaction_id,
+ { "Transaction Identifier", "cops.pc_transaction_id",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "Transaction Identifier", HFILL }
+ },
+ { &hf_cops_pc_cmts_ip,
+ { "CMTS IP Address", "cops.pc_cmts_ip",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "CMTS IP Address", HFILL }
+ },
+ { &hf_cops_pc_prks_ip,
+ { "PRKS IP Address", "cops.pc_prks_ip",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "PRKS IP Address", HFILL }
+ },
+ { &hf_cops_pc_srks_ip,
+ { "SRKS IP Address", "cops.pc_srks_ip",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "SRKS IP Address", HFILL }
+ },
+ { &hf_cops_pc_dfcdc_ip,
+ { "DF IP Address CDC", "cops.pc_dfcdc_ip",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "DF IP Address CDC", HFILL }
+ },
+ { &hf_cops_pc_dfccc_ip,
+ { "DF IP Address CCC", "cops.pc_dfccc_ip",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "DF IP Address CCC", HFILL }
+ },
+ { &hf_cops_pc_dfcdc_ip_port,
+ { "DF IP Port CDC", "cops.pc_dfcdc_ip_port",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "DF IP Port CDC", HFILL }
+ },
+ { &hf_cops_pc_dfccc_ip_port,
+ { "DF IP Port CCC", "cops.pc_dfccc_ip_port",
+ FT_UINT16, BASE_HEX, NULL, 0x00,
+ "DF IP Port CCC", HFILL }
+ },
+ { &hf_cops_pc_activity_count,
+ { "Count", "cops.pc_activity_count",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "Count", HFILL }
+ },
+ { &hf_cops_pc_dest_ip,
+ { "Destination IP Address", "cops.pc_dest_ip",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "Destination IP Address", HFILL }
+ },
+ { &hf_cops_pc_gate_id,
+ { "Gate Identifier", "cops.pc_gate_id",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "Gate Identifier", HFILL }
+ },
+ { &hf_cops_pc_max_packet_size,
+ { "Maximum Packet Size", "cops.pc_max_packet_size",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "Maximum Packet Size", HFILL }
+ },
+ { &hf_cops_pc_min_policed_unit,
+ { "Minimum Policed Unit", "cops.pc_min_policed_unit",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "Minimum Policed Unit", HFILL }
+ },
+ { &hf_cops_pc_peak_data_rate,
+ { "Peak Data Rate", "cops.pc_peak_data_rate",
+ FT_FLOAT, BASE_NONE, NULL, 0x00,
+ "Peak Data Rate", HFILL }
+ },
+ { &hf_cops_pc_spec_rate,
+ { "Rate", "cops.pc_spec_rate",
+ FT_FLOAT, BASE_NONE, NULL, 0x00,
+ "Rate", HFILL }
+ },
+ { &hf_cops_pc_remote_gate_id,
+ { "Remote Gate ID", "cops.pc_remote_gate_id",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "Remote Gate ID", HFILL }
+ },
+ { &hf_cops_pc_reserved,
+ { "Reserved", "cops.pc_reserved",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "Reserved", HFILL }
+ },
+ { &hf_cops_pc_key,
+ { "Security Key", "cops.pc_key",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "Security Key", HFILL }
+ },
+ { &hf_cops_pc_slack_term,
+ { "Slack Term", "cops.pc_slack_term",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "Slack Term", HFILL }
+ },
+ { &hf_cops_pc_src_ip,
+ { "Source IP Address", "cops.pc_src_ip",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "Source IP Address", HFILL }
+ },
+ { &hf_cops_pc_subscriber_id,
+ { "Subscriber Identifier (IPv4)", "cops.pc_subscriber_id",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "Subscriber Identifier (IPv4)", HFILL }
+ },
+ { &hf_cops_pc_token_bucket_rate,
+ { "Token Bucket Rate", "cops.pc_token_bucket_rate",
+ FT_FLOAT, BASE_NONE, NULL, 0x00,
+ "Token Bucket Rate", HFILL }
+ },
+ { &hf_cops_pc_token_bucket_size,
+ { "Token Bucket Size", "cops.pc_token_bucket_size",
+ FT_FLOAT, BASE_NONE, NULL, 0x00,
+ "Token Bucket Size", HFILL }
+ },
+ { &hf_cops_pc_bcid,
+ { "Billing Correlation ID", "cops.pc_bcid",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "Billing Correlation ID", HFILL }
+ },
+ { &hf_cops_pc_bcid_ts,
+ { "BDID Timestamp", "cops.pc_bcid_ts",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "BCID Timestamp", HFILL }
+ },
+ { &hf_cops_pc_bcid_ev,
+ { "BDID Event Counter", "cops.pc_bcid_ev",
+ FT_UINT32, BASE_HEX, NULL, 0x00,
+ "BCID Event Counter", HFILL }
+ },
+
+
+ /* End of addition for PacketCable */
+
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_cops,
+ &ett_cops_ver_flags,
+ &ett_cops_obj,
+ &ett_cops_pr_obj,
+ &ett_cops_obj_data,
+ &ett_cops_r_type_flags,
+ &ett_cops_itf,
+ &ett_cops_reason,
+ &ett_cops_decision,
+ &ett_cops_error,
+ &ett_cops_clientsi,
+ &ett_cops_asn1,
+ &ett_cops_gperror,
+ &ett_cops_cperror,
+ &ett_cops_pdp,
+ &ett_cops_subtree,
+ };
+
+ module_t* cops_module;
+
+ /* Register the protocol name and description */
+ proto_cops = proto_register_protocol("Common Open Policy Service",
+ "COPS", "cops");
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_cops, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ /* Register our configuration options for cops */
+ cops_module = prefs_register_protocol(proto_cops, proto_reg_handoff_cops);
+ prefs_register_uint_preference(cops_module,"tcp.cops_port",
+ "COPS TCP Port",
+ "Set the TCP port for COPS messages",
+ 10,&global_cops_tcp_port);
+ prefs_register_bool_preference(cops_module, "desegment",
+ "Desegment all COPS messages\nspanning multiple TCP segments",
+ "Whether the COPS dissector should desegment all messages spanning multiple TCP segments",
+ &cops_desegment);
+
+ /* For PacketCable */
+ prefs_register_bool_preference(cops_module, "packetcable",
+ "Decode for PacketCable clients",
+ "Decode the COPS messages using PacketCable clients. (Select port 2126)",
+ &cops_packetcable);
+
+#ifdef HAVE_NET_SNMP /*enable preference only if compiled with NET-SNMP*/
+ prefs_register_bool_preference(cops_module, "typefrommib",
+ "Decode COPS-PR ASN.1 types by reading them\nfrom PIBs (converted to MIBs)",
+ "Whether the COPS dissector should decode COPS-PR ASN.1 types based on data types read from packet or PIBs (converted to MIBs)",
+ &cops_typefrommib);
+#endif /*HAVE_NET_SNMP*/
+}
+
+void proto_reg_handoff_cops(void)
+{
+ static int cops_prefs_initialized = FALSE;
+ static dissector_handle_t cops_handle;
+
+ if (!cops_prefs_initialized) {
+ cops_handle = create_dissector_handle(dissect_cops, proto_cops);
+ cops_prefs_initialized = TRUE;
+ } else
+ dissector_delete("tcp.port",cops_tcp_port,cops_handle);
+
+ /* Set our port numbers for future use */
+ cops_tcp_port = global_cops_tcp_port;
+
+ dissector_add("tcp.port", cops_tcp_port, cops_handle);
+}
+
+
+/* Additions for PacketCable ( Added by Dick Gooris, Lucent Technologies ) */
+
+/* Definitions for print formatting */
+#define FMT_DEC 0
+#define FMT_HEX 1
+#define FMT_IP 2
+#define FMT_FLT 3
+
+/* Print the translated information in the display gui in a formatted way
+ *
+ * octets = The number of octets to obtain from the buffer
+ *
+ * vsp = If not a NULL pointer, it points to an array with text
+ *
+ * mode = 0 -> print decimal value
+ * 1 -> print hexadecimal vaue
+ * 2 -> print value as an ip address
+ * 3 -> print value as an ieee float
+ *
+ * This function in combination with the separate function info_to_cops_subtree() for subtrees.
+ *
+ */
+
+void info_to_display(tvbuff_t *tvb, proto_item *stt, int offset, int octets, char *str, const value_string *vsp, int mode,gint *hf_proto_parameter)
+{
+
+ guint8 code8 = 0;
+ guint16 code16 = 0;
+ guint32 code32 = 0;
+ guint32 codeip = 0;
+ float codefl = 0.0;
+
+ /* Print information elements in the specified way */
+ switch (octets) {
+
+ case 1:
+ /* Get the octet */
+ code8 = tvb_get_guint8( tvb, offset );
+ if (vsp == NULL) {
+ /* Hexadecimal format */
+ if (mode==FMT_HEX)
+ proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb,
+ offset, octets, code8,"%-28s : 0x%02x",str,code8);
+ else
+ /* Print an 8 bits integer */
+ proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb,
+ offset, octets, code8,"%-28s : %u",str,code8);
+ } else {
+ if (mode==FMT_HEX)
+ /* Hexadecimal format */
+ proto_tree_add_uint_format(
+ stt, *hf_proto_parameter,tvb, offset, octets, code8,
+ "%-28s : %s (0x%02x)",str,val_to_str(code8, vsp, "Unknown"),code8);
+ else
+ /* String table indexed */
+ proto_tree_add_uint_format(
+ stt, *hf_proto_parameter,tvb, offset, octets, code8,
+ "%-28s : %s (%u)",str,val_to_str(code8, vsp, "Unknown"),code8);
+ }
+ break;
+
+ case 2:
+
+ /* Get the next two octets */
+ code16 = tvb_get_ntohs(tvb,offset);
+ if (vsp == NULL) {
+ /* Hexadecimal format */
+ if (mode==FMT_HEX)
+ proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb,
+ offset, octets, code16,"%-28s : 0x%04x",str,code16);
+ else
+ /* Print a 16 bits integer */
+ proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb,
+ offset, octets, code16,"%-28s : %u",str,code16);
+ } else {
+ if (mode==FMT_HEX)
+ /* Hexadecimal format */
+ proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb,
+ offset, octets, code16,"%-28s : %s (0x%04x)", str,
+ val_to_str(code16, vsp, "Unknown (0x%04x)"),code16);
+ else
+ /* Print a 16 bits integer */
+ proto_tree_add_uint_format(
+ stt, *hf_proto_parameter,tvb, offset, octets, code16,
+ "%-28s : %s (%u)",str,val_to_str(code16, vsp, "Unknown (0x%04x)"),code16);
+ }
+ break;
+
+ case 4:
+
+ /* Get the next four octets */
+ switch (mode) {
+ case FMT_FLT: codefl = tvb_get_ntohieee_float(tvb,offset);
+ break;
+ case FMT_IP: tvb_memcpy(tvb, (guint8 *)&code32, offset, 4);
+ codeip = tvb_get_ntohl(tvb,offset);
+ break;
+ default: code32 = tvb_get_ntohl(tvb,offset);
+ }
+
+ if (vsp == NULL) {
+ /* Hexadecimal format */
+ if (mode==FMT_HEX) {
+ proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb,
+ offset, octets, code32,"%-28s : 0x%08x",str,code32);
+ break;
+ }
+ /* Ip address format*/
+ if (mode==FMT_IP) {
+ proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb, offset,octets,
+ codeip,"%-28s : %s",str,ip_to_str((guint8 *)&code32));
+ break;
+ }
+ /* Ieee float format */
+ if (mode==FMT_FLT) {
+ proto_tree_add_float_format(stt, *hf_proto_parameter,tvb, offset, octets,
+ codefl,"%-28s : %.10g",str,codefl);
+ break;
+ }
+ /* Print a 32 bits integer */
+ proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb, offset, octets,
+ code32,"%-28s : %u",str,code32);
+ } else {
+ /* Hexadecimal format */
+ if (mode==FMT_HEX)
+ proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb, offset, octets,
+ code32,"%-28s : %s (0x%08x)",str,val_to_str(code32, vsp, "Unknown"),code32);
+ else
+ /* String table indexed */
+ proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb, offset, octets,
+ code32,"%-28s : %s (%u)",str,val_to_str(code32, vsp, "Unknown"),code32);
+ }
+ break;
+
+ /* In case of more than 4 octets.... */
+ default: {
+ if (mode==FMT_HEX)
+ proto_tree_add_bytes(stt, *hf_proto_parameter,
+ tvb, offset, octets, tvb_get_ptr(tvb, offset,octets));
+ else
+ proto_tree_add_uint_format(stt, *hf_proto_parameter,
+ tvb, offset, octets, code32,"%s",str);
+ break;
+ }
+
+ }
+}
+
+/* Print the subtree information for cops */
+proto_tree *info_to_cops_subtree(tvbuff_t *tvb, proto_tree *st, int n, int offset, char *str) {
+ proto_item *tv;
+
+ tv = proto_tree_add_uint_format( st, hf_cops_subtree, tvb, offset, n, (guint)NULL, str);
+ return( proto_item_add_subtree( tv, ett_cops_subtree ) );
+}
+
+/* Cops - Section : Transaction ID */
+void cops_transaction_id(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
+
+ proto_tree *stt;
+ guint16 code16;
+ char info[50];
+
+ /* Create a subtree */
+ stt = info_to_cops_subtree(tvb,st,n,offset,"Transaction ID");
+
+ /* Transaction Identifier */
+ info_to_display(tvb,stt,offset,2,"Transaction Identifier", NULL,FMT_DEC,&hf_cops_pc_transaction_id);
+ offset +=2;
+
+ /* Gate Command Type */
+ code16 = tvb_get_ntohs(tvb,offset);
+ proto_tree_add_uint_format(stt, hf_cops_pc_gate_command_type,tvb, offset, 2,
+ code16,"%-28s : %s (%u)", "Gate Command Type",
+ val_to_str(code16,table_cops_transaction_id, "Unknown (0x%04x)"),code16);
+
+ /* Write the right data into the 'info field' on the Gui */
+ sprintf(info,"COPS %-20s - ",val_to_str(opcode_idx,cops_op_code_vals, "Unknown"));
+ strcat(info,val_to_str(code16,table_cops_transaction_id, "Unknown"));
+
+ if (check_col(cpinfo->cinfo, COL_INFO)) {
+ col_clear(cpinfo->cinfo, COL_INFO);
+ col_add_str(cpinfo->cinfo, COL_INFO,info);
+ }
+
+}
+
+/* Cops - Section : Subscriber ID */
+void cops_subscriber_id_v4(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
+
+ proto_item *tv;
+
+ /* Create a subtree */
+ tv = info_to_cops_subtree(tvb,st,n,offset,"Subscriber ID");
+
+ /* Subscriber Identifier */
+ info_to_display(tvb,tv,offset,4,"Subscriber Identifier (IPv4)", NULL,FMT_IP,&hf_cops_pc_subscriber_id);
+}
+
+/* Cops - Section : Gate ID */
+void cops_gate_id(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
+
+ proto_tree *stt;
+
+ /* Create a subtree */
+ stt = info_to_cops_subtree(tvb,st,n,offset,"Gate ID");
+
+ /* Gate Identifier */
+ info_to_display(tvb,stt,offset,4,"Gate Identifier", NULL,FMT_HEX,&hf_cops_pc_gate_id);
+}
+
+/* Cops - Section : Activity Count */
+void cops_activity_count(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
+
+ proto_tree *stt;
+
+ /* Create a subtree */
+ stt = info_to_cops_subtree(tvb,st,n,offset,"Activity Count");
+
+ /* Activity Count */
+ info_to_display(tvb,stt,offset,4,"Count", NULL,FMT_DEC,&hf_cops_pc_activity_count);
+}
+
+/* Cops - Section : Gate Specifications */
+void cops_gate_specs(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
+
+ proto_tree *stt;
+
+ /* Create a subtree */
+ stt = info_to_cops_subtree(tvb,st,n,offset,"Gate Specifications");
+
+ /* Direction */
+ info_to_display(tvb,stt,offset,1,"Direction",table_cops_direction,FMT_DEC,&hf_cops_pc_direction);
+ offset += 1;
+
+ /* Protocol ID */
+ info_to_display(tvb,stt,offset,1,"Protocol ID",NULL,FMT_DEC,&hf_cops_pc_protocol_id);
+ offset += 1;
+
+ /* Flags */
+ info_to_display(tvb,stt,offset,1,"Flags",NULL,FMT_DEC,&hf_cops_pc_gate_spec_flags);
+ offset += 1;
+
+ /* Session Class */
+ info_to_display(tvb,stt,offset,1,"Session Class",table_cops_session_class,FMT_DEC,&hf_cops_pc_session_class);
+ offset += 1;
+
+ /* Source IP Address */
+ info_to_display(tvb,stt,offset,4,"Source IP Address",NULL,FMT_IP,&hf_cops_pc_src_ip);
+ offset += 4;
+
+ /* Destination IP Address */
+ info_to_display(tvb,stt,offset,4,"Destination IP Address",NULL,FMT_IP,&hf_cops_pc_dest_ip);
+ offset += 4;
+
+ /* Source IP Port */
+ info_to_display(tvb,stt,offset,2,"Source IP Port",NULL,FMT_DEC,&hf_cops_pc_src_port);
+ offset += 2;
+
+ /* Destination IP Port */
+ info_to_display(tvb,stt,offset,2,"Destination IP Port",NULL,FMT_DEC,&hf_cops_pc_dest_port);
+ offset += 2;
+
+ /* DiffServ Code Point */
+ info_to_display(tvb,stt,offset,1,"DS Field (DSCP or TOS)",NULL,FMT_HEX,&hf_cops_pc_ds_field);
+ offset += 1;
+
+ /* 3 octets Not specified */
+ offset += 3;
+
+ /* Timer T1 Value */
+ info_to_display(tvb,stt,offset,2,"Timer T1 Value (sec)",NULL,FMT_DEC,&hf_cops_pc_t1_value);
+ offset += 2;
+
+ /* Reserved */
+ info_to_display(tvb,stt,offset,2,"Reserved",NULL,FMT_DEC,&hf_cops_pc_reserved);
+ offset += 2;
+
+ /* Timer T7 Value */
+ info_to_display(tvb,stt,offset,2,"Timer T7 Value (sec)",NULL,FMT_DEC,&hf_cops_pc_t7_value);
+ offset += 2;
+
+ /* Timer T8 Value */
+ info_to_display(tvb,stt,offset,2,"Timer T8 Value (sec)",NULL,FMT_DEC,&hf_cops_pc_t8_value);
+ offset += 2;
+
+ /* Token Bucket Rate */
+ info_to_display(tvb,stt,offset,4,"Token Bucket Rate",NULL,FMT_FLT,&hf_cops_pc_token_bucket_rate);
+ offset += 4;
+
+ /* Token Bucket Size */
+ info_to_display(tvb,stt,offset,4,"Token Bucket Size",NULL,FMT_FLT,&hf_cops_pc_token_bucket_size);
+ offset += 4;
+
+ /* Peak Data Rate */
+ info_to_display(tvb,stt,offset,4,"Peak Data Rate",NULL,FMT_FLT,&hf_cops_pc_peak_data_rate);
+ offset += 4;
+
+ /* Minimum Policed Unit */
+ info_to_display(tvb,stt,offset,4,"Minimum Policed Unit",NULL,FMT_DEC,&hf_cops_pc_min_policed_unit);
+ offset += 4;
+
+ /* Maximum Packet Size */
+ info_to_display(tvb,stt,offset,4,"Maximum Packet Size",NULL,FMT_DEC,&hf_cops_pc_max_packet_size);
+ offset += 4;
+
+ /* Rate */
+ info_to_display(tvb,stt,offset,4,"Rate",NULL,FMT_FLT,&hf_cops_pc_spec_rate);
+ offset += 4;
+
+ /* Slack Term */
+ info_to_display(tvb,stt,offset,4,"Slack Term",NULL,FMT_DEC,&hf_cops_pc_slack_term);
+}
+
+/* Cops - Section : Electronic Surveillance Parameters */
+void cops_surveillance_parameters(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
+
+ proto_tree *stt;
+ guint8 *bcid_str;
+
+ /* Create a subtree */
+ stt = info_to_cops_subtree(tvb,st,n,offset,"Electronic Surveillance Parameters");
+
+ /* DF IP Address for CDC */
+ info_to_display(tvb,stt,offset,4,"DF IP Address for CDC", NULL,FMT_IP,&hf_cops_pc_dfcdc_ip);
+ offset += 4;
+
+ /* DF IP Port for CDC */
+ info_to_display(tvb,stt,offset,2,"DF IP Port for CDC",NULL,FMT_DEC,&hf_cops_pc_dfcdc_ip_port);
+ offset += 2;
+
+ /* Flags */
+ info_to_display(tvb,stt,offset,2,"Flags",NULL,FMT_HEX,&hf_cops_pc_gate_spec_flags);
+ offset += 2;
+
+ /* DF IP Address for CCC */
+ info_to_display(tvb,stt,offset,4,"DF IP Address for CCC", NULL,FMT_IP,&hf_cops_pc_dfccc_ip);
+ offset += 4;
+
+ /* DF IP Port for CCC */
+ info_to_display(tvb,stt,offset,2,"DF IP Port for CCC",NULL,FMT_DEC,&hf_cops_pc_dfccc_ip_port);
+ offset += 2;
+
+ /* Reserved */
+ info_to_display(tvb,stt,offset,2,"Reserved",NULL,FMT_HEX,&hf_cops_pc_reserved);
+ offset += 2;
+
+ /* CCCID */
+ info_to_display(tvb,stt,offset,4,"CCCID", NULL,FMT_HEX,&hf_cops_pc_srks_ip);
+ offset += 4;
+
+ /* BCID Timestamp */
+ info_to_display(tvb,stt,offset,4,"BCID - Timestamp",NULL,FMT_HEX,&hf_cops_pc_bcid_ts);
+ offset += 4;
+
+ /* BCID Element ID */
+ bcid_str = tvb_get_string(tvb, offset, 8);
+ proto_tree_add_text(stt, tvb, offset, 8,"%-28s : '%s'","BCID - Element ID",bcid_str);
+ offset += 8;
+
+ /* BCID Time Zone */
+ bcid_str = tvb_get_string(tvb, offset, 8);
+ proto_tree_add_text(stt, tvb, offset, 8,"%-28s : '%s'","BCID - Time Zone",bcid_str);
+ offset += 8;
+
+ /* BCID Event Counter */
+ info_to_display(tvb,stt,offset,4,"BCID - Event Counter",NULL,FMT_DEC,&hf_cops_pc_bcid_ev);
+}
+
+/* Cops - Section : Event Gereration-Info */
+void cops_event_generation_info(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
+
+ proto_tree *stt;
+ guint8 *bcid_str;
+
+ /* Create a subtree */
+ stt = info_to_cops_subtree(tvb,st,n,offset,"Event Generation Info");
+
+ /* Primary Record Keeping Server IP Address */
+ info_to_display(tvb,stt,offset,4,"PRKS IP Address", NULL,FMT_IP,&hf_cops_pc_prks_ip);
+ offset += 4;
+
+ /* Primary Record Keeping Server IP Port */
+ info_to_display(tvb,stt,offset,2,"PRKS IP Port",NULL,FMT_DEC,&hf_cops_pc_prks_ip_port);
+ offset += 2;
+
+ /* Flags */
+ info_to_display(tvb,stt,offset,1,"Flags",NULL,FMT_HEX,&hf_cops_pc_gate_spec_flags);
+ offset += 1;
+
+ /* Reserved */
+ info_to_display(tvb,stt,offset,1,"Reserved",NULL,FMT_HEX,&hf_cops_pc_reserved);
+ offset += 1;
+
+ /* Secundary Record Keeping Server IP Address */
+ info_to_display(tvb,stt,offset,4,"SRKS IP Address", NULL,FMT_IP,&hf_cops_pc_srks_ip);
+ offset += 4;
+
+ /* Secundary Record Keeping Server IP Port */
+ info_to_display(tvb,stt,offset,2,"SRKS IP Port",NULL,FMT_DEC,&hf_cops_pc_srks_ip_port);
+ offset += 2;
+
+ /* Flags */
+ info_to_display(tvb,stt,offset,1,"Flags",NULL,FMT_DEC,&hf_cops_pc_gate_spec_flags);
+ offset += 1;
+
+ /* Reserved */
+ info_to_display(tvb,stt,offset,1,"Reserved",NULL,FMT_HEX,&hf_cops_pc_reserved);
+ offset += 1;
+
+ /* BCID Timestamp */
+ info_to_display(tvb,stt,offset,4,"BCID - Timestamp",NULL,FMT_HEX,&hf_cops_pc_bcid_ts);
+ offset += 4;
+
+ /* BCID Element ID */
+ bcid_str = tvb_get_string(tvb, offset, 8);
+ proto_tree_add_text(stt, tvb, offset, 8,"%-28s : '%s'","BCID - Element ID",bcid_str);
+ offset += 8;
+
+ /* BCID Time Zone */
+ bcid_str = tvb_get_string(tvb, offset, 8);
+ proto_tree_add_text(stt, tvb, offset, 8,"%-28s : '%s'","BCID - Time Zone",bcid_str);
+ offset += 8;
+
+ /* BCID Event Counter */
+ info_to_display(tvb,stt,offset,4,"BCID - Event Counter",NULL,FMT_DEC,&hf_cops_pc_bcid_ev);
+}
+
+/* Cops - Section : Remote Gate */
+void cops_remote_gate_info(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
+
+ proto_tree *stt;
+
+ /* Create a subtree */
+ stt = info_to_cops_subtree(tvb,st,n,offset,"Remote Gate Info");
+
+ /* CMTS IP Address */
+ info_to_display(tvb,stt,offset,4,"CMTS IP Address", NULL,FMT_IP,&hf_cops_pc_cmts_ip);
+ offset += 4;
+
+ /* CMTS IP Port */
+ info_to_display(tvb,stt,offset,2,"CMTS IP Port",NULL,FMT_DEC,&hf_cops_pc_cmts_ip_port);
+ offset += 2;
+
+ /* Flags */
+ info_to_display(tvb,stt,offset,2,"Flags",NULL,FMT_DEC,&hf_cops_pc_remote_flags);
+ offset += 2;
+
+ /* Remote Gate ID */
+ info_to_display(tvb,stt,offset,4,"Remote Gate ID", NULL,FMT_HEX,&hf_cops_pc_remote_gate_id);
+ offset += 4;
+
+ /* Algorithm */
+ info_to_display(tvb,stt,offset,2,"Algorithm", NULL,FMT_IP,&hf_cops_pc_algorithm);
+ offset += 2;
+
+ /* Reserved */
+ info_to_display(tvb,stt,offset,4,"Reserved", NULL,FMT_IP,&hf_cops_pc_reserved);
+ offset += 4;
+
+ /* Security Key */
+ info_to_display(tvb,stt,offset,4,"Security Key", NULL,FMT_HEX,&hf_cops_pc_key);
+ offset += 4;
+
+ /* Security Key */
+ info_to_display(tvb,stt,offset,4,"Security Key (cont)", NULL,FMT_HEX,&hf_cops_pc_key);
+ offset += 4;
+
+ /* Security Key */
+ info_to_display(tvb,stt,offset,4,"Security Key (cont)", NULL,FMT_HEX,&hf_cops_pc_key);
+ offset += 4;
+
+ /* Security Key */
+ info_to_display(tvb,stt,offset,4,"Security Key (cont)", NULL,FMT_HEX,&hf_cops_pc_key);
+}
+
+/* Cops - Section : PacketCable reason */
+void cops_packetcable_reason(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
+
+ proto_tree *stt;
+ guint16 code16;
+
+ /* Create a subtree */
+ stt = info_to_cops_subtree(tvb,st,n,offset,"PacketCable Reason");
+
+ /* Reason Code */
+ code16 = tvb_get_ntohs(tvb,offset);
+ proto_tree_add_uint_format(stt, hf_cops_pc_reason_code,tvb, offset, 2,
+ code16, "%-28s : %s (%u)","Reason Code",
+ val_to_str(code16, table_cops_reason_code, "Unknown (0x%04x)"),code16);
+ offset += 2;
+
+ if ( code16 == 0 ) {
+ /* Reason Sub Code with Delete */
+ info_to_display(tvb,stt,offset,2,"Reason Sub Code",table_cops_reason_subcode_delete,FMT_DEC,&hf_cops_pc_delete_subcode);
+ } else {
+ /* Reason Sub Code with Close */
+ info_to_display(tvb,stt,offset,2,"Reason Sub Code",table_cops_reason_subcode_close,FMT_DEC,&hf_cops_pc_close_subcode);
+ }
+}
+
+/* Cops - Section : PacketCable error */
+void cops_packetcable_error(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
+
+ proto_tree *stt;
+
+ /* Create a subtree */
+ stt = info_to_cops_subtree(tvb,st,n,offset,"PacketCable Error");
+
+ /* Error Code */
+ info_to_display(tvb,stt,offset,2,"Error Code",table_cops_packetcable_error,FMT_DEC,&hf_cops_pc_packetcable_err_code);
+ offset += 2;
+
+ /* Error Sub Code */
+ info_to_display(tvb,stt,offset,2,"Error Sub Code",NULL,FMT_HEX,&hf_cops_pc_packetcable_sub_code);
+
+}
+
+/* Analyze the PacketCable objects */
+void cops_analyze_packetcable_obj(tvbuff_t *tvb, proto_tree *tree, guint32 offset) {
+
+ gint remdata;
+ guint16 object_len;
+ guint8 s_num, s_type;
+
+ /* Only if this option is enabled by the Gui */
+ if ( cops_packetcable == FALSE ) {
+ return;
+ }
+
+ /* Do the remaining client specific objects */
+ remdata = tvb_length_remaining(tvb, offset);
+ while (remdata > 4) {
+
+ /* In case we have remaining data, then lets try to get this analyzed */
+ object_len = tvb_get_ntohs(tvb, offset);
+ if (object_len < 4) {
+ proto_tree_add_text(tree, tvb, offset, 2,
+ "Incorrect PacketCable object length %u < 4", object_len);
+ return;
+ }
+
+ s_num = tvb_get_guint8(tvb, offset + 2);
+ s_type = tvb_get_guint8(tvb, offset + 3);
+
+ /* Tune offset */
+ offset += 4;
+
+ /* Perform the appropriate functions */
+ switch (s_num){
+ case 1:
+ if (s_type == 1) {
+ cops_transaction_id(tvb, tree, object_len, offset);
+ }
+ break;
+ case 2:
+ if (s_type == 1) {
+ cops_subscriber_id_v4(tvb, tree, object_len, offset);
+ }
+ break;
+ case 3:
+ if (s_type == 1) {
+ cops_gate_id(tvb, tree, object_len, offset);
+ }
+ break;
+ case 4:
+ if (s_type == 1) {
+ cops_activity_count(tvb, tree, object_len, offset);
+ }
+ break;
+ case 5:
+ if (s_type == 1) {
+ cops_gate_specs(tvb, tree, object_len, offset);
+ }
+ break;
+ case 6:
+ if (s_type == 1) {
+ cops_remote_gate_info(tvb, tree, object_len, offset);
+ }
+ break;
+ case 7:
+ if (s_type == 1) {
+ cops_event_generation_info(tvb, tree, object_len, offset);
+ }
+ break;
+ case 9:
+ if (s_type == 1) {
+ cops_packetcable_error(tvb, tree, object_len, offset);
+ }
+ break;
+ case 10:
+ if (s_type == 1) {
+ cops_surveillance_parameters(tvb, tree, object_len, offset);
+ }
+ break;
+ case 13:
+ if (s_type == 1) {
+ cops_packetcable_reason(tvb, tree, object_len, offset);
+ }
+ break;
+ }
+
+ /* Tune offset */
+ offset += object_len-4;
+
+ /* See what we can still get from the buffer */
+ remdata = tvb_length_remaining(tvb, offset);
+ }
+}
+
+/* End of PacketCable Addition */
+
+