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.25 2002/03/12 10:40:01 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"
43 #include "format-oid.h"
46 #define TCP_PORT_COPS 3288
48 /* Variable to hold the tcp port preference */
49 static guint global_cops_tcp_port = TCP_PORT_COPS;
51 /* desegmentation of COPS */
52 static gboolean cops_desegment = TRUE;
54 /* Variable to allow for proper deletion of dissector registration
55 * when the user changes port from the gui
58 static guint cops_tcp_port = 0;
60 #define COPS_OBJECT_HDR_SIZE 4
62 /* Null string of type "guchar[]". */
63 static const guchar nullstring[] = "";
65 #define SAFE_STRING(s) (((s) != NULL) ? (s) : nullstring)
69 #define COPS_IPA 0 /* IP Address */
70 #define COPS_U32 2 /* Unsigned 32*/
71 #define COPS_TIT 3 /* TimeTicks */
72 #define COPS_OPQ 4 /* Opaque */
73 #define COPS_I64 10 /* Integer64 */
74 #define COPS_U64 11 /* Uinteger64 */
79 #define COPS_INTEGER 1 /* l */
80 #define COPS_OCTETSTR 2 /* c */
81 #define COPS_OBJECTID 3 /* ul */
82 #define COPS_IPADDR 4 /* uc */
83 #define COPS_UNSIGNED32 5 /* ul */
84 #define COPS_TIMETICKS 7 /* ul */
85 #define COPS_OPAQUE 8 /* c */
86 #define COPS_INTEGER64 10 /* ll */
87 #define COPS_UNSIGNED64 11 /* ull */
90 typedef struct _COPS_CNV COPS_CNV;
100 static COPS_CNV CopsCnv [] =
102 {ASN1_UNI, ASN1_NUL, COPS_NULL, "NULL"},
103 {ASN1_UNI, ASN1_INT, COPS_INTEGER, "INTEGER"},
104 {ASN1_UNI, ASN1_OTS, COPS_OCTETSTR, "OCTET STRING"},
105 {ASN1_UNI, ASN1_OJI, COPS_OBJECTID, "OBJECTID"},
106 {ASN1_APL, COPS_IPA, COPS_IPADDR, "IPADDR"},
107 {ASN1_APL, COPS_U32, COPS_UNSIGNED32,"UNSIGNED32"},
108 {ASN1_APL, COPS_TIT, COPS_TIMETICKS, "TIMETICKS"},
109 {ASN1_APL, COPS_OPQ, COPS_OPAQUE, "OPAQUE"},
110 {ASN1_APL, COPS_I64, COPS_INTEGER64, "INTEGER64"},
111 {ASN1_APL, COPS_U64, COPS_UNSIGNED64, "UNSIGNED64"},
116 cops_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
121 while (cnv->syntax != -1)
123 if (cnv->tag == tag && cnv->class == cls)
125 *syntax = cnv->syntax;
133 static const value_string cops_flags_vals[] = {
135 { 0x01, "Solicited Message Flag Bit" },
139 /* The different COPS message types */
141 COPS_NO_MSG, /* Not a COPS Message type */
143 COPS_MSG_REQ, /* Request (REQ) */
144 COPS_MSG_DEC, /* Decision (DEC) */
145 COPS_MSG_RPT, /* Report State (RPT) */
146 COPS_MSG_DRQ, /* Delete Request State (DRQ) */
147 COPS_MSG_SSQ, /* Synchronize State Req (SSQ) */
148 COPS_MSG_OPN, /* Client-Open (OPN) */
149 COPS_MSG_CAT, /* Client-Accept (CAT) */
150 COPS_MSG_CC, /* Client-Close (CC) */
151 COPS_MSG_KA, /* Keep-Alive (KA) */
152 COPS_MSG_SSC, /* Synchronize Complete (SSC) */
154 COPS_LAST_OP_CODE /* For error checking */
157 static const value_string cops_op_code_vals[] = {
158 { COPS_MSG_REQ, "Request (REQ)" },
159 { COPS_MSG_DEC, "Decision (DEC)" },
160 { COPS_MSG_RPT, "Report State (RPT)" },
161 { COPS_MSG_DRQ, "Delete Request State (DRQ)" },
162 { COPS_MSG_SSQ, "Synchronize State Req (SSQ)" },
163 { COPS_MSG_OPN, "Client-Open (OPN)" },
164 { COPS_MSG_CAT, "Client-Accept (CAT)" },
165 { COPS_MSG_CC, "Client-Close (CC)" },
166 { COPS_MSG_KA, "Keep-Alive (KA)" },
167 { COPS_MSG_SSC, "Synchronize Complete (SSC)" },
172 /* The different objects in COPS messages */
174 COPS_NO_OBJECT, /* Not a COPS Object type */
176 COPS_OBJ_HANDLE, /* Handle Object (Handle) */
177 COPS_OBJ_CONTEXT, /* Context Object (Context) */
178 COPS_OBJ_IN_INT, /* In-Interface Object (IN-Int) */
179 COPS_OBJ_OUT_INT, /* Out-Interface Object (OUT-Int) */
180 COPS_OBJ_REASON, /* Reason Object (Reason) */
181 COPS_OBJ_DECISION, /* Decision Object (Decision) */
182 COPS_OBJ_LPDPDECISION, /* LPDP Decision Object (LPDPDecision) */
183 COPS_OBJ_ERROR, /* Error Object (Error) */
184 COPS_OBJ_CLIENTSI, /* Client Specific Information Object (ClientSI) */
185 COPS_OBJ_KATIMER, /* Keep-Alive Timer Object (KATimer) */
186 COPS_OBJ_PEPID, /* PEP Identification Object (PEPID) */
187 COPS_OBJ_REPORT_TYPE, /* Report-Type Object (Report-Type) */
188 COPS_OBJ_PDPREDIRADDR, /* PDP Redirect Address Object (PDPRedirAddr) */
189 COPS_OBJ_LASTPDPADDR, /* Last PDP Address (LastPDPaddr) */
190 COPS_OBJ_ACCTTIMER, /* Accounting Timer Object (AcctTimer) */
191 COPS_OBJ_INTEGRITY, /* Message Integrity Object (Integrity) */
192 COPS_LAST_C_NUM /* For error checking */
195 static const value_string cops_c_num_vals[] = {
196 { COPS_OBJ_HANDLE, "Handle Object (Handle)" },
197 { COPS_OBJ_CONTEXT, "Context Object (Context)" },
198 { COPS_OBJ_IN_INT, "In-Interface Object (IN-Int)" },
199 { COPS_OBJ_OUT_INT, "Out-Interface Object (OUT-Int)" },
200 { COPS_OBJ_REASON, "Reason Object (Reason)" },
201 { COPS_OBJ_DECISION, "Decision Object (Decision)" },
202 { COPS_OBJ_LPDPDECISION, "LPDP Decision Object (LPDPDecision)" },
203 { COPS_OBJ_ERROR, "Error Object (Error)" },
204 { COPS_OBJ_CLIENTSI, "Client Specific Information Object (ClientSI)" },
205 { COPS_OBJ_KATIMER, "Keep-Alive Timer Object (KATimer)" },
206 { COPS_OBJ_PEPID, "PEP Identification Object (PEPID)" },
207 { COPS_OBJ_REPORT_TYPE, "Report-Type Object (Report-Type)" },
208 { COPS_OBJ_PDPREDIRADDR, "PDP Redirect Address Object (PDPRedirAddr)" },
209 { COPS_OBJ_LASTPDPADDR, "Last PDP Address (LastPDPaddr)" },
210 { COPS_OBJ_ACCTTIMER, "Accounting Timer Object (AcctTimer)" },
211 { COPS_OBJ_INTEGRITY, "Message Integrity Object (Integrity)" },
216 /* The different objects in COPS-PR messages */
218 COPS_NO_PR_OBJECT, /* Not a COPS-PR Object type */
219 COPS_OBJ_PRID, /* Provisioning Instance Identifier (PRID) */
220 COPS_OBJ_PPRID, /* Prefix Provisioning Instance Identifier (PPRID) */
221 COPS_OBJ_EPD, /* Encoded Provisioning Instance Data (EPD) */
222 COPS_OBJ_GPERR, /* Global Provisioning Error Object (GPERR) */
223 COPS_OBJ_CPERR, /* PRC Class Provisioning Error Object (CPERR) */
224 COPS_OBJ_ERRPRID, /* Error Provisioning Instance Identifier (ErrorPRID)*/
226 COPS_LAST_S_NUM /* For error checking */
230 static const value_string cops_s_num_vals[] = {
231 { COPS_OBJ_PRID, "Provisioning Instance Identifier (PRID)" },
232 { COPS_OBJ_PPRID, "Prefix Provisioning Instance Identifier (PPRID)" },
233 { COPS_OBJ_EPD, "Encoded Provisioning Instance Data (EPD)" },
234 { COPS_OBJ_GPERR, "Global Provisioning Error Object (GPERR)" },
235 { COPS_OBJ_CPERR, "PRC Class Provisioning Error Object (CPERR)" },
236 { COPS_OBJ_ERRPRID, "Error Provisioning Instance Identifier (ErrorPRID)" },
241 /* R-Type is carried within the Context Object */
242 static const value_string cops_r_type_vals[] = {
243 { 0x01, "Incoming-Message/Admission Control request" },
244 { 0x02, "Resource-Allocation request" },
245 { 0x04, "Outgoing-Message request" },
246 { 0x08, "Configuration request" },
249 /* S-Type is carried within the ClientSI Object for COPS-PR*/
250 static const value_string cops_s_type_vals[] = {
255 /* Reason-Code is carried within the Reason object */
256 static const value_string cops_reason_vals[] = {
257 { 1, "Unspecified" },
259 { 3, "Preempted (Another request state takes precedence)" },
260 { 4, "Tear (Used to communicate a signaled state removal)" },
261 { 5, "Timeout (Local state has timed-out)" },
262 { 6, "Route Change (Change invalidates request state)" },
263 { 7, "Insufficient Resources (No local resource available)" },
264 { 8, "PDP's Directive (PDP decision caused the delete)" },
265 { 9, "Unsupported decision (PDP decision not supported)" },
266 { 10, "Synchronize Handle Unknown" },
267 { 11, "Transient Handle (stateless event)" },
268 { 12, "Malformed Decision (could not recover)" },
269 { 13, "Unknown COPS Object from PDP" },
273 /* Command-Code is carried within the Decision object if C-Type is 1 */
274 static const value_string cops_dec_cmd_code_vals[] = {
275 { 0, "NULL Decision (No configuration data available)" },
276 { 1, "Install (Admit request/Install configuration)" },
277 { 2, "Remove (Remove request/Remove configuration)" },
281 /* Decision flags are also carried with the Decision object if C-Type is 1 */
282 static const value_string cops_dec_cmd_flag_vals[] = {
283 { 0x00, "<None set>" },
284 { 0x01, "Trigger Error (Trigger error message if set)" },
288 /* Error-Code from Error object */
289 static const value_string cops_error_vals[] = {
291 {2, "Invalid handle reference" },
292 {3, "Bad message format (Malformed Message)" },
293 {4, "Unable to process (server gives up on query)" },
294 {5, "Mandatory client-specific info missing" },
295 {6, "Unsupported client" },
296 {7, "Mandatory COPS object missing" },
297 {8, "Client Failure" },
298 {9, "Communication Failure" },
299 {10, "Unspecified" },
300 {11, "Shutting down" },
301 {12, "Redirect to Preferred Server" },
302 {13, "Unknown COPS Object" },
303 {14, "Authentication Failure" },
304 {15, "Authentication Required" },
307 /* Error-Code from GPERR object */
308 static const value_string cops_gperror_vals[] = {
310 {2, "AvailMemExhausted" },
311 {3, "unknownASN.1Tag" },
312 {4, "maxMsgSizeExceeded" },
313 {5, "unknownError" },
314 {6, "maxRequestStatesOpen" },
315 {7, "invalidASN.1Length" },
316 {8, "invalidObjectPad" },
317 {9, "unknownPIBData" },
318 {10, "unknownCOPSPRObject" },
319 {11, "malformedDecision" },
323 /* Error-Code from CPERR object */
324 static const value_string cops_cperror_vals[] = {
325 {1, "priSpaceExhausted" },
326 {2, "priInstanceInvalid" },
327 {3, "attrValueInvalid" },
328 {4, "attrValueSupLimited" },
329 {5, "attrEnumSupLimited" },
330 {6, "attrMaxLengthExceeded" },
331 {7, "attrReferenceUnknown" },
332 {8, "priNotifyOnly" },
334 {10, "tooFewAttrs" },
335 {11, "invalidAttrType" },
336 {12, "deletedInRef" },
337 {13, "priSpecificError" },
342 /* Report-Type from Report-Type object */
343 static const value_string cops_report_type_vals[] = {
344 {1, " Success : Decision was successful at the PEP" },
345 {2, " Failure : Decision could not be completed by PEP" },
346 {3, " Accounting: Accounting update for an installed state" },
350 /* Initialize the protocol and registered fields */
351 static gint proto_cops = -1;
352 static gint hf_cops_ver_flags = -1;
353 static gint hf_cops_version = -1;
354 static gint hf_cops_flags = -1;
356 static gint hf_cops_op_code = -1;
357 static gint hf_cops_client_type = -1;
358 static gint hf_cops_msg_len = -1;
360 static gint hf_cops_obj_len = -1;
361 static gint hf_cops_obj_c_num = -1;
362 static gint hf_cops_obj_c_type = -1;
364 static gint hf_cops_obj_s_num = -1;
365 static gint hf_cops_obj_s_type = -1;
367 static gint hf_cops_r_type_flags = -1;
368 static gint hf_cops_m_type_flags = -1;
370 static gint hf_cops_in_int_ipv4 = -1;
371 static gint hf_cops_in_int_ipv6 = -1;
372 static gint hf_cops_out_int_ipv4 = -1;
373 static gint hf_cops_out_int_ipv6 = -1;
374 static gint hf_cops_int_ifindex = -1;
376 static gint hf_cops_reason = -1;
377 static gint hf_cops_reason_sub = -1;
379 static gint hf_cops_dec_cmd_code = -1;
380 static gint hf_cops_dec_flags = -1;
382 static gint hf_cops_error = -1;
383 static gint hf_cops_error_sub = -1;
385 static gint hf_cops_gperror = -1;
386 static gint hf_cops_gperror_sub = -1;
388 static gint hf_cops_cperror = -1;
389 static gint hf_cops_cperror_sub = -1;
391 static gint hf_cops_katimer = -1;
393 static gint hf_cops_pepid = -1;
395 static gint hf_cops_report_type = -1;
397 static gint hf_cops_pdprediraddr_ipv4 = -1;
398 static gint hf_cops_pdprediraddr_ipv6 = -1;
399 static gint hf_cops_lastpdpaddr_ipv4 = -1;
400 static gint hf_cops_lastpdpaddr_ipv6 = -1;
401 static gint hf_cops_pdp_tcp_port = -1;
403 static gint hf_cops_accttimer = -1;
405 static gint hf_cops_key_id = -1;
406 static gint hf_cops_seq_num = -1;
408 /* Initialize the subtree pointers */
409 static gint ett_cops = -1;
410 static gint ett_cops_ver_flags = -1;
411 static gint ett_cops_obj = -1;
412 static gint ett_cops_pr_obj = -1;
413 static gint ett_cops_obj_data = -1;
414 static gint ett_cops_r_type_flags = -1;
415 static gint ett_cops_itf = -1;
416 static gint ett_cops_reason = -1;
417 static gint ett_cops_decision = -1;
418 static gint ett_cops_error = -1;
419 static gint ett_cops_gperror = -1;
420 static gint ett_cops_cperror = -1;
421 static gint ett_cops_pdp = -1;
423 void proto_reg_handoff_cops(void);
425 static void dissect_cops_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
427 static int dissect_cops_object(tvbuff_t *tvb, guint32 offset, proto_tree *tree);
428 static int dissect_cops_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
429 guint8 c_num, guint8 c_type, guint16 len);
431 static int dissect_cops_pr_objects(tvbuff_t *tvb, guint32 offset, proto_tree *tree, guint16 pr_len);
432 static int dissect_cops_pr_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
433 guint8 s_num, guint8 s_type, guint16 len);
435 /* Code to actually dissect the packets */
437 dissect_cops(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
439 volatile int offset = 0;
440 int length_remaining;
445 while (tvb_reported_length_remaining(tvb, offset) != 0) {
446 length_remaining = tvb_length_remaining(tvb, offset);
447 if (length_remaining == -1)
451 * Can we do reassembly?
453 if (cops_desegment && pinfo->can_desegment) {
455 * Yes - is the COPS header split across segment
458 if (length_remaining < 8) {
460 * Yes. Tell the TCP dissector where
461 * the data for this message starts in
462 * the data it handed us, and how many
463 * more bytes we need, and return.
465 pinfo->desegment_offset = offset;
466 pinfo->desegment_len = 8 - length_remaining;
472 * Get the length of the COPS message.
474 msg_len = tvb_get_ntohl(tvb, offset + 4);
477 * Can we do reassembly?
479 if (cops_desegment && pinfo->can_desegment) {
481 * Yes - is the DNS packet split across segment
484 if ((guint32)length_remaining < msg_len) {
486 * Yes. Tell the TCP dissector where
487 * the data for this message starts in
488 * the data it handed us, and how many
489 * more bytes we need, and return.
491 pinfo->desegment_offset = offset;
492 pinfo->desegment_len =
493 msg_len - length_remaining;
499 * Construct a tvbuff containing the amount of the payload
500 * we have available. Make its reported length the
501 * amount of data in the COPS packet.
503 * XXX - if reassembly isn't enabled. the subdissector
504 * will throw a BoundsError exception, rather than a
505 * ReportedBoundsError exception. We really want
506 * a tvbuff where the length is "length", the reported
507 * length is "plen + 2", and the "if the snapshot length
508 * were infinite" length were the minimum of the
509 * reported length of the tvbuff handed to us and "plen+2",
510 * with a new type of exception thrown if the offset is
511 * within the reported length but beyond that third length,
512 * with that exception getting the "Unreassembled Packet"
515 length = length_remaining;
516 if ((guint32)length > msg_len)
518 next_tvb = tvb_new_subset(tvb, offset, length, msg_len);
521 * Dissect the COPS packet.
523 * Catch the ReportedBoundsError exception; if this
524 * particular message happens to get a ReportedBoundsError
525 * exception, that doesn't mean that we should stop
526 * dissecting COPS messages within this frame or chunk
527 * of reassembled data.
529 * If it gets a BoundsError, we can stop, as there's nothing
530 * more to see, so we just re-throw it.
533 dissect_cops_pdu(next_tvb, pinfo, tree);
538 CATCH(ReportedBoundsError) {
539 show_reported_bounds_error(tvb, pinfo, tree);
544 * Skip the COPS packet.
551 dissect_cops_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
555 if (check_col(pinfo->cinfo, COL_PROTOCOL))
556 col_set_str(pinfo->cinfo, COL_PROTOCOL, "COPS");
557 if (check_col(pinfo->cinfo, COL_INFO))
558 col_clear(pinfo->cinfo, COL_INFO);
560 op_code = tvb_get_guint8(tvb, 1);
561 if (check_col(pinfo->cinfo, COL_INFO))
562 col_add_fstr(pinfo->cinfo, COL_INFO, "COPS %s",
563 val_to_str(op_code, cops_op_code_vals, "Unknown Op Code"));
567 proto_tree *cops_tree, *ver_flags_tree;
573 ti = proto_tree_add_item(tree, proto_cops, tvb, offset, -1, FALSE);
574 cops_tree = proto_item_add_subtree(ti, ett_cops);
576 /* Version and flags share the same byte, put them in a subtree */
577 ver_flags = tvb_get_guint8(tvb, offset);
578 tv = proto_tree_add_uint_format(cops_tree, hf_cops_ver_flags, tvb, offset, 1,
579 ver_flags, "Version: %u, Flags: %s",
580 hi_nibble(ver_flags),
581 val_to_str(lo_nibble(ver_flags), cops_flags_vals, "Unknown"));
582 ver_flags_tree = proto_item_add_subtree(tv, ett_cops_ver_flags);
583 proto_tree_add_uint(ver_flags_tree, hf_cops_version, tvb, offset, 1, ver_flags);
584 proto_tree_add_uint(ver_flags_tree, hf_cops_flags, tvb, offset, 1, ver_flags);
587 proto_tree_add_uint(cops_tree, hf_cops_op_code, tvb, offset, 1, tvb_get_guint8(tvb, offset));
589 proto_tree_add_uint(cops_tree, hf_cops_client_type, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
592 msg_len = tvb_get_ntohl(tvb, offset);
593 proto_tree_add_uint(cops_tree, hf_cops_msg_len, tvb, offset, 4, tvb_get_ntohl(tvb, offset));
596 while (tvb_reported_length_remaining(tvb, offset) >= COPS_OBJECT_HDR_SIZE)
597 offset += dissect_cops_object(tvb, offset, cops_tree);
599 garbage = tvb_length_remaining(tvb, offset);
601 proto_tree_add_text(cops_tree, tvb, offset, garbage,
602 "Trailing garbage: %d byte%s", garbage,
603 plurality(garbage, "", "s"));
609 static char *cops_c_type_to_str(guint8 c_num, guint8 c_type)
612 case COPS_OBJ_HANDLE:
614 return "Client Handle";
616 case COPS_OBJ_IN_INT:
617 case COPS_OBJ_OUT_INT:
619 return "IPv4 Address + Interface";
620 else if (c_type == 2)
621 return "IPv6 Address + Interface";
623 case COPS_OBJ_DECISION:
624 case COPS_OBJ_LPDPDECISION:
626 return "Decision Flags (Mandatory)";
627 else if (c_type == 2)
628 return "Stateless Data";
629 else if (c_type == 3)
630 return "Replacement Data";
631 else if (c_type == 4)
632 return "Client Specific Decision Data";
633 else if (c_type == 5)
634 return "Named Decision Data";
636 case COPS_OBJ_CLIENTSI:
638 return "Signaled ClientSI";
639 else if (c_type == 2)
640 return "Named ClientSI";
642 case COPS_OBJ_KATIMER:
644 return "Keep-alive timer value";
646 case COPS_OBJ_PDPREDIRADDR:
647 case COPS_OBJ_LASTPDPADDR:
649 return "IPv4 Address + TCP Port";
650 else if (c_type == 2)
651 return "IPv6 Address + TCP Port";
653 case COPS_OBJ_ACCTTIMER:
655 return "Accounting timer value";
657 case COPS_OBJ_INTEGRITY:
659 return "HMAC digest";
666 static int dissect_cops_object(tvbuff_t *tvb, guint32 offset, proto_tree *tree)
668 guint16 object_len, contents_len;
669 guint8 c_num, c_type;
671 proto_tree *obj_tree;
675 object_len = tvb_get_ntohs(tvb, offset);
676 c_num = tvb_get_guint8(tvb, offset + 2);
677 c_type = tvb_get_guint8(tvb, offset + 3);
679 ti = proto_tree_add_uint_format(tree, hf_cops_obj_c_num, tvb, offset, object_len, c_num,
680 "%s: %s", val_to_str(c_num, cops_c_num_vals, "Unknown"),
681 cops_c_type_to_str(c_num, c_type));
682 obj_tree = proto_item_add_subtree(ti, ett_cops_obj);
684 proto_tree_add_uint(obj_tree, hf_cops_obj_len, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
687 proto_tree_add_uint(obj_tree, hf_cops_obj_c_num, tvb, offset, 1, c_num);
690 type_str = cops_c_type_to_str(c_num, c_type);
691 proto_tree_add_text(obj_tree, tvb, offset, 1, "C-Type: %s%s%u%s",
693 strlen(type_str) ? " (" : "",
695 strlen(type_str) ? ")" : "");
698 contents_len = object_len - COPS_OBJECT_HDR_SIZE;
699 ret = dissect_cops_object_data(tvb, offset, obj_tree, c_num, c_type, contents_len);
700 if (ret < 0) return 0;
702 /* Pad to 32bit boundary */
703 if (object_len % sizeof (guint32))
704 object_len += (sizeof (guint32) - object_len % sizeof (guint32));
709 static int dissect_cops_pr_objects(tvbuff_t *tvb, guint32 offset, proto_tree *tree, guint16 pr_len)
711 guint16 object_len, contents_len;
712 guint8 s_num, s_type;
715 proto_tree *cops_pr_tree, *obj_tree;
718 cops_pr_tree = proto_item_add_subtree(tree, ett_cops_pr_obj);
720 while (pr_len >= COPS_OBJECT_HDR_SIZE) {
721 object_len = tvb_get_ntohs(tvb, offset);
722 s_num = tvb_get_guint8(tvb, offset + 2);
723 s_type = tvb_get_guint8(tvb, offset + 3);
725 ti = proto_tree_add_uint_format(cops_pr_tree, hf_cops_obj_s_num, tvb, offset, object_len, s_num,
726 "%s", val_to_str(s_num, cops_s_num_vals, "Unknown"));
727 obj_tree = proto_item_add_subtree(cops_pr_tree, ett_cops_pr_obj);
729 proto_tree_add_uint(obj_tree, hf_cops_obj_len, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
733 proto_tree_add_uint(obj_tree, hf_cops_obj_s_num, tvb, offset, 1, s_num);
737 type_str = val_to_str(s_type, cops_s_type_vals, "Unknown");
738 proto_tree_add_text(obj_tree, tvb, offset, 1, "S-Type: %s%s%u%s",
740 strlen(type_str) ? " (" : "",
742 strlen(type_str) ? ")" : "");
746 contents_len = object_len - COPS_OBJECT_HDR_SIZE;
747 ret = dissect_cops_pr_object_data(tvb, offset, obj_tree, s_num, s_type, contents_len);
751 /*Pad to 32bit boundary */
752 if (object_len % sizeof (guint32))
753 object_len += (sizeof (guint32) - object_len % sizeof (guint32));
755 pr_len -= object_len - COPS_OBJECT_HDR_SIZE;
756 offset += object_len - COPS_OBJECT_HDR_SIZE;
762 static int dissect_cops_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
763 guint8 c_num, guint8 c_type, guint16 len)
766 proto_tree *r_type_tree, *itf_tree, *reason_tree, *dec_tree, *error_tree, *pdp_tree;
767 guint16 r_type, m_type, reason, reason_sub, cmd_code, cmd_flags, error, error_sub, tcp_port;
768 guint32 ipv4addr, ifindex;
769 struct e_in6_addr ipv6addr;
772 case COPS_OBJ_CONTEXT:
773 r_type = tvb_get_ntohs(tvb, offset);
774 m_type = tvb_get_ntohs(tvb, offset + 2);
775 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: R-Type: %s, M-Type: %u",
776 val_to_str(r_type, cops_r_type_vals, "Unknown"),
779 r_type_tree = proto_item_add_subtree(ti, ett_cops_r_type_flags);
780 proto_tree_add_uint(r_type_tree, hf_cops_r_type_flags, tvb, offset, 2, r_type);
782 proto_tree_add_uint(r_type_tree, hf_cops_m_type_flags, tvb, offset, 2, m_type);
786 case COPS_OBJ_IN_INT:
787 case COPS_OBJ_OUT_INT:
788 if (c_type == 1) { /* IPv4 */
789 tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset, 4);
790 ifindex = tvb_get_ntohl(tvb, offset + 4);
791 ti = proto_tree_add_text(tree, tvb, offset, 8, "Contents: IPv4 address %s, ifIndex: %u",
792 ip_to_str((guint8 *)&ipv4addr), ifindex);
793 itf_tree = proto_item_add_subtree(ti, ett_cops_itf);
794 proto_tree_add_ipv4(itf_tree,
795 (c_num == COPS_OBJ_IN_INT) ? hf_cops_in_int_ipv4 : hf_cops_out_int_ipv4,
796 tvb, offset, 4, ipv4addr);
798 } else if (c_type == 2) { /* IPv6 */
799 tvb_memcpy(tvb, (guint8 *)&ipv6addr, offset, sizeof ipv6addr);
800 ifindex = tvb_get_ntohl(tvb, offset + sizeof ipv6addr);
801 ti = proto_tree_add_text(tree, tvb, offset, 20, "Contents: IPv6 address %s, ifIndex: %u",
802 ip6_to_str(&ipv6addr), ifindex);
803 itf_tree = proto_item_add_subtree(ti, ett_cops_itf);
804 proto_tree_add_ipv6(itf_tree,
805 (c_num == COPS_OBJ_IN_INT) ? hf_cops_in_int_ipv6 : hf_cops_out_int_ipv6,
806 tvb, offset, 16, (guint8 *)&ipv6addr);
811 proto_tree_add_uint(itf_tree, hf_cops_int_ifindex, tvb, offset, 4, ifindex);
815 case COPS_OBJ_REASON:
816 reason = tvb_get_ntohs(tvb, offset);
817 reason_sub = tvb_get_ntohs(tvb, offset + 2);
818 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Reason-Code: %s, Reason Sub-code: 0x%04x",
819 val_to_str(reason, cops_reason_vals, "<Unknown value>"), reason_sub);
820 reason_tree = proto_item_add_subtree(ti, ett_cops_reason);
821 proto_tree_add_uint(reason_tree, hf_cops_reason, tvb, offset, 2, reason);
824 proto_tree_add_text(reason_tree, tvb, offset, 2, "Reason Sub-code: "
825 "Unknown object's C-Num %u, C-Type %u",
826 tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
828 proto_tree_add_uint(reason_tree, hf_cops_reason_sub, tvb, offset, 2, reason_sub);
832 case COPS_OBJ_DECISION:
833 case COPS_OBJ_LPDPDECISION:
835 cmd_code = tvb_get_ntohs(tvb, offset);
836 cmd_flags = tvb_get_ntohs(tvb, offset + 2);
837 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Command-Code: %s, Flags: %s",
838 val_to_str(cmd_code, cops_dec_cmd_code_vals, "<Unknown value>"),
839 val_to_str(cmd_flags, cops_dec_cmd_flag_vals, "<Unknown flag>"));
840 dec_tree = proto_item_add_subtree(ti, ett_cops_decision);
841 proto_tree_add_uint(dec_tree, hf_cops_dec_cmd_code, tvb, offset, 2, cmd_code);
843 proto_tree_add_uint(dec_tree, hf_cops_dec_flags, tvb, offset, 2, cmd_flags);
844 } else if (c_type == 5) { /*COPS-PR Data*/
845 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: %u bytes", len);
846 dissect_cops_pr_objects(tvb, offset, ti, len);
856 error = tvb_get_ntohs(tvb, offset);
857 error_sub = tvb_get_ntohs(tvb, offset + 2);
858 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
859 val_to_str(error, cops_error_vals, "<Unknown value>"), error_sub);
860 error_tree = proto_item_add_subtree(ti, ett_cops_error);
861 proto_tree_add_uint(error_tree, hf_cops_error, tvb, offset, 2, error);
864 proto_tree_add_text(error_tree, tvb, offset, 2, "Error Sub-code: "
865 "Unknown object's C-Num %u, C-Type %u",
866 tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
868 proto_tree_add_uint(error_tree, hf_cops_error_sub, tvb, offset, 2, error_sub);
872 case COPS_OBJ_CLIENTSI:
874 if (c_type != 2) /*Not COPS-PR data*/
877 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: %u bytes", len);
879 dissect_cops_pr_objects(tvb, offset, ti, len);
883 case COPS_OBJ_KATIMER:
887 proto_tree_add_item(tree, hf_cops_katimer, tvb, offset + 2, 2, FALSE);
888 if (tvb_get_ntohs(tvb, offset + 2) == 0)
889 proto_tree_add_text(tree, tvb, offset, 0, "Value of zero implies infinity.");
897 if (tvb_strnlen(tvb, offset, len) == -1)
898 proto_tree_add_text(tree, tvb, offset, len, "<PEP Id is not a NUL terminated ASCII string>");
900 proto_tree_add_item(tree, hf_cops_pepid, tvb, offset,
901 tvb_strnlen(tvb, offset, len) + 1, FALSE);
905 case COPS_OBJ_REPORT_TYPE:
909 proto_tree_add_item(tree, hf_cops_report_type, tvb, offset, 2, FALSE);
913 case COPS_OBJ_PDPREDIRADDR:
914 case COPS_OBJ_LASTPDPADDR:
915 if (c_type == 1) { /* IPv4 */
916 tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset, 4);
917 tcp_port = tvb_get_ntohs(tvb, offset + 4 + 2);
918 ti = proto_tree_add_text(tree, tvb, offset, 8, "Contents: IPv4 address %s, TCP Port Number: %u",
919 ip_to_str((guint8 *)&ipv4addr), tcp_port);
920 pdp_tree = proto_item_add_subtree(ti, ett_cops_pdp);
921 proto_tree_add_ipv4(pdp_tree,
922 (c_num == COPS_OBJ_PDPREDIRADDR) ? hf_cops_pdprediraddr_ipv4 : hf_cops_lastpdpaddr_ipv4,
923 tvb, offset, 4, ipv4addr);
925 } else if (c_type == 2) { /* IPv6 */
926 tvb_memcpy(tvb, (guint8 *)&ipv6addr, offset, sizeof ipv6addr);
927 tcp_port = tvb_get_ntohs(tvb, offset + sizeof ipv6addr + 2);
928 ti = proto_tree_add_text(tree, tvb, offset, 20, "Contents: IPv6 address %s, TCP Port Number: %u",
929 ip6_to_str(&ipv6addr), tcp_port);
930 pdp_tree = proto_item_add_subtree(ti, ett_cops_pdp);
931 proto_tree_add_ipv6(pdp_tree,
932 (c_num == COPS_OBJ_PDPREDIRADDR) ? hf_cops_pdprediraddr_ipv6 : hf_cops_lastpdpaddr_ipv6,
933 tvb, offset, 16, (guint8 *)&ipv6addr);
939 proto_tree_add_uint(pdp_tree, hf_cops_pdp_tcp_port, tvb, offset, 2, tcp_port);
943 case COPS_OBJ_ACCTTIMER:
947 proto_tree_add_item(tree, hf_cops_accttimer, tvb, offset + 2, 2, FALSE);
948 if (tvb_get_ntohs(tvb, offset + 2) == 0)
949 proto_tree_add_text(tree, tvb, offset, 0, "Value of zero means "
950 "there SHOULD be no unsolicited accounting updates.");
954 case COPS_OBJ_INTEGRITY:
956 break; /* Not HMAC digest */
958 proto_tree_add_item(tree, hf_cops_key_id, tvb, offset, 4, FALSE);
959 proto_tree_add_item(tree, hf_cops_seq_num, tvb, offset + 4, 4, FALSE);
960 proto_tree_add_text(tree, tvb, offset + 8 , len - 8, "Contents: Keyed Message Digest");
969 ti = proto_tree_add_text(tree, tvb, offset, len, "Contents: %u bytes", len);
974 static int decode_cops_pr_asn1_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree, guint epdlen)
988 subid_t *variable_oid;
989 guint variable_oid_length;
991 gint32 vb_integer_value;
992 guint32 vb_uinteger_value;
994 guint8 *vb_octet_string;
999 gchar *vb_display_string;
1001 guint variable_length;
1007 while (epdlen > 0){ /*while there is stuff to be decoded*/
1009 asn1_open(&asn1, tvb, offset);
1012 /* parse the type of the object */
1014 start = asn1.offset;
1016 ret = asn1_header_decode (&asn1, &cls, &con, &tag, &def, &vb_length);
1017 if (ret != ASN1_ERR_NOERROR)
1020 return ASN1_ERR_LENGTH_NOT_DEFINITE;
1022 /* Convert the class, constructed flag, and tag to a type. */
1023 vb_type_name = cops_tag_cls2syntax(tag, cls, &vb_type);
1024 if (vb_type_name == NULL) {
1027 * Dissect the value as an opaque string of octets.
1029 vb_type_name = "unsupported type";
1030 vb_type = COPS_OPAQUE;
1033 /* parse the value */
1038 ret = asn1_int32_value_decode(&asn1, vb_length,
1040 if (ret != ASN1_ERR_NOERROR)
1042 length = asn1.offset - start;
1044 proto_tree_add_text(tree, asn1.tvb, offset, length,
1045 "Value: %s: %d (%#x)", vb_type_name,
1046 vb_integer_value, vb_integer_value);
1051 case COPS_UNSIGNED32:
1052 case COPS_TIMETICKS:
1053 ret = asn1_uint32_value_decode(&asn1, vb_length,
1054 &vb_uinteger_value);
1055 if (ret != ASN1_ERR_NOERROR)
1057 length = asn1.offset - start;
1059 proto_tree_add_text(tree, asn1.tvb, offset, length,
1060 "Value: %s: %u (%#x)", vb_type_name,
1061 vb_uinteger_value, vb_uinteger_value);
1068 case COPS_UNSIGNED64:
1069 case COPS_INTEGER64:
1070 ret = asn1_string_value_decode (&asn1, vb_length,
1072 if (ret != ASN1_ERR_NOERROR)
1074 length = asn1.offset - start;
1077 * If some characters are not printable, display
1078 * the string as bytes.
1080 for (i = 0; i < vb_length; i++) {
1081 if (!(isprint(vb_octet_string[i])
1082 || isspace(vb_octet_string[i])))
1085 if (i < vb_length) {
1087 * We stopped, due to a non-printable
1088 * character, before we got to the end
1091 vb_display_string = g_malloc(4*vb_length);
1092 buf = &vb_display_string[0];
1093 len = sprintf(buf, "%03u", vb_octet_string[0]);
1095 for (i = 1; i < vb_length; i++) {
1096 len = sprintf(buf, ".%03u",
1097 vb_octet_string[i]);
1100 proto_tree_add_text(tree, asn1.tvb, offset, length,
1101 "Value: %s: %s", vb_type_name,
1103 g_free(vb_display_string);
1105 proto_tree_add_text(tree, asn1.tvb, offset, length,
1106 "Value: %s: %.*s", vb_type_name,
1108 SAFE_STRING(vb_octet_string));
1111 g_free(vb_octet_string);
1115 ret = asn1_null_decode (&asn1, vb_length);
1116 if (ret != ASN1_ERR_NOERROR)
1118 length = asn1.offset - start;
1120 proto_tree_add_text(tree, asn1.tvb, offset, length,
1121 "Value: %s", vb_type_name);
1126 ret = asn1_oid_value_decode (&asn1, vb_length, &vb_oid,
1128 if (ret != ASN1_ERR_NOERROR)
1130 length = asn1.offset - start;
1133 vb_display_string = format_oid(vb_oid, vb_oid_length);
1134 proto_tree_add_text(tree, asn1.tvb, offset, length,
1135 "Value: %s: %s", vb_type_name, vb_display_string);
1136 g_free(vb_display_string);
1142 #ifdef HAVE_SPRINT_VALUE
1146 variable.val.objid = vb_oid;
1147 vb_display_string = format_var(&variable,
1148 variable_oid, variable_oid_length, vb_type,
1150 proto_tree_add_text(tree, asn1.tvb, offset,
1152 "Value: %s", vb_display_string);
1153 break; /* we added formatted version to the tree */
1155 #endif /* HAVE_SPRINT_VALUE */
1157 vb_display_string = format_oid(vb_oid, vb_oid_length);
1158 proto_tree_add_text(tree, asn1.tvb, offset, length,
1159 "Value: %s: %s", vb_type_name, vb_display_string);
1160 g_free(vb_display_string);
1169 g_assert_not_reached();
1170 return ASN1_ERR_WRONG_TYPE;
1173 asn1_close(&asn1,&offset);
1180 static int dissect_cops_pr_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
1181 guint8 s_num, guint8 s_type, guint16 len)
1184 proto_tree *gperror_tree, *cperror_tree;
1185 guint16 gperror=0, gperror_sub=0, cperror=0, cperror_sub=0;
1189 if (s_type != 1) /* Not Provisioning Instance Identifier (PRID) */
1192 ti=proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1194 decode_cops_pr_asn1_data(tvb, offset, ti, len);
1199 case COPS_OBJ_PPRID:
1200 if (s_type != 1) /* Not Prefix Provisioning Instance Identifier (PPRID) */
1203 ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1205 decode_cops_pr_asn1_data(tvb, offset, ti, len);
1210 if (s_type != 1) /* Not Encoded Provisioning Instance Data (EPD) */
1213 ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1215 decode_cops_pr_asn1_data(tvb, offset, ti, len);
1219 case COPS_OBJ_GPERR:
1220 if (s_type != 1) /* Not Global Provisioning Error Object (GPERR) */
1223 gperror = tvb_get_ntohs(tvb, offset);
1224 gperror_sub = tvb_get_ntohs(tvb, offset + 2);
1225 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
1226 val_to_str(gperror, cops_gperror_vals, "<Unknown value>"), gperror_sub);
1227 gperror_tree = proto_item_add_subtree(ti, ett_cops_gperror);
1228 proto_tree_add_uint(gperror_tree, hf_cops_gperror, tvb, offset, 2, gperror);
1230 if (cperror == 13) {
1231 proto_tree_add_text(gperror_tree, tvb, offset, 2, "Error Sub-code: "
1232 "Unknown object's C-Num %u, C-Type %u",
1233 tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
1235 proto_tree_add_uint(gperror_tree, hf_cops_gperror_sub, tvb, offset, 2, gperror_sub);
1239 case COPS_OBJ_CPERR:
1240 if (s_type != 1) /*Not PRC Class Provisioning Error Object (CPERR) */
1245 cperror = tvb_get_ntohs(tvb, offset);
1246 cperror_sub = tvb_get_ntohs(tvb, offset + 2);
1247 ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
1248 val_to_str(cperror, cops_cperror_vals, "<Unknown value>"), cperror_sub);
1249 cperror_tree = proto_item_add_subtree(ti, ett_cops_cperror);
1250 proto_tree_add_uint(cperror_tree, hf_cops_cperror, tvb, offset, 2, cperror);
1252 if (cperror == 13) {
1253 proto_tree_add_text(cperror_tree, tvb, offset, 2, "Error Sub-code: "
1254 "Unknown object's S-Num %u, C-Type %u",
1255 tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
1257 proto_tree_add_uint(cperror_tree, hf_cops_cperror_sub, tvb, offset, 2, cperror_sub);
1261 case COPS_OBJ_ERRPRID:
1262 if (s_type != 1) /*Not Error Provisioning Instance Identifier (ErrorPRID)*/
1265 ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1267 decode_cops_pr_asn1_data(tvb, offset, ti, len);
1275 ti = proto_tree_add_text(tree, tvb, offset, len, "Contents: %u bytes", len);
1281 /* Register the protocol with Ethereal */
1282 void proto_register_cops(void)
1285 /* Setup list of header fields */
1286 static hf_register_info hf[] = {
1287 { &hf_cops_ver_flags,
1288 { "Version and Flags", "cops.ver_flags",
1289 FT_UINT8, BASE_HEX, NULL, 0x0,
1290 "Version and Flags in COPS Common Header", HFILL }
1293 { "Version", "cops.version",
1294 FT_UINT8, BASE_DEC, NULL, 0xF0,
1295 "Version in COPS Common Header", HFILL }
1298 { "Flags", "cops.flags",
1299 FT_UINT8, BASE_HEX, VALS(cops_flags_vals), 0x0F,
1300 "Flags in COPS Common Header", HFILL }
1303 { "Op Code", "cops.op_code",
1304 FT_UINT8, BASE_DEC, VALS(cops_op_code_vals), 0x0,
1305 "Op Code in COPS Common Header", HFILL }
1307 { &hf_cops_client_type,
1308 { "Client Type", "cops.client_type",
1309 FT_UINT16, BASE_DEC, NULL, 0x0,
1310 "Client Type in COPS Common Header", HFILL }
1313 { "Message Length", "cops.msg_len",
1314 FT_UINT32, BASE_DEC, NULL, 0x0,
1315 "Message Length in COPS Common Header", HFILL }
1318 { "Object Length", "cops.obj.len",
1319 FT_UINT32, BASE_DEC, NULL, 0x0,
1320 "Object Length in COPS Object Header", HFILL }
1322 { &hf_cops_obj_c_num,
1323 { "C-Num", "cops.c_num",
1324 FT_UINT8, BASE_DEC, VALS(cops_c_num_vals), 0x0,
1325 "C-Num in COPS Object Header", HFILL }
1327 { &hf_cops_obj_c_type,
1328 { "C-Type", "cops.c_type",
1329 FT_UINT8, BASE_DEC, NULL, 0x0,
1330 "C-Type in COPS Object Header", HFILL }
1333 { &hf_cops_obj_s_num,
1334 { "S-Num", "cops.s_num",
1335 FT_UINT8, BASE_DEC, VALS(cops_s_num_vals), 0x0,
1336 "S-Num in COPS-PR Object Header", HFILL }
1338 { &hf_cops_obj_s_type,
1339 { "S-Type", "cops.s_type",
1340 FT_UINT8, BASE_DEC, NULL, 0x0,
1341 "S-Type in COPS-PR Object Header", HFILL }
1344 { &hf_cops_r_type_flags,
1345 { "R-Type", "cops.context.r_type",
1346 FT_UINT16, BASE_HEX, VALS(cops_r_type_vals), 0xFFFF,
1347 "R-Type in COPS Context Object", HFILL }
1349 { &hf_cops_m_type_flags,
1350 { "M-Type", "cops.context.m_type",
1351 FT_UINT16, BASE_HEX, NULL, 0xFFFF,
1352 "M-Type in COPS Context Object", HFILL }
1354 { &hf_cops_in_int_ipv4,
1355 { "IPv4 address", "cops.in-int.ipv4",
1356 FT_IPv4, 0, NULL, 0xFFFF,
1357 "IPv4 address in COPS IN-Int object", HFILL }
1359 { &hf_cops_in_int_ipv6,
1360 { "IPv6 address", "cops.in-int.ipv6",
1361 FT_IPv6, 0, NULL, 0xFFFF,
1362 "IPv6 address in COPS IN-Int object", HFILL }
1364 { &hf_cops_out_int_ipv4,
1365 { "IPv4 address", "cops.out-int.ipv4",
1366 FT_IPv4, 0, NULL, 0xFFFF,
1367 "IPv4 address in COPS OUT-Int object", HFILL }
1369 { &hf_cops_out_int_ipv6,
1370 { "IPv6 address", "cops.out-int.ipv6",
1371 FT_IPv6, 0, NULL, 0xFFFF,
1372 "IPv6 address in COPS OUT-Int", HFILL }
1374 { &hf_cops_int_ifindex,
1375 { "ifIndex", "cops.in-out-int.ifindex",
1376 FT_UINT32, BASE_DEC, NULL, 0x0,
1377 "If SNMP is supported, corresponds to MIB-II ifIndex", HFILL }
1380 { "Reason", "cops.reason",
1381 FT_UINT16, BASE_DEC, VALS(cops_reason_vals), 0,
1382 "Reason in Reason object", HFILL }
1384 { &hf_cops_reason_sub,
1385 { "Reason Sub-code", "cops.reason_sub",
1386 FT_UINT16, BASE_HEX, NULL, 0,
1387 "Reason Sub-code in Reason object", HFILL }
1389 { &hf_cops_dec_cmd_code,
1390 { "Command-Code", "cops.decision.cmd",
1391 FT_UINT16, BASE_DEC, VALS(cops_dec_cmd_code_vals), 0,
1392 "Command-Code in Decision/LPDP Decision object", HFILL }
1394 { &hf_cops_dec_flags,
1395 { "Flags", "cops.decision.flags",
1396 FT_UINT16, BASE_HEX, VALS(cops_dec_cmd_flag_vals), 0xffff,
1397 "Flags in Decision/LPDP Decision object", HFILL }
1400 { "Error", "cops.error",
1401 FT_UINT16, BASE_DEC, VALS(cops_error_vals), 0,
1402 "Error in Error object", HFILL }
1404 { &hf_cops_error_sub,
1405 { "Error Sub-code", "cops.error_sub",
1406 FT_UINT16, BASE_HEX, NULL, 0,
1407 "Error Sub-code in Error object", HFILL }
1410 { "Contents: KA Timer Value", "cops.katimer.value",
1411 FT_UINT16, BASE_DEC, NULL, 0,
1412 "Keep-Alive Timer Value in KATimer object", HFILL }
1415 { "Contents: PEP Id", "cops.pepid.id",
1416 FT_STRING, BASE_NONE, NULL, 0,
1417 "PEP Id in PEPID object", HFILL }
1419 { &hf_cops_report_type,
1420 { "Contents: Report-Type", "cops.report_type",
1421 FT_UINT16, BASE_DEC, VALS(cops_report_type_vals), 0,
1422 "Report-Type in Report-Type object", HFILL }
1424 { &hf_cops_pdprediraddr_ipv4,
1425 { "IPv4 address", "cops.pdprediraddr.ipv4",
1426 FT_IPv4, 0, NULL, 0xFFFF,
1427 "IPv4 address in COPS PDPRedirAddr object", HFILL }
1429 { &hf_cops_pdprediraddr_ipv6,
1430 { "IPv6 address", "cops.pdprediraddr.ipv6",
1431 FT_IPv6, 0, NULL, 0xFFFF,
1432 "IPv6 address in COPS PDPRedirAddr object", HFILL }
1434 { &hf_cops_lastpdpaddr_ipv4,
1435 { "IPv4 address", "cops.lastpdpaddr.ipv4",
1436 FT_IPv4, 0, NULL, 0xFFFF,
1437 "IPv4 address in COPS LastPDPAddr object", HFILL }
1439 { &hf_cops_lastpdpaddr_ipv6,
1440 { "IPv6 address", "cops.lastpdpaddr.ipv6",
1441 FT_IPv6, 0, NULL, 0xFFFF,
1442 "IPv6 address in COPS LastPDPAddr object", HFILL }
1444 { &hf_cops_pdp_tcp_port,
1445 { "TCP Port Number", "cops.pdp.tcp_port",
1446 FT_UINT32, BASE_DEC, NULL, 0x0,
1447 "TCP Port Number of PDP in PDPRedirAddr/LastPDPAddr object", HFILL }
1449 { &hf_cops_accttimer,
1450 { "Contents: ACCT Timer Value", "cops.accttimer.value",
1451 FT_UINT16, BASE_DEC, NULL, 0,
1452 "Accounting Timer Value in AcctTimer object", HFILL }
1455 { "Contents: Key ID", "cops.integrity.key_id",
1456 FT_UINT32, BASE_DEC, NULL, 0,
1457 "Key ID in Integrity object", HFILL }
1460 { "Contents: Sequence Number", "cops.integrity.seq_num",
1461 FT_UINT32, BASE_DEC, NULL, 0,
1462 "Sequence Number in Integrity object", HFILL }
1465 { "Error", "cops.gperror",
1466 FT_UINT16, BASE_DEC, VALS(cops_gperror_vals), 0,
1467 "Error in Error object", HFILL }
1469 { &hf_cops_gperror_sub,
1470 { "Error Sub-code", "cops.gperror_sub",
1471 FT_UINT16, BASE_HEX, NULL, 0,
1472 "Error Sub-code in Error object", HFILL }
1475 { "Error", "cops.cperror",
1476 FT_UINT16, BASE_DEC, VALS(cops_cperror_vals), 0,
1477 "Error in Error object", HFILL }
1479 { &hf_cops_cperror_sub,
1480 { "Error Sub-code", "cops.cperror_sub",
1481 FT_UINT16, BASE_HEX, NULL, 0,
1482 "Error Sub-code in Error object", HFILL }
1487 /* Setup protocol subtree array */
1488 static gint *ett[] = {
1490 &ett_cops_ver_flags,
1493 &ett_cops_r_type_flags,
1502 module_t* cops_module;
1504 /* Register the protocol name and description */
1505 proto_cops = proto_register_protocol("Common Open Policy Service",
1508 /* Required function calls to register the header fields and subtrees used */
1509 proto_register_field_array(proto_cops, hf, array_length(hf));
1510 proto_register_subtree_array(ett, array_length(ett));
1512 /* Register our configuration options for cops,
1513 * particularly our ports
1515 cops_module = prefs_register_protocol(proto_cops,
1516 proto_reg_handoff_cops);
1517 prefs_register_uint_preference(cops_module,"tcp.cops_port",
1519 "Set the TCP port for COPS messages",
1520 10,&global_cops_tcp_port);
1521 prefs_register_bool_preference(cops_module, "desegment",
1522 "Desegment all COPS messages spanning multiple TCP segments",
1523 "Whether the COPS dissector should desegment all messages spanning multiple TCP segments",
1528 proto_reg_handoff_cops(void)
1530 static int cops_prefs_initialized = FALSE;
1531 static dissector_handle_t cops_handle;
1533 if(!cops_prefs_initialized){
1534 cops_handle = create_dissector_handle(dissect_cops, proto_cops);
1535 cops_prefs_initialized = TRUE;
1538 dissector_delete("tcp.port",cops_tcp_port,cops_handle);
1541 /* Set our port numbers for future use */
1542 cops_tcp_port = global_cops_tcp_port;
1544 dissector_add("tcp.port", cops_tcp_port, cops_handle);