2 * Routines for the COPS (Common Open Policy Service) protocol dissection
3 * RFC2748 & COPS-PR extension RFC3084
5 * Copyright 2000, Heikki Vatiainen <hessu@cs.tut.fi>
7 * $Id: packet-cops.c,v 1.22 2002/02/26 12:26:06 guy Exp $
9 * Ethereal - Network traffic analyzer
10 * By Gerald Combs <gerald@ethereal.com>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
38 #include <epan/packet.h>
39 #include "packet-ipv6.h"
40 #include "packet-frame.h"
42 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
47 #define MAX_STRING_LEN 2048 /* TBC */
49 # if defined(HAVE_UCD_SNMP_SNMP_H)
53 # include <ucd-snmp/asn1.h>
54 # include <ucd-snmp/snmp_api.h>
55 # include <ucd-snmp/snmp_impl.h>
56 # include <ucd-snmp/mib.h>
59 * Sigh. UCD SNMP 4.1.1 makes "snmp_set_suffix_only()" a macro
60 * that calls "ds_set_int()" with the first two arguments
61 * being DS_LIBRARY_ID and DS_LIB_PRINT_SUFFIX_ONLY; this means that,
62 * when building with 4.1.1, we need to arrange that
63 * <ucd-snmp/default_store.h> is included, to define those two values
64 * and to declare "ds_int()".
68 * 1) we can't include it on earlier versions (at least not 3.6.2),
69 * as it doesn't exist in those versions;
71 * 2) we don't want to include <ucd-snmp/ucd-snmp-includes.h>,
72 * as that includes <ucd-snmp/snmp.h>, and that defines a whole
73 * bunch of values that we also define ourselves.
75 * So we only include it if "snmp_set_suffix_only" is defined as
78 # ifdef snmp_set_suffix_only
79 # include <ucd-snmp/default_store.h>
83 * XXX - for now, we assume all versions of UCD SNMP have it.
85 # define HAVE_SPRINT_VALUE
88 * Define values "sprint_value()" expects.
90 # define VALTYPE_INTEGER ASN_INTEGER
91 # define VALTYPE_COUNTER ASN_COUNTER
92 # define VALTYPE_GAUGE ASN_GAUGE
93 # define VALTYPE_TIMETICKS ASN_TIMETICKS
94 # define VALTYPE_STRING ASN_OCTET_STR
95 # define VALTYPE_IPADDR ASN_IPADDRESS
96 # define VALTYPE_OPAQUE ASN_OPAQUE
97 # define VALTYPE_NSAP ASN_NSAP
98 # define VALTYPE_OBJECTID ASN_OBJECT_ID
99 # define VALTYPE_BITSTR ASN_BIT_STR
100 # define VALTYPE_COUNTER64 ASN_COUNTER64
102 # ifdef RED_HAT_MODIFIED_UCD_SNMP
103 # include <ucd-snmp/parse.h>
107 # elif defined(HAVE_SNMP_SNMP_H)
111 # include <snmp/snmp.h>
114 * Some older versions of CMU SNMP may lack these values (e.g., the
115 * "libsnmp3.6" package for Debian, which is based on some old
116 * CMU SNMP, perhaps 1.0); for now, we assume they also lack
120 # define HAVE_SPRINT_VALUE
122 * Define values "sprint_value()" expects.
124 # define VALTYPE_INTEGER SMI_INTEGER
125 # define VALTYPE_COUNTER SMI_COUNTER32
126 # define VALTYPE_GAUGE SMI_GAUGE32
127 # define VALTYPE_TIMETICKS SMI_TIMETICKS
128 # define VALTYPE_STRING SMI_STRING
129 # define VALTYPE_IPADDR SMI_IPADDRESS
130 # define VALTYPE_OPAQUE SMI_OPAQUE
131 # define VALTYPE_NSAP SMI_STRING
132 # define VALTYPE_OBJECTID SMI_OBJID
133 # define VALTYPE_BITSTR ASN_BIT_STR
134 # define VALTYPE_COUNTER64 SMI_COUNTER64
137 * Now undo all the definitions they "helpfully" gave us, so we don't get
138 * complaints about redefining them.
140 * Why, oh why, is there no library that provides code to
144 * 2) translate object IDs into names;
146 * 3) let you find out, for a given object ID, what the type, enum
147 * values, display hint, etc. are;
149 * in a *simple* fashion, without assuming that your code is part of an
150 * SNMP agent or client that wants a pile of definitions of PDU types,
151 * etc.? Is it just that 99 44/100% of the code that uses an SNMP library
152 * *is* part of an agent or client, and really *does* need that stuff,
153 * and *doesn't* need the interfaces we want?
155 # undef SNMP_ERR_NOERROR
156 # undef SNMP_ERR_TOOBIG
157 # undef SNMP_ERR_NOSUCHNAME
158 # undef SNMP_ERR_BADVALUE
159 # undef SNMP_ERR_READONLY
160 # undef SNMP_ERR_NOACCESS
161 # undef SNMP_ERR_WRONGTYPE
162 # undef SNMP_ERR_WRONGLENGTH
163 # undef SNMP_ERR_WRONGENCODING
164 # undef SNMP_ERR_WRONGVALUE
165 # undef SNMP_ERR_NOCREATION
166 # undef SNMP_ERR_INCONSISTENTVALUE
167 # undef SNMP_ERR_RESOURCEUNAVAILABLE
168 # undef SNMP_ERR_COMMITFAILED
169 # undef SNMP_ERR_UNDOFAILED
170 # undef SNMP_ERR_AUTHORIZATIONERROR
171 # undef SNMP_ERR_NOTWRITABLE
172 # undef SNMP_ERR_INCONSISTENTNAME
173 # undef SNMP_TRAP_COLDSTART
174 # undef SNMP_TRAP_WARMSTART
175 # undef SNMP_TRAP_LINKDOWN
176 # undef SNMP_TRAP_LINKUP
177 # undef SNMP_TRAP_EGPNEIGHBORLOSS
178 # undef SNMP_TRAP_ENTERPRISESPECIFIC
185 #define TCP_PORT_COPS 3288
187 /* Variable to hold the tcp port preference */
188 static guint global_cops_tcp_port = TCP_PORT_COPS;
190 /* desegmentation of COPS */
191 static gboolean cops_desegment = TRUE;
193 /* Variable to allow for proper deletion of dissector registration
194 * when the user changes port from the gui
197 static guint cops_tcp_port = 0;
199 #define COPS_OBJECT_HDR_SIZE 4
201 /* Null string of type "guchar[]". */
202 static const guchar nullstring[] = "";
204 #define SAFE_STRING(s) (((s) != NULL) ? (s) : nullstring)
208 #define COPS_IPA 0 /* IP Address */
209 #define COPS_U32 2 /* Unsigned 32*/
210 #define COPS_TIT 3 /* TimeTicks */
211 #define COPS_OPQ 4 /* Opaque */
212 #define COPS_I64 10 /* Integer64 */
213 #define COPS_U64 11 /* Uinteger64 */
218 #define COPS_INTEGER 1 /* l */
219 #define COPS_OCTETSTR 2 /* c */
220 #define COPS_OBJECTID 3 /* ul */
221 #define COPS_IPADDR 4 /* uc */
222 #define COPS_UNSIGNED32 5 /* ul */
223 #define COPS_TIMETICKS 7 /* ul */
224 #define COPS_OPAQUE 8 /* c */
225 #define COPS_INTEGER64 10 /* ll */
226 #define COPS_UNSIGNED64 11 /* ull */
229 typedef struct _COPS_CNV COPS_CNV;
239 static COPS_CNV CopsCnv [] =
241 {ASN1_UNI, ASN1_NUL, COPS_NULL, "NULL"},
242 {ASN1_UNI, ASN1_INT, COPS_INTEGER, "INTEGER"},
243 {ASN1_UNI, ASN1_OTS, COPS_OCTETSTR, "OCTET STRING"},
244 {ASN1_UNI, ASN1_OJI, COPS_OBJECTID, "OBJECTID"},
245 {ASN1_APL, COPS_IPA, COPS_IPADDR, "IPADDR"},
246 {ASN1_APL, COPS_U32, COPS_UNSIGNED32,"UNSIGNED32"},
247 {ASN1_APL, COPS_TIT, COPS_TIMETICKS, "TIMETICKS"},
248 {ASN1_APL, COPS_OPQ, COPS_OPAQUE, "OPAQUE"},
249 {ASN1_APL, COPS_I64, COPS_INTEGER64, "INTEGER64"},
250 {ASN1_APL, COPS_U64, COPS_UNSIGNED64, "UNSIGNED64"},
255 cops_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
260 while (cnv->syntax != -1)
262 if (cnv->tag == tag && cnv->class == cls)
264 *syntax = cnv->syntax;
272 static const value_string cops_flags_vals[] = {
274 { 0x01, "Solicited Message Flag Bit" },
278 /* The different COPS message types */
280 COPS_NO_MSG, /* Not a COPS Message type */
282 COPS_MSG_REQ, /* Request (REQ) */
283 COPS_MSG_DEC, /* Decision (DEC) */
284 COPS_MSG_RPT, /* Report State (RPT) */
285 COPS_MSG_DRQ, /* Delete Request State (DRQ) */
286 COPS_MSG_SSQ, /* Synchronize State Req (SSQ) */
287 COPS_MSG_OPN, /* Client-Open (OPN) */
288 COPS_MSG_CAT, /* Client-Accept (CAT) */
289 COPS_MSG_CC, /* Client-Close (CC) */
290 COPS_MSG_KA, /* Keep-Alive (KA) */
291 COPS_MSG_SSC, /* Synchronize Complete (SSC) */
293 COPS_LAST_OP_CODE /* For error checking */
296 static const value_string cops_op_code_vals[] = {
297 { COPS_MSG_REQ, "Request (REQ)" },
298 { COPS_MSG_DEC, "Decision (DEC)" },
299 { COPS_MSG_RPT, "Report State (RPT)" },
300 { COPS_MSG_DRQ, "Delete Request State (DRQ)" },
301 { COPS_MSG_SSQ, "Synchronize State Req (SSQ)" },
302 { COPS_MSG_OPN, "Client-Open (OPN)" },
303 { COPS_MSG_CAT, "Client-Accept (CAT)" },
304 { COPS_MSG_CC, "Client-Close (CC)" },
305 { COPS_MSG_KA, "Keep-Alive (KA)" },
306 { COPS_MSG_SSC, "Synchronize Complete (SSC)" },
311 /* The different objects in COPS messages */
313 COPS_NO_OBJECT, /* Not a COPS Object type */
315 COPS_OBJ_HANDLE, /* Handle Object (Handle) */
316 COPS_OBJ_CONTEXT, /* Context Object (Context) */
317 COPS_OBJ_IN_INT, /* In-Interface Object (IN-Int) */
318 COPS_OBJ_OUT_INT, /* Out-Interface Object (OUT-Int) */
319 COPS_OBJ_REASON, /* Reason Object (Reason) */
320 COPS_OBJ_DECISION, /* Decision Object (Decision) */
321 COPS_OBJ_LPDPDECISION, /* LPDP Decision Object (LPDPDecision) */
322 COPS_OBJ_ERROR, /* Error Object (Error) */
323 COPS_OBJ_CLIENTSI, /* Client Specific Information Object (ClientSI) */
324 COPS_OBJ_KATIMER, /* Keep-Alive Timer Object (KATimer) */
325 COPS_OBJ_PEPID, /* PEP Identification Object (PEPID) */
326 COPS_OBJ_REPORT_TYPE, /* Report-Type Object (Report-Type) */
327 COPS_OBJ_PDPREDIRADDR, /* PDP Redirect Address Object (PDPRedirAddr) */
328 COPS_OBJ_LASTPDPADDR, /* Last PDP Address (LastPDPaddr) */
329 COPS_OBJ_ACCTTIMER, /* Accounting Timer Object (AcctTimer) */
330 COPS_OBJ_INTEGRITY, /* Message Integrity Object (Integrity) */
331 COPS_LAST_C_NUM /* For error checking */
334 static const value_string cops_c_num_vals[] = {
335 { COPS_OBJ_HANDLE, "Handle Object (Handle)" },
336 { COPS_OBJ_CONTEXT, "Context Object (Context)" },
337 { COPS_OBJ_IN_INT, "In-Interface Object (IN-Int)" },
338 { COPS_OBJ_OUT_INT, "Out-Interface Object (OUT-Int)" },
339 { COPS_OBJ_REASON, "Reason Object (Reason)" },
340 { COPS_OBJ_DECISION, "Decision Object (Decision)" },
341 { COPS_OBJ_LPDPDECISION, "LPDP Decision Object (LPDPDecision)" },
342 { COPS_OBJ_ERROR, "Error Object (Error)" },
343 { COPS_OBJ_CLIENTSI, "Client Specific Information Object (ClientSI)" },
344 { COPS_OBJ_KATIMER, "Keep-Alive Timer Object (KATimer)" },
345 { COPS_OBJ_PEPID, "PEP Identification Object (PEPID)" },
346 { COPS_OBJ_REPORT_TYPE, "Report-Type Object (Report-Type)" },
347 { COPS_OBJ_PDPREDIRADDR, "PDP Redirect Address Object (PDPRedirAddr)" },
348 { COPS_OBJ_LASTPDPADDR, "Last PDP Address (LastPDPaddr)" },
349 { COPS_OBJ_ACCTTIMER, "Accounting Timer Object (AcctTimer)" },
350 { COPS_OBJ_INTEGRITY, "Message Integrity Object (Integrity)" },
355 /* The different objects in COPS-PR messages */
357 COPS_NO_PR_OBJECT, /* Not a COPS-PR Object type */
358 COPS_OBJ_PRID, /* Provisioning Instance Identifier (PRID) */
359 COPS_OBJ_PPRID, /* Prefix Provisioning Instance Identifier (PPRID) */
360 COPS_OBJ_EPD, /* Encoded Provisioning Instance Data (EPD) */
361 COPS_OBJ_GPERR, /* Global Provisioning Error Object (GPERR) */
362 COPS_OBJ_CPERR, /* PRC Class Provisioning Error Object (CPERR) */
363 COPS_OBJ_ERRPRID, /* Error Provisioning Instance Identifier (ErrorPRID)*/
365 COPS_LAST_S_NUM /* For error checking */
369 static const value_string cops_s_num_vals[] = {
370 { COPS_OBJ_PRID, "Provisioning Instance Identifier (PRID)" },
371 { COPS_OBJ_PPRID, "Prefix Provisioning Instance Identifier (PPRID)" },
372 { COPS_OBJ_EPD, "Encoded Provisioning Instance Data (EPD)" },
373 { COPS_OBJ_GPERR, "Global Provisioning Error Object (GPERR)" },
374 { COPS_OBJ_CPERR, "PRC Class Provisioning Error Object (CPERR)" },
375 { COPS_OBJ_ERRPRID, "Error Provisioning Instance Identifier (ErrorPRID)" },
380 /* R-Type is carried within the Context Object */
381 static const value_string cops_r_type_vals[] = {
382 { 0x01, "Incoming-Message/Admission Control request" },
383 { 0x02, "Resource-Allocation request" },
384 { 0x04, "Outgoing-Message request" },
385 { 0x08, "Configuration request" },
388 /* S-Type is carried within the ClientSI Object for COPS-PR*/
389 static const value_string cops_s_type_vals[] = {
394 /* Reason-Code is carried within the Reason object */
395 static const value_string cops_reason_vals[] = {
396 { 1, "Unspecified" },
398 { 3, "Preempted (Another request state takes precedence)" },
399 { 4, "Tear (Used to communicate a signaled state removal)" },
400 { 5, "Timeout (Local state has timed-out)" },
401 { 6, "Route Change (Change invalidates request state)" },
402 { 7, "Insufficient Resources (No local resource available)" },
403 { 8, "PDP's Directive (PDP decision caused the delete)" },
404 { 9, "Unsupported decision (PDP decision not supported)" },
405 { 10, "Synchronize Handle Unknown" },
406 { 11, "Transient Handle (stateless event)" },
407 { 12, "Malformed Decision (could not recover)" },
408 { 13, "Unknown COPS Object from PDP" },
412 /* Command-Code is carried within the Decision object if C-Type is 1 */
413 static const value_string cops_dec_cmd_code_vals[] = {
414 { 0, "NULL Decision (No configuration data available)" },
415 { 1, "Install (Admit request/Install configuration)" },
416 { 2, "Remove (Remove request/Remove configuration)" },
420 /* Decision flags are also carried with the Decision object if C-Type is 1 */
421 static const value_string cops_dec_cmd_flag_vals[] = {
422 { 0x00, "<None set>" },
423 { 0x01, "Trigger Error (Trigger error message if set)" },
427 /* Error-Code from Error object */
428 static const value_string cops_error_vals[] = {
430 {2, "Invalid handle reference" },
431 {3, "Bad message format (Malformed Message)" },
432 {4, "Unable to process (server gives up on query)" },
433 {5, "Mandatory client-specific info missing" },
434 {6, "Unsupported client" },
435 {7, "Mandatory COPS object missing" },
436 {8, "Client Failure" },
437 {9, "Communication Failure" },
438 {10, "Unspecified" },
439 {11, "Shutting down" },
440 {12, "Redirect to Preferred Server" },
441 {13, "Unknown COPS Object" },
442 {14, "Authentication Failure" },
443 {15, "Authentication Required" },
446 /* Error-Code from GPERR object */
447 static const value_string cops_gperror_vals[] = {
449 {2, "AvailMemExhausted" },
450 {3, "unknownASN.1Tag" },
451 {4, "maxMsgSizeExceeded" },
452 {5, "unknownError" },
453 {6, "maxRequestStatesOpen" },
454 {7, "invalidASN.1Length" },
455 {8, "invalidObjectPad" },
456 {9, "unknownPIBData" },
457 {10, "unknownCOPSPRObject" },
458 {11, "malformedDecision" },
462 /* Error-Code from CPERR object */
463 static const value_string cops_cperror_vals[] = {
464 {1, "priSpaceExhausted" },
465 {2, "priInstanceInvalid" },
466 {3, "attrValueInvalid" },
467 {4, "attrValueSupLimited" },
468 {5, "attrEnumSupLimited" },
469 {6, "attrMaxLengthExceeded" },
470 {7, "attrReferenceUnknown" },
471 {8, "priNotifyOnly" },
473 {10, "tooFewAttrs" },
474 {11, "invalidAttrType" },
475 {12, "deletedInRef" },
476 {13, "priSpecificError" },
481 /* Report-Type from Report-Type object */
482 static const value_string cops_report_type_vals[] = {
483 {1, " Success : Decision was successful at the PEP" },
484 {2, " Failure : Decision could not be completed by PEP" },
485 {3, " Accounting: Accounting update for an installed state" },
489 /* Initialize the protocol and registered fields */
490 static gint proto_cops = -1;
491 static gint hf_cops_ver_flags = -1;
492 static gint hf_cops_version = -1;
493 static gint hf_cops_flags = -1;
495 static gint hf_cops_op_code = -1;
496 static gint hf_cops_client_type = -1;
497 static gint hf_cops_msg_len = -1;
499 static gint hf_cops_obj_len = -1;
500 static gint hf_cops_obj_c_num = -1;
501 static gint hf_cops_obj_c_type = -1;
503 static gint hf_cops_obj_s_num = -1;
504 static gint hf_cops_obj_s_type = -1;
506 static gint hf_cops_r_type_flags = -1;
507 static gint hf_cops_m_type_flags = -1;
509 static gint hf_cops_in_int_ipv4 = -1;
510 static gint hf_cops_in_int_ipv6 = -1;
511 static gint hf_cops_out_int_ipv4 = -1;
512 static gint hf_cops_out_int_ipv6 = -1;
513 static gint hf_cops_int_ifindex = -1;
515 static gint hf_cops_reason = -1;
516 static gint hf_cops_reason_sub = -1;
518 static gint hf_cops_dec_cmd_code = -1;
519 static gint hf_cops_dec_flags = -1;
521 static gint hf_cops_error = -1;
522 static gint hf_cops_error_sub = -1;
524 static gint hf_cops_gperror = -1;
525 static gint hf_cops_gperror_sub = -1;
527 static gint hf_cops_cperror = -1;
528 static gint hf_cops_cperror_sub = -1;
530 static gint hf_cops_katimer = -1;
532 static gint hf_cops_pepid = -1;
534 static gint hf_cops_report_type = -1;
536 static gint hf_cops_pdprediraddr_ipv4 = -1;
537 static gint hf_cops_pdprediraddr_ipv6 = -1;
538 static gint hf_cops_lastpdpaddr_ipv4 = -1;
539 static gint hf_cops_lastpdpaddr_ipv6 = -1;
540 static gint hf_cops_pdp_tcp_port = -1;
542 static gint hf_cops_accttimer = -1;
544 static gint hf_cops_key_id = -1;
545 static gint hf_cops_seq_num = -1;
547 /* Initialize the subtree pointers */
548 static gint ett_cops = -1;
549 static gint ett_cops_ver_flags = -1;
550 static gint ett_cops_obj = -1;
551 static gint ett_cops_pr_obj = -1;
552 static gint ett_cops_obj_data = -1;
553 static gint ett_cops_r_type_flags = -1;
554 static gint ett_cops_itf = -1;
555 static gint ett_cops_reason = -1;
556 static gint ett_cops_decision = -1;
557 static gint ett_cops_error = -1;
558 static gint ett_cops_gperror = -1;
559 static gint ett_cops_cperror = -1;
560 static gint ett_cops_pdp = -1;
562 void proto_reg_handoff_cops(void);
564 static void dissect_cops_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
566 static int dissect_cops_object(tvbuff_t *tvb, guint32 offset, proto_tree *tree);
567 static int dissect_cops_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
568 guint8 c_num, guint8 c_type, guint16 len);
570 static int dissect_cops_pr_objects(tvbuff_t *tvb, guint32 offset, proto_tree *tree, guint16 pr_len);
571 static int dissect_cops_pr_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
572 guint8 s_num, guint8 s_type, guint16 len);
574 /* Code to actually dissect the packets */
576 dissect_cops(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
578 volatile int offset = 0;
579 int length_remaining;
584 while (tvb_reported_length_remaining(tvb, offset) != 0) {
585 length_remaining = tvb_length_remaining(tvb, offset);
586 if (length_remaining == -1)
590 * Can we do reassembly?
592 if (cops_desegment && pinfo->can_desegment) {
594 * Yes - is the COPS header split across segment
597 if (length_remaining < 8) {
599 * Yes. Tell the TCP dissector where
600 * the data for this message starts in
601 * the data it handed us, and how many
602 * more bytes we need, and return.
604 pinfo->desegment_offset = offset;
605 pinfo->desegment_len = 8 - length_remaining;
611 * Get the length of the COPS message.
613 msg_len = tvb_get_ntohl(tvb, offset + 4);
616 * Can we do reassembly?
618 if (cops_desegment && pinfo->can_desegment) {
620 * Yes - is the DNS packet split across segment
623 if ((guint32)length_remaining < msg_len) {
625 * Yes. Tell the TCP dissector where
626 * the data for this message starts in
627 * the data it handed us, and how many
628 * more bytes we need, and return.
630 pinfo->desegment_offset = offset;
631 pinfo->desegment_len =
632 msg_len - length_remaining;
638 * Construct a tvbuff containing the amount of the payload
639 * we have available. Make its reported length the
640 * amount of data in the COPS packet.
642 * XXX - if reassembly isn't enabled. the subdissector
643 * will throw a BoundsError exception, rather than a
644 * ReportedBoundsError exception. We really want
645 * a tvbuff where the length is "length", the reported
646 * length is "plen + 2", and the "if the snapshot length
647 * were infinite" length were the minimum of the
648 * reported length of the tvbuff handed to us and "plen+2",
649 * with a new type of exception thrown if the offset is
650 * within the reported length but beyond that third length,
651 * with that exception getting the "Unreassembled Packet"
654 length = length_remaining;
655 if ((guint32)length > msg_len)
657 next_tvb = tvb_new_subset(tvb, offset, length, msg_len);
660 * Dissect the COPS packet.
662 * Catch the ReportedBoundsError exception; if this
663 * particular message happens to get a ReportedBoundsError
664 * exception, that doesn't mean that we should stop
665 * dissecting COPS messages within this frame or chunk
666 * of reassembled data.
668 * If it gets a BoundsError, we can stop, as there's nothing
669 * more to see, so we just re-throw it.
672 dissect_cops_pdu(next_tvb, pinfo, tree);
677 CATCH(ReportedBoundsError) {
678 show_reported_bounds_error(tvb, pinfo, tree);
683 * Skip the COPS packet.
690 dissect_cops_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
694 if (check_col(pinfo->cinfo, COL_PROTOCOL))
695 col_set_str(pinfo->cinfo, COL_PROTOCOL, "COPS");
696 if (check_col(pinfo->cinfo, COL_INFO))
697 col_clear(pinfo->cinfo, COL_INFO);
699 op_code = tvb_get_guint8(tvb, 1);
700 if (check_col(pinfo->cinfo, COL_INFO))
701 col_add_fstr(pinfo->cinfo, COL_INFO, "COPS %s",
702 val_to_str(op_code, cops_op_code_vals, "Unknown Op Code"));
706 proto_tree *cops_tree, *ver_flags_tree;
712 ti = proto_tree_add_item(tree, proto_cops, tvb, offset, -1, FALSE);
713 cops_tree = proto_item_add_subtree(ti, ett_cops);
715 /* Version and flags share the same byte, put them in a subtree */
716 ver_flags = tvb_get_guint8(tvb, offset);
717 tv = proto_tree_add_uint_format(cops_tree, hf_cops_ver_flags, tvb, offset, 1,
718 ver_flags, "Version: %u, Flags: %s",
719 hi_nibble(ver_flags),
720 val_to_str(lo_nibble(ver_flags), cops_flags_vals, "Unknown"));
721 ver_flags_tree = proto_item_add_subtree(tv, ett_cops_ver_flags);
722 proto_tree_add_uint(ver_flags_tree, hf_cops_version, tvb, offset, 1, ver_flags);
723 proto_tree_add_uint(ver_flags_tree, hf_cops_flags, tvb, offset, 1, ver_flags);
726 proto_tree_add_uint(cops_tree, hf_cops_op_code, tvb, offset, 1, tvb_get_guint8(tvb, offset));
728 proto_tree_add_uint(cops_tree, hf_cops_client_type, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
731 msg_len = tvb_get_ntohl(tvb, offset);
732 proto_tree_add_uint(cops_tree, hf_cops_msg_len, tvb, offset, 4, tvb_get_ntohl(tvb, offset));
735 while (tvb_reported_length_remaining(tvb, offset) >= COPS_OBJECT_HDR_SIZE)
736 offset += dissect_cops_object(tvb, offset, cops_tree);
738 garbage = tvb_length_remaining(tvb, offset);
740 proto_tree_add_text(cops_tree, tvb, offset, garbage,
741 "Trailing garbage: %d byte%s", garbage,
742 plurality(garbage, "", "s"));
748 static char *cops_c_type_to_str(guint8 c_num, guint8 c_type)
751 case COPS_OBJ_HANDLE:
753 return "Client Handle";
755 case COPS_OBJ_IN_INT:
756 case COPS_OBJ_OUT_INT:
758 return "IPv4 Address + Interface";
759 else if (c_type == 2)
760 return "IPv6 Address + Interface";
762 case COPS_OBJ_DECISION:
763 case COPS_OBJ_LPDPDECISION:
765 return "Decision Flags (Mandatory)";
766 else if (c_type == 2)
767 return "Stateless Data";
768 else if (c_type == 3)
769 return "Replacement Data";
770 else if (c_type == 4)
771 return "Client Specific Decision Data";
772 else if (c_type == 5)
773 return "Named Decision Data";
775 case COPS_OBJ_CLIENTSI:
777 return "Signaled ClientSI";
778 else if (c_type == 2)
779 return "Named ClientSI";
781 case COPS_OBJ_KATIMER:
783 return "Keep-alive timer value";
785 case COPS_OBJ_PDPREDIRADDR:
786 case COPS_OBJ_LASTPDPADDR:
788 return "IPv4 Address + TCP Port";
789 else if (c_type == 2)
790 return "IPv6 Address + TCP Port";
792 case COPS_OBJ_ACCTTIMER:
794 return "Accounting timer value";
796 case COPS_OBJ_INTEGRITY:
798 return "HMAC digest";
805 static int dissect_cops_object(tvbuff_t *tvb, guint32 offset, proto_tree *tree)
807 guint16 object_len, contents_len;
808 guint8 c_num, c_type;
810 proto_tree *obj_tree;
814 object_len = tvb_get_ntohs(tvb, offset);
815 c_num = tvb_get_guint8(tvb, offset + 2);
816 c_type = tvb_get_guint8(tvb, offset + 3);
818 ti = proto_tree_add_uint_format(tree, hf_cops_obj_c_num, tvb, offset, object_len, c_num,
819 "%s: %s", val_to_str(c_num, cops_c_num_vals, "Unknown"),
820 cops_c_type_to_str(c_num, c_type));
821 obj_tree = proto_item_add_subtree(ti, ett_cops_obj);
823 proto_tree_add_uint(obj_tree, hf_cops_obj_len, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
826 proto_tree_add_uint(obj_tree, hf_cops_obj_c_num, tvb, offset, 1, c_num);
829 type_str = cops_c_type_to_str(c_num, c_type);
830 proto_tree_add_text(obj_tree, tvb, offset, 1, "C-Type: %s%s%u%s",
832 strlen(type_str) ? " (" : "",
834 strlen(type_str) ? ")" : "");
837 contents_len = object_len - COPS_OBJECT_HDR_SIZE;
838 ret = dissect_cops_object_data(tvb, offset, obj_tree, c_num, c_type, contents_len);
839 if (ret < 0) return 0;
841 /* Pad to 32bit boundary */
842 if (object_len % sizeof (guint32))
843 object_len += (sizeof (guint32) - object_len % sizeof (guint32));
848 static int dissect_cops_pr_objects(tvbuff_t *tvb, guint32 offset, proto_tree *tree, guint16 pr_len)
850 guint16 object_len, contents_len;
851 guint8 s_num, s_type;
854 proto_tree *cops_pr_tree, *obj_tree;
857 cops_pr_tree = proto_item_add_subtree(tree, ett_cops_pr_obj);
859 while (pr_len >= COPS_OBJECT_HDR_SIZE) {
860 object_len = tvb_get_ntohs(tvb, offset);
861 s_num = tvb_get_guint8(tvb, offset + 2);
862 s_type = tvb_get_guint8(tvb, offset + 3);
864 ti = proto_tree_add_uint_format(cops_pr_tree, hf_cops_obj_s_num, tvb, offset, object_len, s_num,
865 "%s", val_to_str(s_num, cops_s_num_vals, "Unknown"));
866 obj_tree = proto_item_add_subtree(cops_pr_tree, ett_cops_pr_obj);
868 proto_tree_add_uint(obj_tree, hf_cops_obj_len, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
872 proto_tree_add_uint(obj_tree, hf_cops_obj_s_num, tvb, offset, 1, s_num);
876 type_str = val_to_str(s_type, cops_s_type_vals, "Unknown");
877 proto_tree_add_text(obj_tree, tvb, offset, 1, "S-Type: %s%s%u%s",
879 strlen(type_str) ? " (" : "",
881 strlen(type_str) ? ")" : "");
885 contents_len = object_len - COPS_OBJECT_HDR_SIZE;
886 ret = dissect_cops_pr_object_data(tvb, offset, obj_tree, s_num, s_type, contents_len);
890 /*Pad to 32bit boundary */
891 if (object_len % sizeof (guint32))
892 object_len += (sizeof (guint32) - object_len % sizeof (guint32));
894 pr_len -= object_len - COPS_OBJECT_HDR_SIZE;
895 offset += object_len - COPS_OBJECT_HDR_SIZE;
901 static int dissect_cops_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
902 guint8 c_num, guint8 c_type, guint16 len)
905 proto_tree *r_type_tree, *itf_tree, *reason_tree, *dec_tree, *error_tree, *pdp_tree;
906 guint16 r_type, m_type, reason, reason_sub, cmd_code, cmd_flags, error, error_sub, tcp_port;
907 guint32 ipv4addr, ifindex;
908 struct e_in6_addr ipv6addr;
911 case COPS_OBJ_CONTEXT:
912 r_type = tvb_get_ntohs(tvb, offset);
913 m_type = tvb_get_ntohs(tvb, offset + 2);
914 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: R-Type: %s, M-Type: %u",
915 val_to_str(r_type, cops_r_type_vals, "Unknown"),
918 r_type_tree = proto_item_add_subtree(ti, ett_cops_r_type_flags);
919 proto_tree_add_uint(r_type_tree, hf_cops_r_type_flags, tvb, offset, 2, r_type);
921 proto_tree_add_uint(r_type_tree, hf_cops_m_type_flags, tvb, offset, 2, m_type);
925 case COPS_OBJ_IN_INT:
926 case COPS_OBJ_OUT_INT:
927 if (c_type == 1) { /* IPv4 */
928 tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset, 4);
929 ifindex = tvb_get_ntohl(tvb, offset + 4);
930 ti = proto_tree_add_text(tree, tvb, offset, 8, "Contents: IPv4 address %s, ifIndex: %u",
931 ip_to_str((guint8 *)&ipv4addr), ifindex);
932 itf_tree = proto_item_add_subtree(ti, ett_cops_itf);
933 proto_tree_add_ipv4(itf_tree,
934 (c_num == COPS_OBJ_IN_INT) ? hf_cops_in_int_ipv4 : hf_cops_out_int_ipv4,
935 tvb, offset, 4, ipv4addr);
937 } else if (c_type == 2) { /* IPv6 */
938 tvb_memcpy(tvb, (guint8 *)&ipv6addr, offset, sizeof ipv6addr);
939 ifindex = tvb_get_ntohl(tvb, offset + sizeof ipv6addr);
940 ti = proto_tree_add_text(tree, tvb, offset, 20, "Contents: IPv6 address %s, ifIndex: %u",
941 ip6_to_str(&ipv6addr), ifindex);
942 itf_tree = proto_item_add_subtree(ti, ett_cops_itf);
943 proto_tree_add_ipv6(itf_tree,
944 (c_num == COPS_OBJ_IN_INT) ? hf_cops_in_int_ipv6 : hf_cops_out_int_ipv6,
945 tvb, offset, 16, (guint8 *)&ipv6addr);
950 proto_tree_add_uint(itf_tree, hf_cops_int_ifindex, tvb, offset, 4, ifindex);
954 case COPS_OBJ_REASON:
955 reason = tvb_get_ntohs(tvb, offset);
956 reason_sub = tvb_get_ntohs(tvb, offset + 2);
957 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Reason-Code: %s, Reason Sub-code: 0x%04x",
958 val_to_str(reason, cops_reason_vals, "<Unknown value>"), reason_sub);
959 reason_tree = proto_item_add_subtree(ti, ett_cops_reason);
960 proto_tree_add_uint(reason_tree, hf_cops_reason, tvb, offset, 2, reason);
963 proto_tree_add_text(reason_tree, tvb, offset, 2, "Reason Sub-code: "
964 "Unknown object's C-Num %u, C-Type %u",
965 tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
967 proto_tree_add_uint(reason_tree, hf_cops_reason_sub, tvb, offset, 2, reason_sub);
971 case COPS_OBJ_DECISION:
972 case COPS_OBJ_LPDPDECISION:
974 cmd_code = tvb_get_ntohs(tvb, offset);
975 cmd_flags = tvb_get_ntohs(tvb, offset + 2);
976 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Command-Code: %s, Flags: %s",
977 val_to_str(cmd_code, cops_dec_cmd_code_vals, "<Unknown value>"),
978 val_to_str(cmd_flags, cops_dec_cmd_flag_vals, "<Unknown flag>"));
979 dec_tree = proto_item_add_subtree(ti, ett_cops_decision);
980 proto_tree_add_uint(dec_tree, hf_cops_dec_cmd_code, tvb, offset, 2, cmd_code);
982 proto_tree_add_uint(dec_tree, hf_cops_dec_flags, tvb, offset, 2, cmd_flags);
983 } else if (c_type == 5) { /*COPS-PR Data*/
984 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: %u bytes", len);
985 dissect_cops_pr_objects(tvb, offset, ti, len);
995 error = tvb_get_ntohs(tvb, offset);
996 error_sub = tvb_get_ntohs(tvb, offset + 2);
997 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
998 val_to_str(error, cops_error_vals, "<Unknown value>"), error_sub);
999 error_tree = proto_item_add_subtree(ti, ett_cops_error);
1000 proto_tree_add_uint(error_tree, hf_cops_error, tvb, offset, 2, error);
1003 proto_tree_add_text(error_tree, tvb, offset, 2, "Error Sub-code: "
1004 "Unknown object's C-Num %u, C-Type %u",
1005 tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
1007 proto_tree_add_uint(error_tree, hf_cops_error_sub, tvb, offset, 2, error_sub);
1011 case COPS_OBJ_CLIENTSI:
1013 if (c_type != 2) /*Not COPS-PR data*/
1016 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: %u bytes", len);
1018 dissect_cops_pr_objects(tvb, offset, ti, len);
1022 case COPS_OBJ_KATIMER:
1026 proto_tree_add_item(tree, hf_cops_katimer, tvb, offset + 2, 2, FALSE);
1027 if (tvb_get_ntohs(tvb, offset + 2) == 0)
1028 proto_tree_add_text(tree, tvb, offset, 0, "Value of zero implies infinity.");
1032 case COPS_OBJ_PEPID:
1036 if (tvb_strnlen(tvb, offset, len) == -1)
1037 proto_tree_add_text(tree, tvb, offset, len, "<PEP Id is not a NUL terminated ASCII string>");
1039 proto_tree_add_item(tree, hf_cops_pepid, tvb, offset,
1040 tvb_strnlen(tvb, offset, len) + 1, FALSE);
1044 case COPS_OBJ_REPORT_TYPE:
1048 proto_tree_add_item(tree, hf_cops_report_type, tvb, offset, 2, FALSE);
1052 case COPS_OBJ_PDPREDIRADDR:
1053 case COPS_OBJ_LASTPDPADDR:
1054 if (c_type == 1) { /* IPv4 */
1055 tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset, 4);
1056 tcp_port = tvb_get_ntohs(tvb, offset + 4 + 2);
1057 ti = proto_tree_add_text(tree, tvb, offset, 8, "Contents: IPv4 address %s, TCP Port Number: %u",
1058 ip_to_str((guint8 *)&ipv4addr), tcp_port);
1059 pdp_tree = proto_item_add_subtree(ti, ett_cops_pdp);
1060 proto_tree_add_ipv4(pdp_tree,
1061 (c_num == COPS_OBJ_PDPREDIRADDR) ? hf_cops_pdprediraddr_ipv4 : hf_cops_lastpdpaddr_ipv4,
1062 tvb, offset, 4, ipv4addr);
1064 } else if (c_type == 2) { /* IPv6 */
1065 tvb_memcpy(tvb, (guint8 *)&ipv6addr, offset, sizeof ipv6addr);
1066 tcp_port = tvb_get_ntohs(tvb, offset + sizeof ipv6addr + 2);
1067 ti = proto_tree_add_text(tree, tvb, offset, 20, "Contents: IPv6 address %s, TCP Port Number: %u",
1068 ip6_to_str(&ipv6addr), tcp_port);
1069 pdp_tree = proto_item_add_subtree(ti, ett_cops_pdp);
1070 proto_tree_add_ipv6(pdp_tree,
1071 (c_num == COPS_OBJ_PDPREDIRADDR) ? hf_cops_pdprediraddr_ipv6 : hf_cops_lastpdpaddr_ipv6,
1072 tvb, offset, 16, (guint8 *)&ipv6addr);
1078 proto_tree_add_uint(pdp_tree, hf_cops_pdp_tcp_port, tvb, offset, 2, tcp_port);
1082 case COPS_OBJ_ACCTTIMER:
1086 proto_tree_add_item(tree, hf_cops_accttimer, tvb, offset + 2, 2, FALSE);
1087 if (tvb_get_ntohs(tvb, offset + 2) == 0)
1088 proto_tree_add_text(tree, tvb, offset, 0, "Value of zero means "
1089 "there SHOULD be no unsolicited accounting updates.");
1093 case COPS_OBJ_INTEGRITY:
1095 break; /* Not HMAC digest */
1097 proto_tree_add_item(tree, hf_cops_key_id, tvb, offset, 4, FALSE);
1098 proto_tree_add_item(tree, hf_cops_seq_num, tvb, offset + 4, 4, FALSE);
1099 proto_tree_add_text(tree, tvb, offset + 8 , len - 8, "Contents: Keyed Message Digest");
1108 ti = proto_tree_add_text(tree, tvb, offset, len, "Contents: %u bytes", len);
1114 format_oid(subid_t *oid, guint oid_length)
1122 result_len = oid_length * 22;
1123 result = g_malloc(result_len + 1);
1125 len = sprintf(buf, "%lu", (unsigned long)oid[0]);
1127 for (i = 1; i < oid_length;i++) {
1128 len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
1134 static int decode_cops_pr_asn1_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree, guint epdlen)
1143 gchar *vb_type_name;
1146 guint cls, con, tag;
1148 subid_t *variable_oid;
1149 guint variable_oid_length;
1151 gint32 vb_integer_value;
1152 guint32 vb_uinteger_value;
1154 guint8 *vb_octet_string;
1157 guint vb_oid_length;
1159 gchar *vb_display_string;
1161 guint variable_length;
1163 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1164 gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
1171 while (epdlen > 0){ /*while there is stuff to be decoded*/
1173 asn1_open(&asn1, tvb, offset);
1176 /* parse the type of the object */
1178 start = asn1.offset;
1180 ret = asn1_header_decode (&asn1, &cls, &con, &tag, &def, &vb_length);
1181 if (ret != ASN1_ERR_NOERROR)
1184 return ASN1_ERR_LENGTH_NOT_DEFINITE;
1186 /* Convert the class, constructed flag, and tag to a type. */
1187 vb_type_name = cops_tag_cls2syntax(tag, cls, &vb_type);
1188 if (vb_type_name == NULL) {
1191 * Dissect the value as an opaque string of octets.
1193 vb_type_name = "unsupported type";
1194 vb_type = COPS_OPAQUE;
1197 /* parse the value */
1202 ret = asn1_int32_value_decode(&asn1, vb_length,
1204 if (ret != ASN1_ERR_NOERROR)
1206 length = asn1.offset - start;
1208 proto_tree_add_text(tree, asn1.tvb, offset, length,
1209 "Value: %s: %d (%#x)", vb_type_name,
1210 vb_integer_value, vb_integer_value);
1215 case COPS_UNSIGNED32:
1216 case COPS_TIMETICKS:
1217 ret = asn1_uint32_value_decode(&asn1, vb_length,
1218 &vb_uinteger_value);
1219 if (ret != ASN1_ERR_NOERROR)
1221 length = asn1.offset - start;
1223 proto_tree_add_text(tree, asn1.tvb, offset, length,
1224 "Value: %s: %u (%#x)", vb_type_name,
1225 vb_uinteger_value, vb_uinteger_value);
1232 case COPS_UNSIGNED64:
1233 case COPS_INTEGER64:
1234 ret = asn1_string_value_decode (&asn1, vb_length,
1236 if (ret != ASN1_ERR_NOERROR)
1238 length = asn1.offset - start;
1241 * If some characters are not printable, display
1242 * the string as bytes.
1244 for (i = 0; i < vb_length; i++) {
1245 if (!(isprint(vb_octet_string[i])
1246 || isspace(vb_octet_string[i])))
1249 if (i < vb_length) {
1251 * We stopped, due to a non-printable
1252 * character, before we got to the end
1255 vb_display_string = g_malloc(4*vb_length);
1256 buf = &vb_display_string[0];
1257 len = sprintf(buf, "%03u", vb_octet_string[0]);
1259 for (i = 1; i < vb_length; i++) {
1260 len = sprintf(buf, ".%03u",
1261 vb_octet_string[i]);
1264 proto_tree_add_text(tree, asn1.tvb, offset, length,
1265 "Value: %s: %s", vb_type_name,
1267 g_free(vb_display_string);
1269 proto_tree_add_text(tree, asn1.tvb, offset, length,
1270 "Value: %s: %.*s", vb_type_name,
1272 SAFE_STRING(vb_octet_string));
1275 g_free(vb_octet_string);
1279 ret = asn1_null_decode (&asn1, vb_length);
1280 if (ret != ASN1_ERR_NOERROR)
1282 length = asn1.offset - start;
1284 proto_tree_add_text(tree, asn1.tvb, offset, length,
1285 "Value: %s", vb_type_name);
1290 ret = asn1_oid_value_decode (&asn1, vb_length, &vb_oid,
1292 if (ret != ASN1_ERR_NOERROR)
1294 length = asn1.offset - start;
1297 vb_display_string = format_oid(vb_oid,
1300 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1301 # ifdef RED_HAT_MODIFIED_UCD_SNMP
1302 sprint_objid(binit(NULL, vb_oid_string, sizeof(vb_oid_string)),
1303 vb_oid, vb_oid_length);
1305 sprint_objid(vb_oid_string, vb_oid,
1308 proto_tree_add_text(tree, asn1.tvb, offset, length,
1309 "Value: %s: %s (%s)", vb_type_name,
1310 vb_display_string, vb_oid_string);
1314 #else /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1315 proto_tree_add_text(tree, asn1.tvb, offset, length,
1316 "Value: : %s: %s",vb_type_name, vb_display_string);
1319 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1321 proto_tree_add_text(tree, asn1.tvb, offset, length,
1322 "Value: %s: %s", vb_type_name, vb_display_string);
1323 g_free(vb_display_string);
1331 #ifdef HAVE_SPRINT_VALUE
1335 variable.val.objid = vb_oid;
1336 vb_display_string = format_var(&variable,
1337 variable_oid, variable_oid_length, vb_type,
1339 proto_tree_add_text(tree, asn1.tvb, offset,
1341 "Value: %s", vb_display_string);
1342 break; /* we added formatted version to the tree */
1344 #endif /* HAVE_SPRINT_VALUE */
1346 vb_display_string = format_oid(vb_oid, vb_oid_length);
1347 proto_tree_add_text(tree, asn1.tvb, offset, length,
1348 "Value: %s: %s", vb_type_name, vb_display_string);
1349 g_free(vb_display_string);
1358 g_assert_not_reached();
1359 return ASN1_ERR_WRONG_TYPE;
1362 asn1_close(&asn1,&offset);
1369 static int dissect_cops_pr_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
1370 guint8 s_num, guint8 s_type, guint16 len)
1373 proto_tree *gperror_tree, *cperror_tree;
1374 guint16 gperror=0, gperror_sub=0, cperror=0, cperror_sub=0;
1378 if (s_type != 1) /* Not Provisioning Instance Identifier (PRID) */
1381 ti=proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1383 decode_cops_pr_asn1_data(tvb, offset, ti, len);
1388 case COPS_OBJ_PPRID:
1389 if (s_type != 1) /* Not Prefix Provisioning Instance Identifier (PPRID) */
1392 ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1394 decode_cops_pr_asn1_data(tvb, offset, ti, len);
1399 if (s_type != 1) /* Not Encoded Provisioning Instance Data (EPD) */
1402 ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1404 decode_cops_pr_asn1_data(tvb, offset, ti, len);
1408 case COPS_OBJ_GPERR:
1409 if (s_type != 1) /* Not Global Provisioning Error Object (GPERR) */
1412 gperror = tvb_get_ntohs(tvb, offset);
1413 gperror_sub = tvb_get_ntohs(tvb, offset + 2);
1414 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
1415 val_to_str(gperror, cops_gperror_vals, "<Unknown value>"), gperror_sub);
1416 gperror_tree = proto_item_add_subtree(ti, ett_cops_gperror);
1417 proto_tree_add_uint(gperror_tree, hf_cops_gperror, tvb, offset, 2, gperror);
1419 if (cperror == 13) {
1420 proto_tree_add_text(gperror_tree, tvb, offset, 2, "Error Sub-code: "
1421 "Unknown object's C-Num %u, C-Type %u",
1422 tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
1424 proto_tree_add_uint(gperror_tree, hf_cops_gperror_sub, tvb, offset, 2, gperror_sub);
1428 case COPS_OBJ_CPERR:
1429 if (s_type != 1) /*Not PRC Class Provisioning Error Object (CPERR) */
1434 cperror = tvb_get_ntohs(tvb, offset);
1435 cperror_sub = tvb_get_ntohs(tvb, offset + 2);
1436 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
1437 val_to_str(cperror, cops_cperror_vals, "<Unknown value>"), cperror_sub);
1438 cperror_tree = proto_item_add_subtree(ti, ett_cops_cperror);
1439 proto_tree_add_uint(cperror_tree, hf_cops_cperror, tvb, offset, 2, cperror);
1441 if (cperror == 13) {
1442 proto_tree_add_text(cperror_tree, tvb, offset, 2, "Error Sub-code: "
1443 "Unknown object's S-Num %u, C-Type %u",
1444 tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
1446 proto_tree_add_uint(cperror_tree, hf_cops_cperror_sub, tvb, offset, 2, cperror_sub);
1450 case COPS_OBJ_ERRPRID:
1451 if (s_type != 1) /*Not Error Provisioning Instance Identifier (ErrorPRID)*/
1454 ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1456 decode_cops_pr_asn1_data(tvb, offset, ti, len);
1464 ti = proto_tree_add_text(tree, tvb, offset, len, "Contents: %u bytes", len);
1470 /* Register the protocol with Ethereal */
1471 void proto_register_cops(void)
1474 /* Setup list of header fields */
1475 static hf_register_info hf[] = {
1476 { &hf_cops_ver_flags,
1477 { "Version and Flags", "cops.ver_flags",
1478 FT_UINT8, BASE_HEX, NULL, 0x0,
1479 "Version and Flags in COPS Common Header", HFILL }
1482 { "Version", "cops.version",
1483 FT_UINT8, BASE_DEC, NULL, 0xF0,
1484 "Version in COPS Common Header", HFILL }
1487 { "Flags", "cops.flags",
1488 FT_UINT8, BASE_HEX, VALS(cops_flags_vals), 0x0F,
1489 "Flags in COPS Common Header", HFILL }
1492 { "Op Code", "cops.op_code",
1493 FT_UINT8, BASE_DEC, VALS(cops_op_code_vals), 0x0,
1494 "Op Code in COPS Common Header", HFILL }
1496 { &hf_cops_client_type,
1497 { "Client Type", "cops.client_type",
1498 FT_UINT16, BASE_DEC, NULL, 0x0,
1499 "Client Type in COPS Common Header", HFILL }
1502 { "Message Length", "cops.msg_len",
1503 FT_UINT32, BASE_DEC, NULL, 0x0,
1504 "Message Length in COPS Common Header", HFILL }
1507 { "Object Length", "cops.obj.len",
1508 FT_UINT32, BASE_DEC, NULL, 0x0,
1509 "Object Length in COPS Object Header", HFILL }
1511 { &hf_cops_obj_c_num,
1512 { "C-Num", "cops.c_num",
1513 FT_UINT8, BASE_DEC, VALS(cops_c_num_vals), 0x0,
1514 "C-Num in COPS Object Header", HFILL }
1516 { &hf_cops_obj_c_type,
1517 { "C-Type", "cops.c_type",
1518 FT_UINT8, BASE_DEC, NULL, 0x0,
1519 "C-Type in COPS Object Header", HFILL }
1522 { &hf_cops_obj_s_num,
1523 { "S-Num", "cops.s_num",
1524 FT_UINT8, BASE_DEC, VALS(cops_s_num_vals), 0x0,
1525 "S-Num in COPS-PR Object Header", HFILL }
1527 { &hf_cops_obj_s_type,
1528 { "S-Type", "cops.s_type",
1529 FT_UINT8, BASE_DEC, NULL, 0x0,
1530 "S-Type in COPS-PR Object Header", HFILL }
1533 { &hf_cops_r_type_flags,
1534 { "R-Type", "cops.context.r_type",
1535 FT_UINT16, BASE_HEX, VALS(cops_r_type_vals), 0xFFFF,
1536 "R-Type in COPS Context Object", HFILL }
1538 { &hf_cops_m_type_flags,
1539 { "M-Type", "cops.context.m_type",
1540 FT_UINT16, BASE_HEX, NULL, 0xFFFF,
1541 "M-Type in COPS Context Object", HFILL }
1543 { &hf_cops_in_int_ipv4,
1544 { "IPv4 address", "cops.in-int.ipv4",
1545 FT_IPv4, 0, NULL, 0xFFFF,
1546 "IPv4 address in COPS IN-Int object", HFILL }
1548 { &hf_cops_in_int_ipv6,
1549 { "IPv6 address", "cops.in-int.ipv6",
1550 FT_IPv6, 0, NULL, 0xFFFF,
1551 "IPv6 address in COPS IN-Int object", HFILL }
1553 { &hf_cops_out_int_ipv4,
1554 { "IPv4 address", "cops.out-int.ipv4",
1555 FT_IPv4, 0, NULL, 0xFFFF,
1556 "IPv4 address in COPS OUT-Int object", HFILL }
1558 { &hf_cops_out_int_ipv6,
1559 { "IPv6 address", "cops.out-int.ipv6",
1560 FT_IPv6, 0, NULL, 0xFFFF,
1561 "IPv6 address in COPS OUT-Int", HFILL }
1563 { &hf_cops_int_ifindex,
1564 { "ifIndex", "cops.in-out-int.ifindex",
1565 FT_UINT32, BASE_DEC, NULL, 0x0,
1566 "If SNMP is supported, corresponds to MIB-II ifIndex", HFILL }
1569 { "Reason", "cops.reason",
1570 FT_UINT16, BASE_DEC, VALS(cops_reason_vals), 0,
1571 "Reason in Reason object", HFILL }
1573 { &hf_cops_reason_sub,
1574 { "Reason Sub-code", "cops.reason_sub",
1575 FT_UINT16, BASE_HEX, NULL, 0,
1576 "Reason Sub-code in Reason object", HFILL }
1578 { &hf_cops_dec_cmd_code,
1579 { "Command-Code", "cops.decision.cmd",
1580 FT_UINT16, BASE_DEC, VALS(cops_dec_cmd_code_vals), 0,
1581 "Command-Code in Decision/LPDP Decision object", HFILL }
1583 { &hf_cops_dec_flags,
1584 { "Flags", "cops.decision.flags",
1585 FT_UINT16, BASE_HEX, VALS(cops_dec_cmd_flag_vals), 0xffff,
1586 "Flags in Decision/LPDP Decision object", HFILL }
1589 { "Error", "cops.error",
1590 FT_UINT16, BASE_DEC, VALS(cops_error_vals), 0,
1591 "Error in Error object", HFILL }
1593 { &hf_cops_error_sub,
1594 { "Error Sub-code", "cops.error_sub",
1595 FT_UINT16, BASE_HEX, NULL, 0,
1596 "Error Sub-code in Error object", HFILL }
1599 { "Contents: KA Timer Value", "cops.katimer.value",
1600 FT_UINT16, BASE_DEC, NULL, 0,
1601 "Keep-Alive Timer Value in KATimer object", HFILL }
1604 { "Contents: PEP Id", "cops.pepid.id",
1605 FT_STRING, BASE_NONE, NULL, 0,
1606 "PEP Id in PEPID object", HFILL }
1608 { &hf_cops_report_type,
1609 { "Contents: Report-Type", "cops.report_type",
1610 FT_UINT16, BASE_DEC, VALS(cops_report_type_vals), 0,
1611 "Report-Type in Report-Type object", HFILL }
1613 { &hf_cops_pdprediraddr_ipv4,
1614 { "IPv4 address", "cops.pdprediraddr.ipv4",
1615 FT_IPv4, 0, NULL, 0xFFFF,
1616 "IPv4 address in COPS PDPRedirAddr object", HFILL }
1618 { &hf_cops_pdprediraddr_ipv6,
1619 { "IPv6 address", "cops.pdprediraddr.ipv6",
1620 FT_IPv6, 0, NULL, 0xFFFF,
1621 "IPv6 address in COPS PDPRedirAddr object", HFILL }
1623 { &hf_cops_lastpdpaddr_ipv4,
1624 { "IPv4 address", "cops.lastpdpaddr.ipv4",
1625 FT_IPv4, 0, NULL, 0xFFFF,
1626 "IPv4 address in COPS LastPDPAddr object", HFILL }
1628 { &hf_cops_lastpdpaddr_ipv6,
1629 { "IPv6 address", "cops.lastpdpaddr.ipv6",
1630 FT_IPv6, 0, NULL, 0xFFFF,
1631 "IPv6 address in COPS LastPDPAddr object", HFILL }
1633 { &hf_cops_pdp_tcp_port,
1634 { "TCP Port Number", "cops.pdp.tcp_port",
1635 FT_UINT32, BASE_DEC, NULL, 0x0,
1636 "TCP Port Number of PDP in PDPRedirAddr/LastPDPAddr object", HFILL }
1638 { &hf_cops_accttimer,
1639 { "Contents: ACCT Timer Value", "cops.accttimer.value",
1640 FT_UINT16, BASE_DEC, NULL, 0,
1641 "Accounting Timer Value in AcctTimer object", HFILL }
1644 { "Contents: Key ID", "cops.integrity.key_id",
1645 FT_UINT32, BASE_DEC, NULL, 0,
1646 "Key ID in Integrity object", HFILL }
1649 { "Contents: Sequence Number", "cops.integrity.seq_num",
1650 FT_UINT32, BASE_DEC, NULL, 0,
1651 "Sequence Number in Integrity object", HFILL }
1654 { "Error", "cops.gperror",
1655 FT_UINT16, BASE_DEC, VALS(cops_gperror_vals), 0,
1656 "Error in Error object", HFILL }
1658 { &hf_cops_gperror_sub,
1659 { "Error Sub-code", "cops.gperror_sub",
1660 FT_UINT16, BASE_HEX, NULL, 0,
1661 "Error Sub-code in Error object", HFILL }
1664 { "Error", "cops.cperror",
1665 FT_UINT16, BASE_DEC, VALS(cops_cperror_vals), 0,
1666 "Error in Error object", HFILL }
1668 { &hf_cops_cperror_sub,
1669 { "Error Sub-code", "cops.cperror_sub",
1670 FT_UINT16, BASE_HEX, NULL, 0,
1671 "Error Sub-code in Error object", HFILL }
1676 /* Setup protocol subtree array */
1677 static gint *ett[] = {
1679 &ett_cops_ver_flags,
1682 &ett_cops_r_type_flags,
1691 module_t* cops_module;
1693 /* Register the protocol name and description */
1694 proto_cops = proto_register_protocol("Common Open Policy Service",
1697 /* Required function calls to register the header fields and subtrees used */
1698 proto_register_field_array(proto_cops, hf, array_length(hf));
1699 proto_register_subtree_array(ett, array_length(ett));
1701 /* Register our configuration options for cops,
1702 * particularly our ports
1704 cops_module = prefs_register_protocol(proto_cops,
1705 proto_reg_handoff_cops);
1706 prefs_register_uint_preference(cops_module,"tcp.cops_port",
1708 "Set the TCP port for COPS messages",
1709 10,&global_cops_tcp_port);
1710 prefs_register_bool_preference(cops_module, "desegment",
1711 "Desegment all COPS messages spanning multiple TCP segments",
1712 "Whether the COPS dissector should desegment all messages spanning multiple TCP segments",
1717 proto_reg_handoff_cops(void)
1719 static int cops_prefs_initialized = FALSE;
1720 static dissector_handle_t cops_handle;
1722 if(!cops_prefs_initialized){
1723 cops_handle = create_dissector_handle(dissect_cops, proto_cops);
1724 cops_prefs_initialized = TRUE;
1727 dissector_delete("tcp.port",cops_tcp_port,cops_handle);
1730 /* Set our port numbers for future use */
1731 cops_tcp_port = global_cops_tcp_port;
1733 dissector_add("tcp.port", cops_tcp_port, cops_handle);