Win32 only: Preference setting to open a console window, one of:
[metze/wireshark/wip.git] / packet-cops.c
1 /* packet-cops.c
2  * Routines for the COPS (Common Open Policy Service) protocol dissection
3  * RFC2748 & COPS-PR extension RFC3084
4  *
5  * Copyright 2000, Heikki Vatiainen <hessu@cs.tut.fi>
6  *
7  * Added PacketCable specifications by Dick Gooris <gooris@lucent.com>
8  *
9  * Taken from PacketCable specifications :
10  *    PacketCable Dynamic Quality-of-Service Specification
11  *    Based on PKT-SP-DQOS-I09-040402 (April 2, 2004)
12  *    www.packetcable.com
13  *
14  * Implemented in ethereal at April 7-8, 2004
15  *
16  * $Id: packet-cops.c,v 1.48 2004/05/04 06:01:52 guy Exp $
17  *
18  * Ethereal - Network traffic analyzer
19  * By Gerald Combs <gerald@ethereal.com>
20  * Copyright 1998 Gerald Combs
21  *
22  * This program is free software; you can redistribute it and/or
23  * modify it under the terms of the GNU General Public License
24  * as published by the Free Software Foundation; either version 2
25  * of the License, or (at your option) any later version.
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  * GNU General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License
33  * along with this program; if not, write to the Free Software
34  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  */
36
37 #ifdef HAVE_CONFIG_H
38 # include "config.h"
39 #endif
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <ctype.h>
45
46 #include <glib.h>
47 #include <epan/packet.h>
48 #include "packet-ipv6.h"
49 #include "packet-tcp.h"
50
51 #ifdef HAVE_SOME_SNMP
52 #ifdef HAVE_NET_SNMP
53 # include <net-snmp/net-snmp-config.h>
54 # include <net-snmp/mib_api.h>
55 # include <net-snmp/library/default_store.h>
56 # include <net-snmp/config_api.h>
57 #else /* HAVE_NET_SNMP */
58 # include <ucd-snmp/ucd-snmp-config.h>
59 # include <ucd-snmp/asn1.h>
60 # include <ucd-snmp/snmp_api.h>
61 # include <ucd-snmp/snmp_impl.h>
62 # include <ucd-snmp/mib.h>
63 # include <ucd-snmp/default_store.h>
64 # include <ucd-snmp/read_config.h>
65 # include <ucd-snmp/tools.h>
66 #endif /* HAVE_NET_SNMP */
67 #endif /* HAVE_SOME_SNMP */
68
69 #include "asn1.h"
70 #include "format-oid.h"
71 #include "prefs.h"
72
73 /* For PacketCable, port 2126 */
74 #define TCP_PORT_COPS 3288
75
76 /* Preference: Variable to hold the tcp port preference */
77 static guint global_cops_tcp_port = TCP_PORT_COPS;
78
79 /* Preference: desegmentation of COPS */
80 static gboolean cops_desegment = TRUE;
81
82 /* Variable to allow for proper deletion of dissector registration
83  * when the user changes port from the gui
84  */
85
86 static guint cops_tcp_port = 0;
87
88 /*Some local globals needed to read COPS-PR ASN.1 Types from PIB-MIBs */
89 /*MAX_OID_LEN from NET-SNMP's asn1.h*/
90
91 #ifdef HAVE_NET_SNMP
92 static  subid_t last_decoded_prid_oid[MAX_OID_LEN]={0};
93 static  subid_t last_decoded_prid_oid_length=0;
94 extern struct tree *tree_head;
95
96 /* Preference: COPS-PR ASN.1 type decoding based on PIB/MIB or data in packet */
97 static gboolean cops_typefrommib = FALSE;
98
99 #endif /* HAVE_NET_SNMP */
100
101 #define COPS_OBJECT_HDR_SIZE 4
102
103 /* Null string of type "guchar[]". */
104 static const guchar nullstring[] = "";
105
106 #define SAFE_STRING(s)  (((s) != NULL) ? (s) : nullstring)
107
108 /* COPS PR Tags */
109
110 #define COPS_IPA    0           /* IP Address */
111 #define COPS_U32    2           /* Unsigned 32*/
112 #define COPS_TIT    3           /* TimeTicks */
113 #define COPS_OPQ    4           /* Opaque */
114 #define COPS_I64    10          /* Integer64 */
115 #define COPS_U64    11          /* Uinteger64 */
116
117 /* COPS PR Types */
118
119 #define COPS_NULL                0
120 #define COPS_INTEGER             1    /* l  */
121 #define COPS_OCTETSTR            2    /* c  */
122 #define COPS_OBJECTID            3    /* ul */
123 #define COPS_IPADDR              4    /* uc */
124 #define COPS_UNSIGNED32          5    /* ul */
125 #define COPS_TIMETICKS           7    /* ul */
126 #define COPS_OPAQUE              8    /* c  */
127 #define COPS_INTEGER64           10   /* ll */
128 #define COPS_UNSIGNED64          11   /* ull  */
129
130
131 typedef struct _COPS_CNV COPS_CNV;
132
133 struct _COPS_CNV
134 {
135   guint class;
136   guint tag;
137   gint  syntax;
138   gchar *name;
139 };
140
141 static COPS_CNV CopsCnv [] =
142 {
143   {ASN1_UNI, ASN1_NUL, COPS_NULL,      "NULL"},
144   {ASN1_UNI, ASN1_INT, COPS_INTEGER,   "INTEGER"},
145   {ASN1_UNI, ASN1_OTS, COPS_OCTETSTR,  "OCTET STRING"},
146   {ASN1_UNI, ASN1_OJI, COPS_OBJECTID,  "OBJECTID"},
147   {ASN1_APL, COPS_IPA, COPS_IPADDR,    "IPADDR"},
148   {ASN1_APL, COPS_U32, COPS_UNSIGNED32,"UNSIGNED32"},
149   {ASN1_APL, COPS_TIT, COPS_TIMETICKS, "TIMETICKS"},
150   {ASN1_APL, COPS_OPQ, COPS_OPAQUE,    "OPAQUE"},
151   {ASN1_APL, COPS_I64, COPS_INTEGER64, "INTEGER64"},
152   {ASN1_APL, COPS_U64, COPS_UNSIGNED64, "UNSIGNED64"},
153   {0,       0,         -1,                  NULL}
154 };
155
156 static gchar *
157 cops_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
158 {
159   COPS_CNV *cnv;
160
161   cnv = CopsCnv;
162   while (cnv->syntax != -1)
163   {
164     if (cnv->tag == tag && cnv->class == cls)
165     {
166       *syntax = cnv->syntax;
167       return cnv->name;
168     }
169     cnv++;
170   }
171   return NULL;
172 }
173
174 static const value_string cops_flags_vals[] = {
175   { 0x00,          "None" },
176   { 0x01,          "Solicited Message Flag Bit" },
177   { 0, NULL },
178 };
179
180 /* The different COPS message types */
181 enum cops_op_code {
182   COPS_NO_MSG,          /* Not a COPS Message type     */
183
184   COPS_MSG_REQ,         /* Request (REQ)               */
185   COPS_MSG_DEC,         /* Decision (DEC)              */
186   COPS_MSG_RPT,         /* Report State (RPT)          */
187   COPS_MSG_DRQ,         /* Delete Request State (DRQ)  */
188   COPS_MSG_SSQ,         /* Synchronize State Req (SSQ) */
189   COPS_MSG_OPN,         /* Client-Open (OPN)           */
190   COPS_MSG_CAT,         /* Client-Accept (CAT)         */
191   COPS_MSG_CC,          /* Client-Close (CC)           */
192   COPS_MSG_KA,          /* Keep-Alive (KA)             */
193   COPS_MSG_SSC,         /* Synchronize Complete (SSC)  */
194
195   COPS_LAST_OP_CODE     /* For error checking          */
196 };
197
198 static const value_string cops_op_code_vals[] = {
199   { COPS_MSG_REQ,          "Request (REQ)" },
200   { COPS_MSG_DEC,          "Decision (DEC)" },
201   { COPS_MSG_RPT,          "Report State (RPT)" },
202   { COPS_MSG_DRQ,          "Delete Request State (DRQ)" },
203   { COPS_MSG_SSQ,          "Synchronize State Req (SSQ)" },
204   { COPS_MSG_OPN,          "Client-Open (OPN)" },
205   { COPS_MSG_CAT,          "Client-Accept (CAT)" },
206   { COPS_MSG_CC,           "Client-Close (CC)" },
207   { COPS_MSG_KA,           "Keep-Alive (KA)" },
208   { COPS_MSG_SSC,          "Synchronize Complete (SSC)" },
209   { 0, NULL },
210 };
211
212
213 /* The different objects in COPS messages */
214 enum cops_c_num {
215   COPS_NO_OBJECT,        /* Not a COPS Object type               */
216
217   COPS_OBJ_HANDLE,       /* Handle Object (Handle)               */
218   COPS_OBJ_CONTEXT,      /* Context Object (Context)             */
219   COPS_OBJ_IN_INT,       /* In-Interface Object (IN-Int)         */
220   COPS_OBJ_OUT_INT,      /* Out-Interface Object (OUT-Int)       */
221   COPS_OBJ_REASON,       /* Reason Object (Reason)               */
222   COPS_OBJ_DECISION,     /* Decision Object (Decision)           */
223   COPS_OBJ_LPDPDECISION, /* LPDP Decision Object (LPDPDecision)  */
224   COPS_OBJ_ERROR,        /* Error Object (Error)                 */
225   COPS_OBJ_CLIENTSI,     /* Client Specific Information Object (ClientSI) */
226   COPS_OBJ_KATIMER,      /* Keep-Alive Timer Object (KATimer)    */
227   COPS_OBJ_PEPID,        /* PEP Identification Object (PEPID)    */
228   COPS_OBJ_REPORT_TYPE,  /* Report-Type Object (Report-Type)     */
229   COPS_OBJ_PDPREDIRADDR, /* PDP Redirect Address Object (PDPRedirAddr) */
230   COPS_OBJ_LASTPDPADDR,  /* Last PDP Address (LastPDPaddr)       */
231   COPS_OBJ_ACCTTIMER,    /* Accounting Timer Object (AcctTimer)  */
232   COPS_OBJ_INTEGRITY,    /* Message Integrity Object (Integrity) */
233   COPS_LAST_C_NUM        /* For error checking                   */
234 };
235
236 static const value_string cops_c_num_vals[] = {
237   { COPS_OBJ_HANDLE,       "Handle Object (Handle)" },
238   { COPS_OBJ_CONTEXT,      "Context Object (Context)" },
239   { COPS_OBJ_IN_INT,       "In-Interface Object (IN-Int)" },
240   { COPS_OBJ_OUT_INT,      "Out-Interface Object (OUT-Int)" },
241   { COPS_OBJ_REASON,       "Reason Object (Reason)" },
242   { COPS_OBJ_DECISION,     "Decision Object (Decision)" },
243   { COPS_OBJ_LPDPDECISION, "LPDP Decision Object (LPDPDecision)" },
244   { COPS_OBJ_ERROR,        "Error Object (Error)" },
245   { COPS_OBJ_CLIENTSI,     "Client Specific Information Object (ClientSI)" },
246   { COPS_OBJ_KATIMER,      "Keep-Alive Timer Object (KATimer)" },
247   { COPS_OBJ_PEPID,        "PEP Identification Object (PEPID)" },
248   { COPS_OBJ_REPORT_TYPE,  "Report-Type Object (Report-Type)" },
249   { COPS_OBJ_PDPREDIRADDR, "PDP Redirect Address Object (PDPRedirAddr)" },
250   { COPS_OBJ_LASTPDPADDR,  "Last PDP Address (LastPDPaddr)" },
251   { COPS_OBJ_ACCTTIMER,    "Accounting Timer Object (AcctTimer)" },
252   { COPS_OBJ_INTEGRITY,    "Message Integrity Object (Integrity)" },
253   { 0, NULL },
254 };
255
256
257 /* The different objects in COPS-PR messages */
258 enum cops_s_num {
259   COPS_NO_PR_OBJECT,     /* Not a COPS-PR Object type               */
260   COPS_OBJ_PRID,         /* Provisioning Instance Identifier (PRID) */
261   COPS_OBJ_PPRID,        /* Prefix Provisioning Instance Identifier (PPRID) */
262   COPS_OBJ_EPD,          /* Encoded Provisioning Instance Data (EPD) */
263   COPS_OBJ_GPERR,        /* Global Provisioning Error Object (GPERR) */
264   COPS_OBJ_CPERR,        /* PRC Class Provisioning Error Object (CPERR) */
265   COPS_OBJ_ERRPRID,      /* Error Provisioning Instance Identifier (ErrorPRID)*/
266
267   COPS_LAST_S_NUM        /* For error checking                   */
268 };
269
270
271 static const value_string cops_s_num_vals[] = {
272   { COPS_OBJ_PRID,         "Provisioning Instance Identifier (PRID)" },
273   { COPS_OBJ_PPRID,        "Prefix Provisioning Instance Identifier (PPRID)" },
274   { COPS_OBJ_EPD,          "Encoded Provisioning Instance Data (EPD)" },
275   { COPS_OBJ_GPERR,        "Global Provisioning Error Object (GPERR)" },
276   { COPS_OBJ_CPERR,        "PRC Class Provisioning Error Object (CPERR)" },
277   { COPS_OBJ_ERRPRID,      "Error Provisioning Instance Identifier (ErrorPRID)" },
278   { 0, NULL },
279
280 };
281
282 /* R-Type is carried within the Context Object */
283 static const value_string cops_r_type_vals[] = {
284   { 0x01, "Incoming-Message/Admission Control request" },
285   { 0x02, "Resource-Allocation request" },
286   { 0x04, "Outgoing-Message request" },
287   { 0x08, "Configuration request" },
288   { 0, NULL },
289 };
290 /* S-Type is carried within the ClientSI Object for COPS-PR*/
291 static const value_string cops_s_type_vals[] = {
292   { 0x01, "BER" },
293   { 0, NULL },
294 };
295
296 /* Reason-Code is carried within the Reason object */
297 static const value_string cops_reason_vals[] = {
298   { 1,  "Unspecified" },
299   { 2,  "Management" },
300   { 3,  "Preempted (Another request state takes precedence)" },
301   { 4,  "Tear (Used to communicate a signaled state removal)" },
302   { 5,  "Timeout (Local state has timed-out)" },
303   { 6,  "Route Change (Change invalidates request state)" },
304   { 7,  "Insufficient Resources (No local resource available)" },
305   { 8,  "PDP's Directive (PDP decision caused the delete)" },
306   { 9,  "Unsupported decision (PDP decision not supported)" },
307   { 10, "Synchronize Handle Unknown" },
308   { 11, "Transient Handle (stateless event)" },
309   { 12, "Malformed Decision (could not recover)" },
310   { 13, "Unknown COPS Object from PDP" },
311   { 0, NULL },
312 };
313
314 /* Command-Code is carried within the Decision object if C-Type is 1 */
315 static const value_string cops_dec_cmd_code_vals[] = {
316   { 0, "NULL Decision (No configuration data available)" },
317   { 1, "Install (Admit request/Install configuration)" },
318   { 2, "Remove (Remove request/Remove configuration)" },
319   { 0, NULL },
320 };
321
322 /* Decision flags are also carried with the Decision object if C-Type is 1 */
323 static const value_string cops_dec_cmd_flag_vals[] = {
324   { 0x00, "<None set>" },
325   { 0x01, "Trigger Error (Trigger error message if set)" },
326   { 0, NULL },
327 };
328
329 /* Error-Code from Error object */
330 static const value_string cops_error_vals[] = {
331   {1,  "Bad handle" },
332   {2,  "Invalid handle reference" },
333   {3,  "Bad message format (Malformed Message)" },
334   {4,  "Unable to process (server gives up on query)" },
335   {5,  "Mandatory client-specific info missing" },
336   {6,  "Unsupported client" },
337   {7,  "Mandatory COPS object missing" },
338   {8,  "Client Failure" },
339   {9,  "Communication Failure" },
340   {10, "Unspecified" },
341   {11, "Shutting down" },
342   {12, "Redirect to Preferred Server" },
343   {13, "Unknown COPS Object" },
344   {14, "Authentication Failure" },
345   {15, "Authentication Required" },
346   {0,  NULL },
347 };
348 /* Error-Code from GPERR object */
349 static const value_string cops_gperror_vals[] = {
350   {1,  "AvailMemLow" },
351   {2,  "AvailMemExhausted" },
352   {3,  "unknownASN.1Tag" },
353   {4,  "maxMsgSizeExceeded" },
354   {5,  "unknownError" },
355   {6,  "maxRequestStatesOpen" },
356   {7,  "invalidASN.1Length" },
357   {8,  "invalidObjectPad" },
358   {9,  "unknownPIBData" },
359   {10, "unknownCOPSPRObject" },
360   {11, "malformedDecision" },
361   {0,  NULL },
362 };
363
364 /* Error-Code from CPERR object */
365 static const value_string cops_cperror_vals[] = {
366   {1,  "priSpaceExhausted" },
367   {2,  "priInstanceInvalid" },
368   {3,  "attrValueInvalid" },
369   {4,  "attrValueSupLimited" },
370   {5,  "attrEnumSupLimited" },
371   {6,  "attrMaxLengthExceeded" },
372   {7,  "attrReferenceUnknown" },
373   {8,  "priNotifyOnly" },
374   {9,  "unknownPrc" },
375   {10, "tooFewAttrs" },
376   {11, "invalidAttrType" },
377   {12, "deletedInRef" },
378   {13, "priSpecificError" },
379         {0,  NULL },
380 };
381
382
383 /* Report-Type from Report-Type object */
384 static const value_string cops_report_type_vals[] = {
385   {1, " Success   : Decision was successful at the PEP" },
386   {2, " Failure   : Decision could not be completed by PEP" },
387   {3, " Accounting: Accounting update for an installed state" },
388   {0, NULL },
389 };
390
391 /* The next tables are for PacketCable */
392
393 /* Transaction ID table */
394 static const value_string table_cops_transaction_id[] =
395 {
396   { 0x1,  "Gate Alloc" },
397   { 0x2,  "Gate Alloc Ack" },
398   { 0x3,  "Gate Alloc Err" },
399   { 0x4,  "Gate Set" },
400   { 0x5,  "Gate Set Ack" },
401   { 0x6,  "Gate Set Err" },
402   { 0x7,  "Gate Info" },
403   { 0x8,  "Gate Info Ack" },
404   { 0x9,  "Gate Info Err" },
405   { 0xa,  "Gate Delete" },
406   { 0xb,  "Gate Delete Ack" },
407   { 0xc,  "Gate Delete Err" },
408   { 0xd,  "Gate Open" },
409   { 0xe,  "Gate Close" },
410   { 0xFF, NULL },
411 };
412
413 /* Direction */
414 static const value_string table_cops_direction[] =
415 {
416   { 0x0,  "Downstream gate" },
417   { 0x1,  "Upstream gate" },
418   { 0xFF, NULL },
419 };
420
421 /* Session Class */
422 static const value_string table_cops_session_class[] =
423 {
424   { 0x0,  "Unspecified" },
425   { 0x1,  "Normal priority VoIP session" },
426   { 0x2,  "High priority VoIP session" },
427   { 0x3,  "Reserved" },
428   { 0xFF, NULL },
429 };
430
431 /* Reason Code */
432 static const value_string table_cops_reason_code[] =
433 {
434   { 0x0,  "Gate Delete Operation" },
435   { 0x1,  "Gate Close Operation" },
436   { 0xFF, NULL },
437 };
438
439 /* Reason Sub Code - Delete */
440 static const value_string table_cops_reason_subcode_delete[] =
441 {
442   { 0x0,  "Normal Operation" },
443   { 0x1,  "Local Gate-coordination not completed" },
444   { 0x2,  "Remote Gate-coordination not completed" },
445   { 0x3,  "Authorization revoked" },
446   { 0x4,  "Unexpected Gate-Open" },
447   { 0x5,  "Local Gate-Close failure" },
448   { 0x127,"Unspecified error" },
449   { 0xFF, NULL },
450 };
451
452 /* Reason Sub Code - Close */
453 static const value_string table_cops_reason_subcode_close[] =
454 {
455   { 0x0,  "Client initiated release (normal operation)" },
456   { 0x1,  "Reservation reassignment" },
457   { 0x2,  "Lack of reservation maintenance" },
458   { 0x3,  "Lack of Docsis Mac-layer responses" },
459   { 0x4,  "Timer T0 expiration; no Gate-Set received from CMS" },
460   { 0x5,  "Timer T1 expiration; no Commit received from MTA" },
461   { 0x6,  "Timer T7 expiration; Service Flow reservation timeout" },
462   { 0x7,  "Timer T8 expiration; Service Flow inactivity in the upstream direction" },
463   { 0x127,"Unspecified error" },
464   { 0xFF, NULL },
465 };
466
467 /* PacketCable Error */
468 static const value_string table_cops_packetcable_error[] =
469 {
470   { 0x1,  "No gates urrently available" },
471   { 0x2,  "Unknown Gate ID" },
472   { 0x3,  "Illegal Session Class value" },
473   { 0x4,  "Subscriber exceeded gate limit" },
474   { 0x5,  "Gate already set" },
475   { 0x6,  "Missing Required Object" },
476   { 0x7,  "Invalid Object" },
477   { 0x127,"Unspecified error" },
478   { 0xFF, NULL },
479 };
480
481 /* End of PacketCable Tables */
482
483
484 /* Initialize the protocol and registered fields */
485 static gint proto_cops = -1;
486 static gint hf_cops_ver_flags = -1;
487 static gint hf_cops_version = -1;
488 static gint hf_cops_flags = -1;
489
490 static gint hf_cops_op_code = -1;
491 static gint hf_cops_client_type = -1;
492 static gint hf_cops_msg_len = -1;
493
494 static gint hf_cops_obj_len = -1;
495 static gint hf_cops_obj_c_num = -1;
496 static gint hf_cops_obj_c_type = -1;
497
498 static gint hf_cops_obj_s_num = -1;
499 static gint hf_cops_obj_s_type = -1;
500
501 static gint hf_cops_r_type_flags = -1;
502 static gint hf_cops_m_type_flags = -1;
503
504 static gint hf_cops_in_int_ipv4 = -1;
505 static gint hf_cops_in_int_ipv6 = -1;
506 static gint hf_cops_out_int_ipv4 = -1;
507 static gint hf_cops_out_int_ipv6 = -1;
508 static gint hf_cops_int_ifindex = -1;
509
510 static gint hf_cops_reason = -1;
511 static gint hf_cops_reason_sub = -1;
512
513 static gint hf_cops_dec_cmd_code = -1;
514 static gint hf_cops_dec_flags = -1;
515
516 static gint hf_cops_error = -1;
517 static gint hf_cops_error_sub = -1;
518
519 static gint hf_cops_gperror = -1;
520 static gint hf_cops_gperror_sub = -1;
521
522 static gint hf_cops_cperror = -1;
523 static gint hf_cops_cperror_sub = -1;
524
525 static gint hf_cops_katimer = -1;
526
527 static gint hf_cops_pepid = -1;
528
529 static gint hf_cops_report_type = -1;
530
531 static gint hf_cops_pdprediraddr_ipv4 = -1;
532 static gint hf_cops_pdprediraddr_ipv6 = -1;
533 static gint hf_cops_lastpdpaddr_ipv4 = -1;
534 static gint hf_cops_lastpdpaddr_ipv6 = -1;
535 static gint hf_cops_pdp_tcp_port = -1;
536
537 static gint hf_cops_accttimer = -1;
538
539 static gint hf_cops_key_id = -1;
540 static gint hf_cops_seq_num = -1;
541
542 /* For PacketCable */
543 static gint hf_cops_subtree = -1;
544 static gint hf_cops_pc_activity_count = -1;
545 static gint hf_cops_pc_algorithm = -1;
546 static gint hf_cops_pc_close_subcode = -1;
547 static gint hf_cops_pc_cmts_ip = -1;
548 static gint hf_cops_pc_cmts_ip_port = -1;
549 static gint hf_cops_pc_prks_ip = -1;
550 static gint hf_cops_pc_prks_ip_port = -1;
551 static gint hf_cops_pc_srks_ip = -1;
552 static gint hf_cops_pc_srks_ip_port = -1;
553 static gint hf_cops_pc_delete_subcode = -1;
554 static gint hf_cops_pc_dest_ip = -1;
555 static gint hf_cops_pc_dest_port = -1;
556 static gint hf_cops_pc_direction = -1;
557 static gint hf_cops_pc_ds_field = -1;
558 static gint hf_cops_pc_gate_id = -1;
559 static gint hf_cops_pc_gate_spec_flags = -1;
560 static gint hf_cops_pc_gate_command_type = -1;
561 static gint hf_cops_pc_key = -1;
562 static gint hf_cops_pc_max_packet_size = -1;
563 static gint hf_cops_pc_min_policed_unit = -1;
564 static gint hf_cops_pc_packetcable_err_code = -1;
565 static gint hf_cops_pc_packetcable_sub_code = -1;
566 static gint hf_cops_pc_peak_data_rate = -1;
567 static gint hf_cops_pc_protocol_id = -1;
568 static gint hf_cops_pc_reason_code = -1;
569 static gint hf_cops_pc_remote_flags = -1;
570 static gint hf_cops_pc_remote_gate_id = -1;
571 static gint hf_cops_pc_reserved = -1;
572 static gint hf_cops_pc_session_class = -1;
573 static gint hf_cops_pc_slack_term = -1;
574 static gint hf_cops_pc_spec_rate = -1;
575 static gint hf_cops_pc_src_ip = -1;
576 static gint hf_cops_pc_src_port = -1;
577 static gint hf_cops_pc_subscriber_id = -1;
578 static gint hf_cops_pc_t1_value = -1;
579 static gint hf_cops_pc_t7_value = -1;
580 static gint hf_cops_pc_t8_value = -1;
581 static gint hf_cops_pc_token_bucket_rate = -1;
582 static gint hf_cops_pc_token_bucket_size = -1;
583 static gint hf_cops_pc_transaction_id = -1;
584 static gint hf_cops_pc_bcid_ts = -1;
585 static gint hf_cops_pc_bcid = -1;
586 static gint hf_cops_pc_bcid_ev = -1;
587 static gint hf_cops_pc_dfcdc_ip = -1;
588 static gint hf_cops_pc_dfccc_ip = -1;
589 static gint hf_cops_pc_dfcdc_ip_port = -1;
590 static gint hf_cops_pc_dfccc_ip_port = -1;
591
592 /* Initialize the subtree pointers */
593 static gint ett_cops = -1;
594 static gint ett_cops_ver_flags = -1;
595 static gint ett_cops_obj = -1;
596 static gint ett_cops_pr_obj = -1;
597 static gint ett_cops_obj_data = -1;
598 static gint ett_cops_r_type_flags = -1;
599 static gint ett_cops_itf = -1;
600 static gint ett_cops_reason = -1;
601 static gint ett_cops_decision = -1;
602 static gint ett_cops_error = -1;
603 static gint ett_cops_clientsi = -1;
604 static gint ett_cops_asn1 = -1;
605 static gint ett_cops_gperror = -1;
606 static gint ett_cops_cperror = -1;
607 static gint ett_cops_pdp = -1;
608
609 /* For PacketCable */
610 static gint ett_cops_subtree = -1;
611
612 void proto_reg_handoff_cops(void);
613
614 static guint get_cops_pdu_len(tvbuff_t *tvb, int offset);
615 static void dissect_cops_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
616
617 static int dissect_cops_object(tvbuff_t *tvb, guint32 offset, proto_tree *tree);
618 static void dissect_cops_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
619                                      guint8 c_num, guint8 c_type, guint16 len);
620
621 static void dissect_cops_pr_objects(tvbuff_t *tvb, guint32 offset, proto_tree *tree, guint16 pr_len);
622 static int dissect_cops_pr_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
623                                        guint8 s_num, guint8 s_type, guint16 len);
624
625 /* Added for PacketCable */
626 proto_tree *info_to_cops_subtree(tvbuff_t *, proto_tree *, int, int, char *);
627 void   info_to_display(tvbuff_t *, proto_item *, int, int, char *, const value_string *, int, gint *);
628 void   cops_transaction_id(tvbuff_t *, proto_tree *, guint, guint32);
629 void   cops_subscriber_id_v4(tvbuff_t *, proto_tree *, guint, guint32);
630 void   cops_gate_id(tvbuff_t *, proto_tree *, guint, guint32);
631 void   cops_activity_count(tvbuff_t *, proto_tree *, guint, guint32);
632 void   cops_gate_specs(tvbuff_t *, proto_tree *, guint, guint32);
633 void   cops_remote_gate_info(tvbuff_t *, proto_tree *, guint, guint32);
634 void   cops_packetcable_reason(tvbuff_t *, proto_tree *, guint, guint32);
635 void   cops_packetcable_error(tvbuff_t *, proto_tree *, guint, guint32);
636 void   cops_analyze_packetcable_obj(tvbuff_t *, proto_tree *, guint32);
637 void   cops_event_generation_info(tvbuff_t *, proto_tree *, guint, guint32);
638 void   cops_surveillance_parameters(tvbuff_t *, proto_tree *, guint, guint32);
639
640 static packet_info *cpinfo;
641 static guint8 opcode_idx;
642 static gboolean cops_packetcable = TRUE;
643 /* End of addition for PacketCable */
644
645
646 /* Code to actually dissect the packets */
647 static void
648 dissect_cops(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
649 {
650   tcp_dissect_pdus(tvb, pinfo, tree, cops_desegment, 8,
651                    get_cops_pdu_len, dissect_cops_pdu);
652 }
653
654 static guint
655 get_cops_pdu_len(tvbuff_t *tvb, int offset)
656 {
657   /*
658    * Get the length of the COPS message.
659    */
660   return tvb_get_ntohl(tvb, offset + 4);
661 }
662
663 static void
664 dissect_cops_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
665 {
666   guint8 op_code;
667   int object_len;
668
669   if (check_col(pinfo->cinfo, COL_PROTOCOL))
670     col_set_str(pinfo->cinfo, COL_PROTOCOL, "COPS");
671   if (check_col(pinfo->cinfo, COL_INFO))
672     col_clear(pinfo->cinfo, COL_INFO);
673
674   op_code = tvb_get_guint8(tvb, 1);
675   if (check_col(pinfo->cinfo, COL_INFO))
676     col_add_fstr(pinfo->cinfo, COL_INFO, "COPS %s",
677                  val_to_str(op_code, cops_op_code_vals, "Unknown Op Code"));
678
679   /* PacketCable: Remember the next two values to manipulate the info field in the Gui */
680   cpinfo = pinfo;
681   opcode_idx = op_code;
682
683   if (tree) {
684     proto_item *ti, *tv;
685     proto_tree *cops_tree, *ver_flags_tree;
686     guint32 msg_len;
687     guint32 offset = 0;
688     guint8 ver_flags;
689     gint garbage;
690
691     ti = proto_tree_add_item(tree, proto_cops, tvb, offset, -1, FALSE);
692     cops_tree = proto_item_add_subtree(ti, ett_cops);
693
694     /* Version and flags share the same byte, put them in a subtree */
695     ver_flags = tvb_get_guint8(tvb, offset);
696     tv = proto_tree_add_uint_format(cops_tree, hf_cops_ver_flags, tvb, offset, 1,
697                                       ver_flags, "Version: %u, Flags: %s",
698                                       hi_nibble(ver_flags),
699                                       val_to_str(lo_nibble(ver_flags), cops_flags_vals, "Unknown"));
700     ver_flags_tree = proto_item_add_subtree(tv, ett_cops_ver_flags);
701     proto_tree_add_uint(ver_flags_tree, hf_cops_version, tvb, offset, 1, ver_flags);
702     proto_tree_add_uint(ver_flags_tree, hf_cops_flags, tvb, offset, 1, ver_flags);
703     offset++;
704
705     proto_tree_add_item(cops_tree, hf_cops_op_code, tvb, offset, 1, FALSE);
706     offset ++;
707     proto_tree_add_item(cops_tree, hf_cops_client_type, tvb, offset, 2, FALSE);
708     offset += 2;
709
710     msg_len = tvb_get_ntohl(tvb, offset);
711     proto_tree_add_uint(cops_tree, hf_cops_msg_len, tvb, offset, 4, msg_len);
712     offset += 4;
713
714     while (tvb_reported_length_remaining(tvb, offset) >= COPS_OBJECT_HDR_SIZE) {
715       object_len = dissect_cops_object(tvb, offset, cops_tree);
716       if (object_len < 0)
717         return;
718       offset += object_len;
719     }
720
721     garbage = tvb_length_remaining(tvb, offset);
722     if (garbage > 0)
723       proto_tree_add_text(cops_tree, tvb, offset, garbage,
724                           "Trailing garbage: %d byte%s", garbage,
725                           plurality(garbage, "", "s"));
726   }
727 }
728
729 static char *cops_c_type_to_str(guint8 c_num, guint8 c_type)
730 {
731   switch (c_num) {
732   case COPS_OBJ_HANDLE:
733     if (c_type == 1)
734       return "Client Handle";
735     break;
736   case COPS_OBJ_IN_INT:
737   case COPS_OBJ_OUT_INT:
738     if (c_type == 1)
739       return "IPv4 Address + Interface";
740     else if (c_type == 2)
741       return "IPv6 Address + Interface";
742     break;
743   case COPS_OBJ_DECISION:
744   case COPS_OBJ_LPDPDECISION:
745     if (c_type == 1)
746       return "Decision Flags (Mandatory)";
747     else if (c_type == 2)
748       return "Stateless Data";
749     else if (c_type == 3)
750       return "Replacement Data";
751     else if (c_type == 4)
752       return "Client Specific Decision Data";
753     else if (c_type == 5)
754       return "Named Decision Data";
755     break;
756   case COPS_OBJ_CLIENTSI:
757     if (c_type == 1)
758       return "Signaled ClientSI";
759     else if (c_type == 2)
760       return "Named ClientSI";
761     break;
762   case COPS_OBJ_KATIMER:
763     if (c_type == 1)
764       return "Keep-alive timer value";
765     break;
766   case COPS_OBJ_PDPREDIRADDR:
767   case COPS_OBJ_LASTPDPADDR:
768     if (c_type == 1)
769       return "IPv4 Address + TCP Port";
770     else if (c_type == 2)
771       return "IPv6 Address + TCP Port";
772     break;
773   case COPS_OBJ_ACCTTIMER:
774     if (c_type == 1)
775       return "Accounting timer value";
776     break;
777   case COPS_OBJ_INTEGRITY:
778     if (c_type == 1)
779       return "HMAC digest";
780     break;
781   }
782
783   return "";
784 }
785
786 static int dissect_cops_object(tvbuff_t *tvb, guint32 offset, proto_tree *tree)
787 {
788   guint16 object_len, contents_len;
789   guint8 c_num, c_type;
790   proto_item *ti;
791   proto_tree *obj_tree;
792   char *type_str;
793
794   object_len = tvb_get_ntohs(tvb, offset);
795   if (object_len < COPS_OBJECT_HDR_SIZE) {
796     /* Bogus! */
797     proto_tree_add_text(tree, tvb, offset, 2,
798                         "Bad COPS object length: %u, should be at least %u",
799                         object_len, COPS_OBJECT_HDR_SIZE);
800     return -1;
801   }
802   c_num = tvb_get_guint8(tvb, offset + 2);
803   c_type = tvb_get_guint8(tvb, offset + 3);
804
805   ti = proto_tree_add_uint_format(tree, hf_cops_obj_c_num, tvb, offset, object_len, c_num,
806                                   "%s: %s", val_to_str(c_num, cops_c_num_vals, "Unknown"),
807                                   cops_c_type_to_str(c_num, c_type));
808   obj_tree = proto_item_add_subtree(ti, ett_cops_obj);
809
810   proto_tree_add_uint(obj_tree, hf_cops_obj_len, tvb, offset, 2, object_len);
811   offset += 2;
812
813   proto_tree_add_uint(obj_tree, hf_cops_obj_c_num, tvb, offset, 1, c_num);
814   offset++;
815
816   type_str = cops_c_type_to_str(c_num, c_type);
817   proto_tree_add_text(obj_tree, tvb, offset, 1, "C-Type: %s%s%u%s",
818                       type_str,
819                       strlen(type_str) ? " (" : "",
820                       c_type,
821                       strlen(type_str) ? ")" : "");
822   offset++;
823
824   contents_len = object_len - COPS_OBJECT_HDR_SIZE;
825   dissect_cops_object_data(tvb, offset, obj_tree, c_num, c_type, contents_len);
826
827   /* Pad to 32bit boundary */
828   if (object_len % sizeof (guint32))
829     object_len += (sizeof (guint32) - object_len % sizeof (guint32));
830
831   return object_len;
832 }
833
834 static void dissect_cops_pr_objects(tvbuff_t *tvb, guint32 offset, proto_tree *tree, guint16 pr_len)
835 {
836   guint16 object_len, contents_len;
837   guint8 s_num, s_type;
838   char *type_str;
839   int ret;
840   proto_tree *cops_pr_tree, *obj_tree;
841   proto_item *ti;
842
843   cops_pr_tree = proto_item_add_subtree(tree, ett_cops_pr_obj);
844
845   while (pr_len >= COPS_OBJECT_HDR_SIZE) {
846     object_len = tvb_get_ntohs(tvb, offset);
847     if (object_len < COPS_OBJECT_HDR_SIZE) {
848       /* Bogus! */
849       proto_tree_add_text(tree, tvb, offset, 2,
850                           "Bad COPS PR object length: %u, should be at least %u",
851                           object_len, COPS_OBJECT_HDR_SIZE);
852       return;
853     }
854     s_num = tvb_get_guint8(tvb, offset + 2);
855
856     ti = proto_tree_add_uint_format(cops_pr_tree, hf_cops_obj_s_num, tvb, offset, object_len, s_num,
857                                     "%s", val_to_str(s_num, cops_s_num_vals, "Unknown"));
858     obj_tree = proto_item_add_subtree(cops_pr_tree, ett_cops_pr_obj);
859
860     proto_tree_add_uint(obj_tree, hf_cops_obj_len, tvb, offset, 2, object_len);
861     offset += 2;
862     pr_len -= 2;
863
864     proto_tree_add_uint(obj_tree, hf_cops_obj_s_num, tvb, offset, 1, s_num);
865     offset++;
866     pr_len--;
867
868     s_type = tvb_get_guint8(tvb, offset);
869     type_str = val_to_str(s_type, cops_s_type_vals, "Unknown");
870     proto_tree_add_text(obj_tree, tvb, offset, 1, "S-Type: %s%s%u%s",
871                         type_str,
872                         strlen(type_str) ? " (" : "",
873                         s_type,
874                         strlen(type_str) ? ")" : "");
875     offset++;
876     pr_len--;
877
878     contents_len = object_len - COPS_OBJECT_HDR_SIZE;
879     ret = dissect_cops_pr_object_data(tvb, offset, obj_tree, s_num, s_type, contents_len);
880     if (ret < 0)
881       break;
882
883     /*Pad to 32bit boundary */
884     if (object_len % sizeof (guint32))
885       object_len += (sizeof (guint32) - object_len % sizeof (guint32));
886
887     pr_len -= object_len - COPS_OBJECT_HDR_SIZE;
888     offset += object_len - COPS_OBJECT_HDR_SIZE;
889   }
890 }
891
892 static void dissect_cops_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
893                                      guint8 c_num, guint8 c_type, guint16 len)
894 {
895   proto_item *ti;
896   proto_tree *r_type_tree, *itf_tree, *reason_tree, *dec_tree, *error_tree, *clientsi_tree, *pdp_tree;
897   guint16 r_type, m_type, reason, reason_sub, cmd_code, cmd_flags, error, error_sub, tcp_port;
898   guint32 ipv4addr, ifindex;
899   struct e_in6_addr ipv6addr;
900
901   switch (c_num) {
902   case COPS_OBJ_CONTEXT:
903     r_type = tvb_get_ntohs(tvb, offset);
904     m_type = tvb_get_ntohs(tvb, offset + 2);
905     ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: R-Type: %s, M-Type: %u",
906                              val_to_str(r_type, cops_r_type_vals, "Unknown"),
907                              m_type);
908
909     r_type_tree = proto_item_add_subtree(ti, ett_cops_r_type_flags);
910     proto_tree_add_uint(r_type_tree, hf_cops_r_type_flags, tvb, offset, 2, r_type);
911     offset += 2;
912     proto_tree_add_uint(r_type_tree, hf_cops_m_type_flags, tvb, offset, 2, m_type);
913
914     break;
915   case COPS_OBJ_IN_INT:
916   case COPS_OBJ_OUT_INT:
917     if (c_type == 1) {          /* IPv4 */
918       tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset, 4);
919       ifindex = tvb_get_ntohl(tvb, offset + 4);
920       ti = proto_tree_add_text(tree, tvb, offset, 8, "Contents: IPv4 address %s, ifIndex: %u",
921                                ip_to_str((guint8 *)&ipv4addr), ifindex);
922       itf_tree = proto_item_add_subtree(ti, ett_cops_itf);
923       proto_tree_add_ipv4(itf_tree,
924                           (c_num == COPS_OBJ_IN_INT) ? hf_cops_in_int_ipv4 : hf_cops_out_int_ipv4,
925                           tvb, offset, 4, ipv4addr);
926       offset += 4;
927     } else if (c_type == 2) {   /* IPv6 */
928       tvb_memcpy(tvb, (guint8 *)&ipv6addr, offset, sizeof ipv6addr);
929       ifindex = tvb_get_ntohl(tvb, offset + sizeof ipv6addr);
930       ti = proto_tree_add_text(tree, tvb, offset, 20, "Contents: IPv6 address %s, ifIndex: %u",
931                                ip6_to_str(&ipv6addr), ifindex);
932       itf_tree = proto_item_add_subtree(ti, ett_cops_itf);
933       proto_tree_add_ipv6(itf_tree,
934                           (c_num == COPS_OBJ_IN_INT) ? hf_cops_in_int_ipv6 : hf_cops_out_int_ipv6,
935                           tvb, offset, 16, (guint8 *)&ipv6addr);
936       offset += 16;
937     } else {
938       break;
939     }
940     proto_tree_add_uint(itf_tree, hf_cops_int_ifindex, tvb, offset, 4, ifindex);
941
942     break;
943   case COPS_OBJ_REASON:
944     reason = tvb_get_ntohs(tvb, offset);
945     reason_sub = tvb_get_ntohs(tvb, offset + 2);
946     ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Reason-Code: %s, Reason Sub-code: 0x%04x",
947                              val_to_str(reason, cops_reason_vals, "<Unknown value>"), reason_sub);
948     reason_tree = proto_item_add_subtree(ti, ett_cops_reason);
949     proto_tree_add_uint(reason_tree, hf_cops_reason, tvb, offset, 2, reason);
950     offset += 2;
951     if (reason == 13) {
952       proto_tree_add_text(reason_tree, tvb, offset, 2, "Reason Sub-code: "
953                           "Unknown object's C-Num %u, C-Type %u",
954                           tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
955     } else
956       proto_tree_add_uint(reason_tree, hf_cops_reason_sub, tvb, offset, 2, reason_sub);
957
958     break;
959   case COPS_OBJ_DECISION:
960   case COPS_OBJ_LPDPDECISION:
961     if (c_type == 1) {
962       cmd_code = tvb_get_ntohs(tvb, offset);
963       cmd_flags = tvb_get_ntohs(tvb, offset + 2);
964       ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Command-Code: %s, Flags: %s",
965                                val_to_str(cmd_code, cops_dec_cmd_code_vals, "<Unknown value>"),
966                                val_to_str(cmd_flags, cops_dec_cmd_flag_vals, "<Unknown flag>"));
967       dec_tree = proto_item_add_subtree(ti, ett_cops_decision);
968       proto_tree_add_uint(dec_tree, hf_cops_dec_cmd_code, tvb, offset, 2, cmd_code);
969       offset += 2;
970       proto_tree_add_uint(dec_tree, hf_cops_dec_flags, tvb, offset, 2, cmd_flags);
971     } else if (c_type == 5) { /*COPS-PR Data*/
972       ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: %u bytes", len);
973       dec_tree = proto_item_add_subtree(ti, ett_cops_decision);
974       dissect_cops_pr_objects(tvb, offset, dec_tree, len);
975     }
976
977     /* PacketCable : Analyze the remaining data if available */
978     cops_analyze_packetcable_obj(tvb, tree, offset);
979
980     break;
981   case COPS_OBJ_ERROR:
982     if (c_type != 1)
983       break;
984
985     error = tvb_get_ntohs(tvb, offset);
986     error_sub = tvb_get_ntohs(tvb, offset + 2);
987     ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
988                              val_to_str(error, cops_error_vals, "<Unknown value>"), error_sub);
989     error_tree = proto_item_add_subtree(ti, ett_cops_error);
990     proto_tree_add_uint(error_tree, hf_cops_error, tvb, offset, 2, error);
991     offset += 2;
992     if (error == 13) {
993       proto_tree_add_text(error_tree, tvb, offset, 2, "Error Sub-code: "
994                           "Unknown object's C-Num %u, C-Type %u",
995                           tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
996     } else
997       proto_tree_add_uint(error_tree, hf_cops_error_sub, tvb, offset, 2, error_sub);
998
999     break;
1000   case COPS_OBJ_CLIENTSI:
1001
1002     /* For PacketCable */
1003     if (c_type == 1) {
1004        cops_analyze_packetcable_obj(tvb, tree, offset);
1005        break;
1006     }
1007
1008     if (c_type != 2) /*Not COPS-PR data*/
1009       break;
1010
1011     ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: %u bytes", len);
1012     clientsi_tree = proto_item_add_subtree(ti, ett_cops_clientsi);
1013
1014     dissect_cops_pr_objects(tvb, offset, clientsi_tree, len);
1015
1016     break;
1017   case COPS_OBJ_KATIMER:
1018     if (c_type != 1)
1019       break;
1020
1021     proto_tree_add_item(tree, hf_cops_katimer, tvb, offset + 2, 2, FALSE);
1022     if (tvb_get_ntohs(tvb, offset + 2) == 0)
1023       proto_tree_add_text(tree, tvb, offset, 0, "Value of zero implies infinity.");
1024
1025     break;
1026   case COPS_OBJ_PEPID:
1027     if (c_type != 1)
1028       break;
1029
1030     if (tvb_strnlen(tvb, offset, len) == -1)
1031       proto_tree_add_text(tree, tvb, offset, len, "<PEP Id is not a NUL terminated ASCII string>");
1032     else
1033       proto_tree_add_item(tree, hf_cops_pepid, tvb, offset,
1034                           tvb_strnlen(tvb, offset, len) + 1, FALSE);
1035
1036     break;
1037   case COPS_OBJ_REPORT_TYPE:
1038     if (c_type != 1)
1039       break;
1040
1041     proto_tree_add_item(tree, hf_cops_report_type, tvb, offset, 2, FALSE);
1042
1043     break;
1044   case COPS_OBJ_PDPREDIRADDR:
1045   case COPS_OBJ_LASTPDPADDR:
1046     if (c_type == 1) {          /* IPv4 */
1047       tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset, 4);
1048       tcp_port = tvb_get_ntohs(tvb, offset + 4 + 2);
1049       ti = proto_tree_add_text(tree, tvb, offset, 8, "Contents: IPv4 address %s, TCP Port Number: %u",
1050                                ip_to_str((guint8 *)&ipv4addr), tcp_port);
1051       pdp_tree = proto_item_add_subtree(ti, ett_cops_pdp);
1052       proto_tree_add_ipv4(pdp_tree,
1053                           (c_num == COPS_OBJ_PDPREDIRADDR) ? hf_cops_pdprediraddr_ipv4 : hf_cops_lastpdpaddr_ipv4,
1054                           tvb, offset, 4, ipv4addr);
1055       offset += 4;
1056     } else if (c_type == 2) {   /* IPv6 */
1057       tvb_memcpy(tvb, (guint8 *)&ipv6addr, offset, sizeof ipv6addr);
1058       tcp_port = tvb_get_ntohs(tvb, offset + sizeof ipv6addr + 2);
1059       ti = proto_tree_add_text(tree, tvb, offset, 20, "Contents: IPv6 address %s, TCP Port Number: %u",
1060                                ip6_to_str(&ipv6addr), tcp_port);
1061       pdp_tree = proto_item_add_subtree(ti, ett_cops_pdp);
1062       proto_tree_add_ipv6(pdp_tree,
1063                           (c_num == COPS_OBJ_PDPREDIRADDR) ? hf_cops_pdprediraddr_ipv6 : hf_cops_lastpdpaddr_ipv6,
1064                           tvb, offset, 16, (guint8 *)&ipv6addr);
1065       offset += 16;
1066     } else {
1067       break;
1068     }
1069     offset += 2;
1070     proto_tree_add_uint(pdp_tree, hf_cops_pdp_tcp_port, tvb, offset, 2, tcp_port);
1071
1072     break;
1073   case COPS_OBJ_ACCTTIMER:
1074     if (c_type != 1)
1075       break;
1076
1077     proto_tree_add_item(tree, hf_cops_accttimer, tvb, offset + 2, 2, FALSE);
1078     if (tvb_get_ntohs(tvb, offset + 2) == 0)
1079       proto_tree_add_text(tree, tvb, offset, 0, "Value of zero means "
1080                           "there SHOULD be no unsolicited accounting updates.");
1081
1082     break;
1083   case COPS_OBJ_INTEGRITY:
1084     if (c_type != 1)
1085       break;      /* Not HMAC digest */
1086
1087     proto_tree_add_item(tree, hf_cops_key_id, tvb, offset, 4, FALSE);
1088     proto_tree_add_item(tree, hf_cops_seq_num, tvb, offset + 4, 4, FALSE);
1089     proto_tree_add_text(tree, tvb, offset + 8 , len - 8, "Contents: Keyed Message Digest");
1090
1091     break;
1092   default:
1093     proto_tree_add_text(tree, tvb, offset, len, "Contents: %u bytes", len);
1094
1095     break;
1096   }
1097 }
1098
1099 #ifdef HAVE_NET_SNMP
1100 static guchar*format_asn_value (struct variable_list *variable, subid_t *variable_oid,
1101                                 guint variable_oid_length, u_char type_from_packet)
1102 {
1103   struct tree *subtree=tree_head;
1104
1105   guchar *buf=NULL;
1106   size_t buf_len=0;
1107   size_t out_len=0;
1108
1109   /*Get the ASN.1 type etc. from the PIB-MIB. If unsuccessful use the type from packet*/
1110   subtree = get_tree(variable_oid,variable_oid_length, subtree);
1111
1112   if (subtree->type == 0)
1113     variable->type= type_from_packet;
1114
1115   buf_len = SPRINT_MAX_LEN; /*defined in NET-SNMP's snmp-impl.h*/
1116   buf = g_malloc(buf_len);
1117   *buf = '\0';
1118   out_len = 0;
1119
1120   /*If the ASN.1 type was found from PIB-MIB, use it for decoding*/
1121   if (!variable->type)
1122     variable->type=mib_to_asn_type(subtree->type);
1123
1124   if (!sprint_realloc_by_type(&buf, &buf_len, &out_len, TRUE, variable, subtree->enums, subtree->hint, NULL))
1125     sprintf(buf,"%s","sprint_realloc_by_type failed");
1126
1127   return buf;
1128 }
1129 #endif  /* HAVE_NET_SNMP */
1130
1131 static int decode_cops_pr_asn1_data(tvbuff_t *tvb, guint32 offset,
1132     proto_tree *tree, guint asnlen, guint8 cops_pr_obj
1133 #ifndef HAVE_NET_SNMP
1134                                                   _U_
1135 #endif
1136     )
1137 {
1138   ASN1_SCK asn1;
1139   int start;
1140   gboolean def;
1141   guint length;
1142
1143   guint vb_length;
1144   gushort vb_type;
1145   gchar *vb_type_name;
1146
1147   int ret;
1148   guint cls, con, tag;
1149   subid_t epd_attribute_index=0;
1150
1151   gint32 vb_integer_value;
1152   guint32 vb_uinteger_value;
1153
1154   guint8 *vb_octet_string;
1155
1156   subid_t *vb_oid;
1157   guint vb_oid_length;
1158
1159   gchar *vb_display_string;
1160   gchar *vb_display_string2;
1161
1162 #ifdef HAVE_NET_SNMP
1163   struct variable_list variable;
1164   long value;
1165 #endif  /* HAVE_NET_SNMP */
1166
1167   unsigned int i;
1168   gchar *buf;
1169   int len;
1170
1171   while (asnlen > 0) { /*while there is ASN stuff to be decoded*/
1172
1173     epd_attribute_index++;
1174 #ifdef HAVE_NET_SNMP
1175     last_decoded_prid_oid[last_decoded_prid_oid_length-1]=epd_attribute_index;
1176 #endif  /* HAVE_NET_SNMP */
1177     asn1_open(&asn1, tvb, offset);
1178
1179     /* parse the type of the object */
1180
1181     start = asn1.offset;
1182
1183     ret = asn1_header_decode (&asn1, &cls, &con, &tag, &def, &vb_length);
1184     if (ret != ASN1_ERR_NOERROR)
1185       return 0;
1186     if (!def)
1187       return ASN1_ERR_LENGTH_NOT_DEFINITE;
1188
1189     /* Convert the class, constructed flag, and tag to a type. */
1190     vb_type_name = cops_tag_cls2syntax(tag, cls, &vb_type);
1191     if (vb_type_name == NULL) {
1192       /*
1193        * Unsupported type.
1194        * Dissect the value as an opaque string of octets.
1195        */
1196       vb_type_name = "unsupported type";
1197       vb_type = COPS_OPAQUE;
1198     }
1199
1200     /* parse the value */
1201
1202     switch (vb_type) {
1203
1204     case COPS_INTEGER:
1205       ret = asn1_int32_value_decode(&asn1, vb_length, &vb_integer_value);
1206       if (ret != ASN1_ERR_NOERROR)
1207         return ret;
1208       length = asn1.offset - start;
1209       if (tree) {
1210 #ifdef HAVE_NET_SNMP
1211         if (cops_typefrommib == TRUE)
1212         {
1213           variable.type = 0;
1214           value = vb_integer_value;
1215           variable.val.integer = &value;
1216           variable.val_len = vb_length ;
1217           vb_display_string=format_asn_value(&variable,
1218                                              last_decoded_prid_oid,last_decoded_prid_oid_length,ASN_INTEGER);
1219
1220           proto_tree_add_text(tree, asn1.tvb, offset, length,
1221                               "Value: %s", vb_display_string);
1222           g_free(vb_display_string);
1223         }
1224         else
1225 #endif /* HAVE_NET_SNMP */
1226           proto_tree_add_text(tree, asn1.tvb, offset, length,
1227                               "Value: %s: %d (%#x)", vb_type_name,
1228                               vb_integer_value, vb_integer_value);
1229       }
1230       break;
1231
1232     case COPS_UNSIGNED32:
1233     case COPS_TIMETICKS:
1234       ret = asn1_uint32_value_decode(&asn1, vb_length, &vb_uinteger_value);
1235       if (ret != ASN1_ERR_NOERROR)
1236         return ret;
1237       length = asn1.offset - start;
1238       if (tree) {
1239 #ifdef HAVE_NET_SNMP
1240         if (cops_typefrommib == TRUE)
1241         {
1242           variable.type = 0;
1243           value = vb_uinteger_value;
1244           variable.val.integer = &value;
1245           variable.val_len = vb_length;
1246
1247           vb_display_string=format_asn_value(&variable,
1248                                              last_decoded_prid_oid,last_decoded_prid_oid_length,ASN_UINTEGER);
1249
1250           proto_tree_add_text(tree, asn1.tvb, offset, length, "Value %s: %s",vb_type_name, vb_display_string);
1251
1252           g_free(vb_display_string);
1253         }
1254         else
1255 #endif /* HAVE_NET_SNMP */
1256           proto_tree_add_text(tree, asn1.tvb, offset, length,
1257                               "Value: %s: %u (%#x)", vb_type_name,
1258                               vb_uinteger_value, vb_uinteger_value);
1259       }
1260       break;
1261
1262     case COPS_OCTETSTR:
1263     case COPS_IPADDR:
1264     case COPS_OPAQUE:
1265     case COPS_UNSIGNED64:
1266     case COPS_INTEGER64:
1267       ret = asn1_string_value_decode (&asn1, vb_length, &vb_octet_string);
1268       if (ret != ASN1_ERR_NOERROR)
1269         return ret;
1270       length = asn1.offset - start;
1271       if (tree) {
1272 #ifdef HAVE_NET_SNMP
1273         if (cops_typefrommib == TRUE)
1274         {
1275           variable.type = 0;
1276           variable.val.string = vb_octet_string;
1277           variable.val_len = vb_length;
1278           vb_display_string = format_asn_value(&variable,
1279                                                last_decoded_prid_oid,last_decoded_prid_oid_length,ASN_OCTET_STR);
1280           proto_tree_add_text(tree, asn1.tvb, offset, length,
1281                               "Value: %s (ASN.1 type from packet: %s)", vb_display_string, vb_type_name);
1282
1283           g_free(vb_display_string);
1284         }
1285         else
1286         {
1287 #endif /* HAVE_NET_SNMP */
1288           for (i = 0; i < vb_length; i++) {
1289             if (!(isprint(vb_octet_string[i]) ||isspace(vb_octet_string[i])))
1290               break;
1291           }
1292
1293           /*
1294            * If some characters are not printable, display the string as bytes.
1295            */
1296           if (i < vb_length) {
1297             /*
1298              * We stopped, due to a non-printable character, before we got
1299              * to the end of the string.
1300              */
1301             vb_display_string = g_malloc(4*vb_length);
1302             buf = &vb_display_string[0];
1303             len = sprintf(buf, "%03u", vb_octet_string[0]);
1304             buf += len;
1305             for (i = 1; i < vb_length; i++) {
1306               len = sprintf(buf, ".%03u", vb_octet_string[i]);
1307               buf += len;
1308             }
1309             proto_tree_add_text(tree, asn1.tvb, offset, length,
1310                                 "Value: %s: %s", vb_type_name, vb_display_string);
1311             g_free(vb_display_string);
1312           } else {
1313             proto_tree_add_text(tree, asn1.tvb, offset, length,
1314                                 "Value: %s: %.*s", vb_type_name, (int)vb_length,
1315                                 SAFE_STRING(vb_octet_string));
1316           }
1317 #ifdef HAVE_NET_SNMP
1318         }
1319 #endif /* HAVE_NET_SNMP */
1320       }
1321       g_free(vb_octet_string);
1322       break;
1323
1324     case COPS_NULL:
1325       ret = asn1_null_decode (&asn1, vb_length);
1326       if (ret != ASN1_ERR_NOERROR)
1327         return ret;
1328       length = asn1.offset - start;
1329       if (tree)
1330         proto_tree_add_text(tree, asn1.tvb, offset, length, "Value: %s", vb_type_name);
1331       break;
1332
1333     case COPS_OBJECTID:
1334       ret = asn1_oid_value_decode (&asn1, vb_length, &vb_oid, &vb_oid_length);
1335       if (ret != ASN1_ERR_NOERROR)
1336         return ret;
1337       length = asn1.offset - start;
1338
1339       if (tree) {
1340         if (cops_pr_obj == COPS_OBJ_PPRID){
1341           /*we're decoding Prefix PRID, that doesn't have a instance Id,
1342            *Use full length of the OID when decoding it.
1343            */
1344           new_format_oid(vb_oid,vb_oid_length,&vb_display_string,&vb_display_string2);
1345
1346           if (!vb_display_string2)   /*if OID couldn't be decoded, print only numeric format*/
1347             proto_tree_add_text(tree, asn1.tvb, offset, length,
1348                                 "Value: %s: %s", vb_type_name, vb_display_string);
1349           else
1350             proto_tree_add_text(tree, asn1.tvb, offset, length,
1351                                 "Value: %s: %s (%s)", vb_type_name,
1352                                 vb_display_string,
1353                                 vb_display_string2);
1354         }
1355         else { /*we're decoding PRID, Error PRID or EPD*/
1356           /*strip the instance Id from the OIDs before decoding and paste it back during printing*/
1357           new_format_oid(vb_oid,vb_oid_length-1,&vb_display_string,&vb_display_string2);
1358
1359           if (!vb_display_string2)  /*if OID couldn't be decoded, print only numeric format*/
1360             proto_tree_add_text(tree, asn1.tvb, offset, length,
1361                                 "Value: %s: %s.%lu", vb_type_name,
1362                                 vb_display_string,
1363                                 (unsigned long)vb_oid[vb_oid_length-1]);
1364           else
1365             proto_tree_add_text(tree, asn1.tvb, offset, length,
1366                                 "Value: %s: %s.%lu (%s.%lu)", vb_type_name,
1367                                 vb_display_string,
1368                                 (unsigned long)vb_oid[vb_oid_length-1],
1369                                 vb_display_string2,
1370                                 (unsigned long)vb_oid[vb_oid_length-1]);
1371         }
1372 #ifdef HAVE_NET_SNMP
1373         if (cops_pr_obj != COPS_OBJ_EPD) {
1374           /* we're not decoding EPD, so let's store the OID of the PRID so that later
1375              when we're decoding this PRID's EPD we can finetune the output.*/
1376           memcpy(last_decoded_prid_oid,vb_oid,vb_oid_length*sizeof(subid_t));
1377           last_decoded_prid_oid_length=vb_oid_length;
1378         }
1379 #endif /* HAVE_NET_SNMP */
1380
1381       g_free(vb_display_string);
1382       if(vb_display_string2)
1383         g_free(vb_display_string2);
1384       }
1385       g_free(vb_oid);
1386       break;
1387
1388     default:
1389       g_assert_not_reached();
1390       return ASN1_ERR_WRONG_TYPE;
1391     }
1392
1393     asn1_close(&asn1,&offset);
1394
1395     asnlen -= length;
1396   }
1397   epd_attribute_index=0;
1398   return 0;
1399 }
1400
1401 static int dissect_cops_pr_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
1402                                        guint8 s_num, guint8 s_type, guint16 len)
1403 {
1404   proto_item *ti;
1405   proto_tree *asn1_object_tree, *gperror_tree, *cperror_tree;
1406   guint16 gperror=0, gperror_sub=0, cperror=0, cperror_sub=0;
1407
1408   switch (s_num){
1409   case COPS_OBJ_PRID:
1410    if (s_type != 1) /* Not Provisioning Instance Identifier (PRID) */
1411       break;
1412
1413     ti=proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1414     asn1_object_tree = proto_item_add_subtree(ti, ett_cops_asn1);
1415
1416     decode_cops_pr_asn1_data(tvb, offset, asn1_object_tree, len, COPS_OBJ_PRID);
1417
1418     break;
1419   case COPS_OBJ_PPRID:
1420     if (s_type != 1) /* Not Prefix Provisioning Instance Identifier (PPRID) */
1421       break;
1422
1423     ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1424     asn1_object_tree = proto_item_add_subtree(ti, ett_cops_asn1);
1425
1426     decode_cops_pr_asn1_data(tvb, offset, asn1_object_tree, len, COPS_OBJ_PPRID);
1427
1428     break;
1429   case COPS_OBJ_EPD:
1430     if (s_type != 1) /* Not  Encoded Provisioning Instance Data (EPD) */
1431       break;
1432
1433     ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1434     asn1_object_tree = proto_item_add_subtree(ti, ett_cops_asn1);
1435
1436     decode_cops_pr_asn1_data(tvb, offset, asn1_object_tree, len, COPS_OBJ_EPD);
1437
1438     break;
1439   case COPS_OBJ_GPERR:
1440     if (s_type != 1) /* Not Global Provisioning Error Object (GPERR) */
1441       break;
1442
1443     gperror = tvb_get_ntohs(tvb, offset);
1444     gperror_sub = tvb_get_ntohs(tvb, offset + 2);
1445     ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
1446                        val_to_str(gperror, cops_gperror_vals, "<Unknown value>"), gperror_sub);
1447     gperror_tree = proto_item_add_subtree(ti, ett_cops_gperror);
1448     proto_tree_add_uint(gperror_tree, hf_cops_gperror, tvb, offset, 2, gperror);
1449     offset += 2;
1450     if (cperror == 13) {
1451       proto_tree_add_text(gperror_tree, tvb, offset, 2, "Error Sub-code: "
1452                           "Unknown object's C-Num %u, C-Type %u",
1453                           tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
1454     } else
1455       proto_tree_add_uint(gperror_tree, hf_cops_gperror_sub, tvb, offset, 2, gperror_sub);
1456
1457     break;
1458   case COPS_OBJ_CPERR:
1459     if (s_type != 1) /*Not PRC Class Provisioning Error Object (CPERR) */
1460       break;
1461
1462     break;
1463
1464     cperror = tvb_get_ntohs(tvb, offset);
1465     cperror_sub = tvb_get_ntohs(tvb, offset + 2);
1466     ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
1467                        val_to_str(cperror, cops_cperror_vals, "<Unknown value>"), cperror_sub);
1468     cperror_tree = proto_item_add_subtree(ti, ett_cops_cperror);
1469     proto_tree_add_uint(cperror_tree, hf_cops_cperror, tvb, offset, 2, cperror);
1470     offset += 2;
1471     if (cperror == 13) {
1472       proto_tree_add_text(cperror_tree, tvb, offset, 2, "Error Sub-code: "
1473                           "Unknown object's S-Num %u, C-Type %u",
1474                           tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
1475     } else
1476       proto_tree_add_uint(cperror_tree, hf_cops_cperror_sub, tvb, offset, 2, cperror_sub);
1477
1478     break;
1479   case COPS_OBJ_ERRPRID:
1480     if (s_type != 1) /*Not  Error Provisioning Instance Identifier (ErrorPRID)*/
1481       break;
1482
1483     ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1484     asn1_object_tree = proto_item_add_subtree(ti, ett_cops_asn1);
1485
1486     decode_cops_pr_asn1_data(tvb, offset, asn1_object_tree, len, COPS_OBJ_ERRPRID);
1487
1488     break;
1489   default:
1490     proto_tree_add_text(tree, tvb, offset, len, "Contents: %u bytes", len);
1491     break;
1492   }
1493
1494   return 0;
1495 }
1496
1497
1498 /* Register the protocol with Ethereal */
1499 void proto_register_cops(void)
1500 {
1501   /* Setup list of header fields */
1502   static hf_register_info hf[] = {
1503     { &hf_cops_ver_flags,
1504       { "Version and Flags",           "cops.ver_flags",
1505       FT_UINT8, BASE_HEX, NULL, 0x0,
1506       "Version and Flags in COPS Common Header", HFILL }
1507     },
1508     { &hf_cops_version,
1509       { "Version",           "cops.version",
1510       FT_UINT8, BASE_DEC, NULL, 0xF0,
1511       "Version in COPS Common Header", HFILL }
1512     },
1513     { &hf_cops_flags,
1514       { "Flags",           "cops.flags",
1515       FT_UINT8, BASE_HEX, VALS(cops_flags_vals), 0x0F,
1516       "Flags in COPS Common Header", HFILL }
1517     },
1518     { &hf_cops_op_code,
1519       { "Op Code",           "cops.op_code",
1520       FT_UINT8, BASE_DEC, VALS(cops_op_code_vals), 0x0,
1521       "Op Code in COPS Common Header", HFILL }
1522     },
1523     { &hf_cops_client_type,
1524       { "Client Type",           "cops.client_type",
1525       FT_UINT16, BASE_DEC, NULL, 0x0,
1526       "Client Type in COPS Common Header", HFILL }
1527     },
1528     { &hf_cops_msg_len,
1529       { "Message Length",           "cops.msg_len",
1530       FT_UINT32, BASE_DEC, NULL, 0x0,
1531       "Message Length in COPS Common Header", HFILL }
1532     },
1533     { &hf_cops_obj_len,
1534       { "Object Length",           "cops.obj.len",
1535       FT_UINT32, BASE_DEC, NULL, 0x0,
1536       "Object Length in COPS Object Header", HFILL }
1537     },
1538     { &hf_cops_obj_c_num,
1539       { "C-Num",           "cops.c_num",
1540       FT_UINT8, BASE_DEC, VALS(cops_c_num_vals), 0x0,
1541       "C-Num in COPS Object Header", HFILL }
1542     },
1543     { &hf_cops_obj_c_type,
1544       { "C-Type",           "cops.c_type",
1545       FT_UINT8, BASE_DEC, NULL, 0x0,
1546       "C-Type in COPS Object Header", HFILL }
1547     },
1548
1549     { &hf_cops_obj_s_num,
1550       { "S-Num",           "cops.s_num",
1551       FT_UINT8, BASE_DEC, VALS(cops_s_num_vals), 0x0,
1552       "S-Num in COPS-PR Object Header", HFILL }
1553     },
1554     { &hf_cops_obj_s_type,
1555       { "S-Type",           "cops.s_type",
1556       FT_UINT8, BASE_DEC, NULL, 0x0,
1557       "S-Type in COPS-PR Object Header", HFILL }
1558     },
1559
1560     { &hf_cops_r_type_flags,
1561       { "R-Type",           "cops.context.r_type",
1562       FT_UINT16, BASE_HEX, VALS(cops_r_type_vals), 0xFFFF,
1563       "R-Type in COPS Context Object", HFILL }
1564     },
1565     { &hf_cops_m_type_flags,
1566       { "M-Type",           "cops.context.m_type",
1567       FT_UINT16, BASE_HEX, NULL, 0xFFFF,
1568       "M-Type in COPS Context Object", HFILL }
1569     },
1570     { &hf_cops_in_int_ipv4,
1571       { "IPv4 address",           "cops.in-int.ipv4",
1572       FT_IPv4, 0, NULL, 0xFFFF,
1573       "IPv4 address in COPS IN-Int object", HFILL }
1574     },
1575     { &hf_cops_in_int_ipv6,
1576       { "IPv6 address",           "cops.in-int.ipv6",
1577       FT_IPv6, 0, NULL, 0xFFFF,
1578       "IPv6 address in COPS IN-Int object", HFILL }
1579     },
1580     { &hf_cops_out_int_ipv4,
1581       { "IPv4 address",           "cops.out-int.ipv4",
1582       FT_IPv4, 0, NULL, 0xFFFF,
1583       "IPv4 address in COPS OUT-Int object", HFILL }
1584     },
1585     { &hf_cops_out_int_ipv6,
1586       { "IPv6 address",           "cops.out-int.ipv6",
1587       FT_IPv6, 0, NULL, 0xFFFF,
1588       "IPv6 address in COPS OUT-Int", HFILL }
1589     },
1590     { &hf_cops_int_ifindex,
1591       { "ifIndex",           "cops.in-out-int.ifindex",
1592       FT_UINT32, BASE_DEC, NULL, 0x0,
1593       "If SNMP is supported, corresponds to MIB-II ifIndex", HFILL }
1594     },
1595     { &hf_cops_reason,
1596       { "Reason",           "cops.reason",
1597       FT_UINT16, BASE_DEC, VALS(cops_reason_vals), 0,
1598       "Reason in Reason object", HFILL }
1599     },
1600     { &hf_cops_reason_sub,
1601       { "Reason Sub-code",           "cops.reason_sub",
1602       FT_UINT16, BASE_HEX, NULL, 0,
1603       "Reason Sub-code in Reason object", HFILL }
1604     },
1605     { &hf_cops_dec_cmd_code,
1606       { "Command-Code",           "cops.decision.cmd",
1607       FT_UINT16, BASE_DEC, VALS(cops_dec_cmd_code_vals), 0,
1608       "Command-Code in Decision/LPDP Decision object", HFILL }
1609     },
1610     { &hf_cops_dec_flags,
1611       { "Flags",           "cops.decision.flags",
1612       FT_UINT16, BASE_HEX, VALS(cops_dec_cmd_flag_vals), 0xffff,
1613       "Flags in Decision/LPDP Decision object", HFILL }
1614     },
1615     { &hf_cops_error,
1616       { "Error",           "cops.error",
1617       FT_UINT16, BASE_DEC, VALS(cops_error_vals), 0,
1618       "Error in Error object", HFILL }
1619     },
1620     { &hf_cops_error_sub,
1621       { "Error Sub-code",           "cops.error_sub",
1622       FT_UINT16, BASE_HEX, NULL, 0,
1623       "Error Sub-code in Error object", HFILL }
1624     },
1625     { &hf_cops_katimer,
1626       { "Contents: KA Timer Value",           "cops.katimer.value",
1627       FT_UINT16, BASE_DEC, NULL, 0,
1628       "Keep-Alive Timer Value in KATimer object", HFILL }
1629     },
1630     { &hf_cops_pepid,
1631       { "Contents: PEP Id",           "cops.pepid.id",
1632       FT_STRING, BASE_NONE, NULL, 0,
1633       "PEP Id in PEPID object", HFILL }
1634     },
1635     { &hf_cops_report_type,
1636       { "Contents: Report-Type",           "cops.report_type",
1637       FT_UINT16, BASE_DEC, VALS(cops_report_type_vals), 0,
1638       "Report-Type in Report-Type object", HFILL }
1639     },
1640     { &hf_cops_pdprediraddr_ipv4,
1641       { "IPv4 address",           "cops.pdprediraddr.ipv4",
1642       FT_IPv4, 0, NULL, 0xFFFF,
1643       "IPv4 address in COPS PDPRedirAddr object", HFILL }
1644     },
1645     { &hf_cops_pdprediraddr_ipv6,
1646       { "IPv6 address",           "cops.pdprediraddr.ipv6",
1647       FT_IPv6, 0, NULL, 0xFFFF,
1648       "IPv6 address in COPS PDPRedirAddr object", HFILL }
1649     },
1650     { &hf_cops_lastpdpaddr_ipv4,
1651       { "IPv4 address",           "cops.lastpdpaddr.ipv4",
1652       FT_IPv4, 0, NULL, 0xFFFF,
1653       "IPv4 address in COPS LastPDPAddr object", HFILL }
1654     },
1655     { &hf_cops_lastpdpaddr_ipv6,
1656       { "IPv6 address",           "cops.lastpdpaddr.ipv6",
1657       FT_IPv6, 0, NULL, 0xFFFF,
1658       "IPv6 address in COPS LastPDPAddr object", HFILL }
1659     },
1660     { &hf_cops_pdp_tcp_port,
1661       { "TCP Port Number",           "cops.pdp.tcp_port",
1662       FT_UINT32, BASE_DEC, NULL, 0x0,
1663        "TCP Port Number of PDP in PDPRedirAddr/LastPDPAddr object", HFILL }
1664     },
1665     { &hf_cops_accttimer,
1666       { "Contents: ACCT Timer Value",           "cops.accttimer.value",
1667       FT_UINT16, BASE_DEC, NULL, 0,
1668       "Accounting Timer Value in AcctTimer object", HFILL }
1669     },
1670     { &hf_cops_key_id,
1671       { "Contents: Key ID",           "cops.integrity.key_id",
1672       FT_UINT32, BASE_DEC, NULL, 0,
1673       "Key ID in Integrity object", HFILL }
1674     },
1675     { &hf_cops_seq_num,
1676       { "Contents: Sequence Number",           "cops.integrity.seq_num",
1677       FT_UINT32, BASE_DEC, NULL, 0,
1678       "Sequence Number in Integrity object", HFILL }
1679     },
1680     { &hf_cops_gperror,
1681       { "Error",           "cops.gperror",
1682       FT_UINT16, BASE_DEC, VALS(cops_gperror_vals), 0,
1683       "Error in Error object", HFILL }
1684     },
1685     { &hf_cops_gperror_sub,
1686       { "Error Sub-code",           "cops.gperror_sub",
1687       FT_UINT16, BASE_HEX, NULL, 0,
1688       "Error Sub-code in Error object", HFILL }
1689     },
1690     { &hf_cops_cperror,
1691       { "Error",           "cops.cperror",
1692       FT_UINT16, BASE_DEC, VALS(cops_cperror_vals), 0,
1693       "Error in Error object", HFILL }
1694     },
1695     { &hf_cops_cperror_sub,
1696       { "Error Sub-code",           "cops.cperror_sub",
1697       FT_UINT16, BASE_HEX, NULL, 0,
1698       "Error Sub-code in Error object", HFILL }
1699     },
1700
1701     /* Added for PacketCable */
1702
1703     { &hf_cops_subtree,
1704       { "Object Subtree", "cops.pc_subtree",
1705         FT_UINT16, BASE_HEX, NULL, 0,
1706         "Object Subtree", HFILL }
1707     },
1708     { &hf_cops_pc_ds_field,
1709       { "DS Field (DSCP or TOS)", "cops.pc_ds_field",
1710         FT_UINT8, BASE_HEX, NULL, 0x00,
1711         "DS Field (DSCP or TOS)", HFILL }
1712     },
1713     { &hf_cops_pc_direction,
1714       { "Direction", "cops.pc_direction",
1715         FT_UINT8, BASE_HEX, NULL, 0x00,
1716         "Direction", HFILL }
1717     },
1718     { &hf_cops_pc_gate_spec_flags,
1719       { "Flags", "cops.pc_gate_spec_flags",
1720         FT_UINT8, BASE_HEX, NULL, 0x00,
1721         "Flags", HFILL }
1722     },
1723     { &hf_cops_pc_protocol_id,
1724       { "Protocol ID", "cops.pc_protocol_id",
1725         FT_UINT8, BASE_HEX, NULL, 0x00,
1726         "Protocol ID", HFILL }
1727     },
1728     { &hf_cops_pc_session_class,
1729       { "Session Class", "cops.pc_session_class",
1730         FT_UINT8, BASE_HEX, NULL, 0x00,
1731         "Session Class", HFILL }
1732     },
1733     { &hf_cops_pc_algorithm,
1734       { "Algorithm", "cops.pc_algorithm",
1735         FT_UINT16, BASE_HEX, NULL, 0x00,
1736         "Algorithm", HFILL }
1737     },
1738     { &hf_cops_pc_cmts_ip_port,
1739       { "CMTS IP Port", "cops.pc_cmts_ip_port",
1740         FT_UINT16, BASE_HEX, NULL, 0x00,
1741         "CMTS IP Port", HFILL }
1742     },
1743     { &hf_cops_pc_prks_ip_port,
1744       { "PRKS IP Port", "cops.pc_prks_ip_port",
1745         FT_UINT16, BASE_HEX, NULL, 0x00,
1746         "PRKS IP Port", HFILL }
1747     },
1748     { &hf_cops_pc_srks_ip_port,
1749       { "SRKS IP Port", "cops.pc_srks_ip_port",
1750         FT_UINT16, BASE_HEX, NULL, 0x00,
1751         "SRKS IP Port", HFILL }
1752     },
1753     { &hf_cops_pc_dest_port,
1754       { "Destination IP Port", "cops.pc_dest_port",
1755         FT_UINT16, BASE_HEX, NULL, 0x00,
1756         "Destination IP Port", HFILL }
1757     },
1758     { &hf_cops_pc_packetcable_err_code,
1759       { "Error Code", "cops.pc_packetcable_err_code",
1760         FT_UINT16, BASE_HEX, NULL, 0x00,
1761         "Error Code", HFILL }
1762     },
1763     { &hf_cops_pc_packetcable_sub_code,
1764       { "Error Sub Code", "cops.pc_packetcable_sub_code",
1765         FT_UINT16, BASE_HEX, NULL, 0x00,
1766         "Error Sub Code", HFILL }
1767     },
1768     { &hf_cops_pc_remote_flags,
1769       { "Flags", "cops.pc_remote_flags",
1770         FT_UINT16, BASE_HEX, NULL, 0x00,
1771         "Flags", HFILL }
1772     },
1773     { &hf_cops_pc_close_subcode,
1774       { "Reason Sub Code", "cops.pc_close_subcode",
1775         FT_UINT16, BASE_HEX, NULL, 0x00,
1776         "Reason Sub Code", HFILL }
1777     },
1778     { &hf_cops_pc_gate_command_type,
1779       { "Gate Command Type", "cops.pc_gate_command_type",
1780         FT_UINT16, BASE_HEX, NULL, 0x00,
1781         "Gate Command Type", HFILL }
1782     },
1783     { &hf_cops_pc_reason_code,
1784       { "Reason Code", "cops.pc_reason_code",
1785         FT_UINT16, BASE_HEX, NULL, 0x00,
1786         "Reason Code", HFILL }
1787     },
1788     { &hf_cops_pc_delete_subcode,
1789       { "Reason Sub Code", "cops.pc_delete_subcode",
1790         FT_UINT16, BASE_HEX, NULL, 0x00,
1791         "Reason Sub Code", HFILL }
1792     },
1793     { &hf_cops_pc_src_port,
1794       { "Source IP Port", "cops.pc_src_port",
1795         FT_UINT16, BASE_HEX, NULL, 0x00,
1796         "Source IP Port", HFILL }
1797     },
1798     { &hf_cops_pc_t1_value,
1799       { "Timer T1 Value (sec)", "cops.pc_t1_value",
1800         FT_UINT16, BASE_HEX, NULL, 0x00,
1801         "Timer T1 Value (sec)", HFILL }
1802     },
1803     { &hf_cops_pc_t7_value,
1804       { "Timer T7 Value (sec)", "cops.pc_t7_value",
1805         FT_UINT16, BASE_HEX, NULL, 0x00,
1806         "Timer T7 Value (sec)", HFILL }
1807     },
1808     { &hf_cops_pc_t8_value,
1809       { "Timer T8 Value (sec)", "cops.pc_t8_value",
1810         FT_UINT16, BASE_HEX, NULL, 0x00,
1811         "Timer T8 Value (sec)", HFILL }
1812     },
1813     { &hf_cops_pc_transaction_id,
1814       { "Transaction Identifier", "cops.pc_transaction_id",
1815         FT_UINT16, BASE_HEX, NULL, 0x00,
1816         "Transaction Identifier", HFILL }
1817     },
1818     { &hf_cops_pc_cmts_ip,
1819       { "CMTS IP Address", "cops.pc_cmts_ip",
1820         FT_UINT32, BASE_HEX, NULL, 0x00,
1821         "CMTS IP Address", HFILL }
1822     },
1823     { &hf_cops_pc_prks_ip,
1824       { "PRKS IP Address", "cops.pc_prks_ip",
1825         FT_UINT32, BASE_HEX, NULL, 0x00,
1826         "PRKS IP Address", HFILL }
1827     },
1828     { &hf_cops_pc_srks_ip,
1829       { "SRKS IP Address", "cops.pc_srks_ip",
1830         FT_UINT32, BASE_HEX, NULL, 0x00,
1831         "SRKS IP Address", HFILL }
1832     },
1833     { &hf_cops_pc_dfcdc_ip,
1834       { "DF IP Address CDC", "cops.pc_dfcdc_ip",
1835         FT_UINT32, BASE_HEX, NULL, 0x00,
1836         "DF IP Address CDC", HFILL }
1837     },
1838     { &hf_cops_pc_dfccc_ip,
1839       { "DF IP Address CCC", "cops.pc_dfccc_ip",
1840         FT_UINT32, BASE_HEX, NULL, 0x00,
1841         "DF IP Address CCC", HFILL }
1842     },
1843     { &hf_cops_pc_dfcdc_ip_port,
1844       { "DF IP Port CDC", "cops.pc_dfcdc_ip_port",
1845         FT_UINT16, BASE_HEX, NULL, 0x00,
1846         "DF IP Port CDC", HFILL }
1847     },
1848     { &hf_cops_pc_dfccc_ip_port,
1849       { "DF IP Port CCC", "cops.pc_dfccc_ip_port",
1850         FT_UINT16, BASE_HEX, NULL, 0x00,
1851         "DF IP Port CCC", HFILL }
1852     },
1853     { &hf_cops_pc_activity_count,
1854       { "Count", "cops.pc_activity_count",
1855         FT_UINT32, BASE_HEX, NULL, 0x00,
1856         "Count", HFILL }
1857     },
1858     { &hf_cops_pc_dest_ip,
1859       { "Destination IP Address", "cops.pc_dest_ip",
1860         FT_UINT32, BASE_HEX, NULL, 0x00,
1861         "Destination IP Address", HFILL }
1862     },
1863     { &hf_cops_pc_gate_id,
1864       { "Gate Identifier", "cops.pc_gate_id",
1865         FT_UINT32, BASE_HEX, NULL, 0x00,
1866         "Gate Identifier", HFILL }
1867     },
1868     { &hf_cops_pc_max_packet_size,
1869       { "Maximum Packet Size", "cops.pc_max_packet_size",
1870         FT_UINT32, BASE_HEX, NULL, 0x00,
1871         "Maximum Packet Size", HFILL }
1872     },
1873     { &hf_cops_pc_min_policed_unit,
1874       { "Minimum Policed Unit", "cops.pc_min_policed_unit",
1875         FT_UINT32, BASE_HEX, NULL, 0x00,
1876         "Minimum Policed Unit", HFILL }
1877     },
1878     { &hf_cops_pc_peak_data_rate,
1879       { "Peak Data Rate", "cops.pc_peak_data_rate",
1880         FT_FLOAT, BASE_NONE, NULL, 0x00,
1881         "Peak Data Rate", HFILL }
1882     },
1883     { &hf_cops_pc_spec_rate,
1884       { "Rate", "cops.pc_spec_rate",
1885         FT_FLOAT, BASE_NONE, NULL, 0x00,
1886         "Rate", HFILL }
1887     },
1888     { &hf_cops_pc_remote_gate_id,
1889       { "Remote Gate ID", "cops.pc_remote_gate_id",
1890         FT_UINT32, BASE_HEX, NULL, 0x00,
1891         "Remote Gate ID", HFILL }
1892     },
1893     { &hf_cops_pc_reserved,
1894       { "Reserved", "cops.pc_reserved",
1895         FT_UINT32, BASE_HEX, NULL, 0x00,
1896         "Reserved", HFILL }
1897     },
1898     { &hf_cops_pc_key,
1899       { "Security Key", "cops.pc_key",
1900         FT_UINT32, BASE_HEX, NULL, 0x00,
1901         "Security Key", HFILL }
1902     },
1903     { &hf_cops_pc_slack_term,
1904       { "Slack Term", "cops.pc_slack_term",
1905         FT_UINT32, BASE_HEX, NULL, 0x00,
1906         "Slack Term", HFILL }
1907     },
1908     { &hf_cops_pc_src_ip,
1909       { "Source IP Address", "cops.pc_src_ip",
1910         FT_UINT32, BASE_HEX, NULL, 0x00,
1911         "Source IP Address", HFILL }
1912     },
1913     { &hf_cops_pc_subscriber_id,
1914       { "Subscriber Identifier (IPv4)", "cops.pc_subscriber_id",
1915         FT_UINT32, BASE_HEX, NULL, 0x00,
1916         "Subscriber Identifier (IPv4)", HFILL }
1917     },
1918     { &hf_cops_pc_token_bucket_rate,
1919       { "Token Bucket Rate", "cops.pc_token_bucket_rate",
1920         FT_FLOAT, BASE_NONE, NULL, 0x00,
1921         "Token Bucket Rate", HFILL }
1922     },
1923     { &hf_cops_pc_token_bucket_size,
1924       { "Token Bucket Size", "cops.pc_token_bucket_size",
1925         FT_FLOAT, BASE_NONE, NULL, 0x00,
1926         "Token Bucket Size", HFILL }
1927     },
1928     { &hf_cops_pc_bcid,
1929       { "Billing Correlation ID", "cops.pc_bcid",
1930         FT_UINT32, BASE_HEX, NULL, 0x00,
1931         "Billing Correlation ID", HFILL }
1932     },
1933     { &hf_cops_pc_bcid_ts,
1934       { "BDID Timestamp", "cops.pc_bcid_ts",
1935         FT_UINT32, BASE_HEX, NULL, 0x00,
1936         "BCID Timestamp", HFILL }
1937     },
1938     { &hf_cops_pc_bcid_ev,
1939       { "BDID Event Counter", "cops.pc_bcid_ev",
1940         FT_UINT32, BASE_HEX, NULL, 0x00,
1941         "BCID Event Counter", HFILL }
1942     },
1943
1944
1945     /* End of addition for PacketCable */
1946
1947   };
1948
1949   /* Setup protocol subtree array */
1950   static gint *ett[] = {
1951     &ett_cops,
1952     &ett_cops_ver_flags,
1953     &ett_cops_obj,
1954     &ett_cops_pr_obj,
1955     &ett_cops_obj_data,
1956     &ett_cops_r_type_flags,
1957     &ett_cops_itf,
1958     &ett_cops_reason,
1959     &ett_cops_decision,
1960     &ett_cops_error,
1961     &ett_cops_clientsi,
1962     &ett_cops_asn1,
1963     &ett_cops_gperror,
1964     &ett_cops_cperror,
1965     &ett_cops_pdp,
1966     &ett_cops_subtree,
1967   };
1968
1969   module_t* cops_module;
1970
1971   /* Register the protocol name and description */
1972   proto_cops = proto_register_protocol("Common Open Policy Service",
1973       "COPS", "cops");
1974
1975   /* Required function calls to register the header fields and subtrees used */
1976   proto_register_field_array(proto_cops, hf, array_length(hf));
1977   proto_register_subtree_array(ett, array_length(ett));
1978
1979   /* Register our configuration options for cops */
1980   cops_module = prefs_register_protocol(proto_cops, proto_reg_handoff_cops);
1981   prefs_register_uint_preference(cops_module,"tcp.cops_port",
1982                                  "COPS TCP Port",
1983                                  "Set the TCP port for COPS messages",
1984                                  10,&global_cops_tcp_port);
1985   prefs_register_bool_preference(cops_module, "desegment",
1986                                  "Desegment all COPS messages\nspanning multiple TCP segments",
1987                                  "Whether the COPS dissector should desegment all messages spanning multiple TCP segments",
1988                                  &cops_desegment);
1989
1990   /* For PacketCable */
1991   prefs_register_bool_preference(cops_module, "packetcable",
1992                                  "Decode for PacketCable clients",
1993                                  "Decode the COPS messages using PacketCable clients. (Select port 2126)",
1994                                  &cops_packetcable);
1995
1996 #ifdef HAVE_NET_SNMP /*enable preference only if compiled with NET-SNMP*/
1997   prefs_register_bool_preference(cops_module, "typefrommib",
1998                                  "Decode COPS-PR ASN.1 types by reading them\nfrom PIBs (converted to MIBs)",
1999                                  "Whether the COPS dissector should decode COPS-PR ASN.1 types based on data types read from packet or PIBs (converted to MIBs)",
2000                                  &cops_typefrommib);
2001 #endif /*HAVE_NET_SNMP*/
2002 }
2003
2004 void proto_reg_handoff_cops(void)
2005 {
2006   static int cops_prefs_initialized = FALSE;
2007   static dissector_handle_t cops_handle;
2008
2009   if (!cops_prefs_initialized) {
2010     cops_handle = create_dissector_handle(dissect_cops, proto_cops);
2011     cops_prefs_initialized = TRUE;
2012   } else
2013     dissector_delete("tcp.port",cops_tcp_port,cops_handle);
2014
2015   /* Set our port numbers for future use */
2016   cops_tcp_port = global_cops_tcp_port;
2017
2018   dissector_add("tcp.port", cops_tcp_port, cops_handle);
2019 }
2020
2021
2022 /* Additions for PacketCable ( Added by Dick Gooris, Lucent Technologies ) */
2023
2024 /* Definitions for print formatting */
2025 #define   FMT_DEC   0
2026 #define   FMT_HEX   1
2027 #define   FMT_IP    2
2028 #define   FMT_FLT   3
2029
2030 /* Print the translated information in the display gui in a formatted way
2031  *
2032  * octets = The number of octets to obtain from the buffer
2033  *
2034  * vsp    = If not a NULL pointer, it points to an array with text
2035  *
2036  * mode   = 0 -> print decimal value
2037  *          1 -> print hexadecimal vaue
2038  *          2 -> print value as an ip address
2039  *          3 -> print value as an ieee float
2040  *
2041  * This function in combination with the separate function info_to_cops_subtree() for subtrees.
2042  *
2043  */
2044
2045 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)
2046 {
2047
2048      guint8   code8  = 0;
2049      guint16  code16 = 0;
2050      guint32  code32 = 0;
2051      guint32  codeip = 0;
2052      float    codefl = 0.0;
2053
2054      /* Print information elements in the specified way */
2055      switch (octets) {
2056
2057      case 1:
2058              /* Get the octet */
2059              code8 = tvb_get_guint8( tvb, offset );
2060              if (vsp == NULL) {
2061                 /* Hexadecimal format */
2062                 if (mode==FMT_HEX)
2063                    proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb,
2064                        offset, octets, code8,"%-28s : 0x%02x",str,code8);
2065                 else
2066                    /* Print an 8 bits integer */
2067                    proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb,
2068                        offset, octets, code8,"%-28s : %u",str,code8);
2069              } else {
2070                if (mode==FMT_HEX)
2071                   /* Hexadecimal format */
2072                   proto_tree_add_uint_format(
2073                       stt, *hf_proto_parameter,tvb, offset, octets, code8,
2074                       "%-28s : %s (0x%02x)",str,val_to_str(code8, vsp, "Unknown"),code8);
2075                else
2076                   /* String table indexed */
2077                   proto_tree_add_uint_format(
2078                       stt, *hf_proto_parameter,tvb, offset, octets, code8,
2079                       "%-28s : %s (%u)",str,val_to_str(code8, vsp, "Unknown"),code8);
2080              }
2081              break;
2082
2083        case 2:
2084
2085              /* Get the next two octets */
2086              code16 = tvb_get_ntohs(tvb,offset);
2087              if (vsp == NULL) {
2088                 /* Hexadecimal format */
2089                 if (mode==FMT_HEX)
2090                    proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb,
2091                        offset, octets, code16,"%-28s : 0x%04x",str,code16);
2092                 else
2093                    /* Print a 16 bits integer */
2094                    proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb,
2095                        offset, octets, code16,"%-28s : %u",str,code16);
2096              }  else {
2097                 if (mode==FMT_HEX)
2098                    /* Hexadecimal format */
2099                    proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb,
2100                        offset, octets, code16,"%-28s : %s (0x%04x)", str,
2101                        val_to_str(code16, vsp, "Unknown (0x%04x)"),code16);
2102                 else
2103                    /* Print a 16 bits integer */
2104                    proto_tree_add_uint_format(
2105                        stt, *hf_proto_parameter,tvb, offset, octets, code16,
2106                        "%-28s : %s (%u)",str,val_to_str(code16, vsp, "Unknown (0x%04x)"),code16);
2107              }
2108              break;
2109
2110         case 4:
2111
2112              /* Get the next four octets */
2113              switch (mode) {
2114                case FMT_FLT:  codefl  = tvb_get_ntohieee_float(tvb,offset);
2115                               break;
2116                case FMT_IP:   tvb_memcpy(tvb, (guint8 *)&code32, offset, 4);
2117                               codeip  = tvb_get_ntohl(tvb,offset);
2118                               break;
2119                default:       code32  = tvb_get_ntohl(tvb,offset);
2120              }
2121
2122              if (vsp == NULL) {
2123                 /* Hexadecimal format */
2124                 if (mode==FMT_HEX) {
2125                    proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb,
2126                        offset, octets, code32,"%-28s : 0x%08x",str,code32);
2127                    break;
2128                 }
2129                 /* Ip address format*/
2130                 if (mode==FMT_IP) {
2131                    proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb, offset,octets,
2132                        codeip,"%-28s : %s",str,ip_to_str((guint8 *)&code32));
2133                    break;
2134                 }
2135                 /* Ieee float format */
2136                 if (mode==FMT_FLT) {
2137                    proto_tree_add_float_format(stt, *hf_proto_parameter,tvb, offset, octets,
2138                        codefl,"%-28s : %.10g",str,codefl);
2139                    break;
2140                 }
2141                 /* Print a 32 bits integer */
2142                 proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb, offset, octets,
2143                     code32,"%-28s : %u",str,code32);
2144              } else {
2145                 /* Hexadecimal format */
2146                 if (mode==FMT_HEX)
2147                    proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb, offset, octets,
2148                            code32,"%-28s : %s (0x%08x)",str,val_to_str(code32, vsp, "Unknown"),code32);
2149                 else
2150                    /* String table indexed */
2151                    proto_tree_add_uint_format(stt, *hf_proto_parameter,tvb, offset, octets,
2152                        code32,"%-28s : %s (%u)",str,val_to_str(code32, vsp, "Unknown"),code32);
2153              }
2154              break;
2155
2156         /* In case of more than 4 octets.... */
2157         default: {
2158              if (mode==FMT_HEX)
2159                 proto_tree_add_bytes(stt, *hf_proto_parameter,
2160                    tvb, offset, octets, tvb_get_ptr(tvb, offset,octets));
2161              else
2162                 proto_tree_add_uint_format(stt, *hf_proto_parameter,
2163                    tvb, offset, octets, code32,"%s",str);
2164              break;
2165         }
2166
2167      }
2168 }
2169
2170 /* Print the subtree information for cops */
2171 proto_tree *info_to_cops_subtree(tvbuff_t *tvb, proto_tree *st, int n, int offset, char *str) {
2172      proto_item *tv;
2173
2174      tv  = proto_tree_add_uint_format( st, hf_cops_subtree, tvb, offset, n, (guint)NULL, str);
2175      return( proto_item_add_subtree( tv, ett_cops_subtree ) );
2176 }
2177
2178 /* Cops - Section : Transaction ID */
2179 void cops_transaction_id(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2180
2181      proto_tree *stt;
2182      guint16  code16;
2183      char info[50];
2184
2185      /* Create a subtree */
2186      stt = info_to_cops_subtree(tvb,st,n,offset,"Transaction ID");
2187
2188      /* Transaction Identifier */
2189      info_to_display(tvb,stt,offset,2,"Transaction Identifier", NULL,FMT_DEC,&hf_cops_pc_transaction_id);
2190      offset +=2;
2191
2192      /* Gate Command Type */
2193      code16 = tvb_get_ntohs(tvb,offset);
2194      proto_tree_add_uint_format(stt, hf_cops_pc_gate_command_type,tvb, offset, 2,
2195             code16,"%-28s : %s (%u)", "Gate Command Type",
2196             val_to_str(code16,table_cops_transaction_id, "Unknown (0x%04x)"),code16);
2197
2198      /* Write the right data into the 'info field' on the Gui */
2199      sprintf(info,"COPS %-20s - ",val_to_str(opcode_idx,cops_op_code_vals, "Unknown"));
2200      strcat(info,val_to_str(code16,table_cops_transaction_id, "Unknown"));
2201
2202      if (check_col(cpinfo->cinfo, COL_INFO)) {
2203           col_clear(cpinfo->cinfo, COL_INFO);
2204           col_add_str(cpinfo->cinfo, COL_INFO,info);
2205      }
2206
2207 }
2208
2209 /* Cops - Section : Subscriber ID */
2210 void cops_subscriber_id_v4(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2211
2212      proto_item *tv;
2213
2214      /* Create a subtree */
2215      tv = info_to_cops_subtree(tvb,st,n,offset,"Subscriber ID");
2216
2217      /* Subscriber Identifier */
2218      info_to_display(tvb,tv,offset,4,"Subscriber Identifier (IPv4)", NULL,FMT_IP,&hf_cops_pc_subscriber_id);
2219 }
2220
2221 /* Cops - Section : Gate ID */
2222 void cops_gate_id(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2223
2224      proto_tree *stt;
2225
2226      /* Create a subtree */
2227      stt = info_to_cops_subtree(tvb,st,n,offset,"Gate ID");
2228
2229      /* Gate Identifier */
2230      info_to_display(tvb,stt,offset,4,"Gate Identifier", NULL,FMT_HEX,&hf_cops_pc_gate_id);
2231 }
2232
2233 /* Cops - Section : Activity Count */
2234 void cops_activity_count(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2235
2236      proto_tree *stt;
2237
2238      /* Create a subtree */
2239      stt = info_to_cops_subtree(tvb,st,n,offset,"Activity Count");
2240
2241      /* Activity Count */
2242      info_to_display(tvb,stt,offset,4,"Count", NULL,FMT_DEC,&hf_cops_pc_activity_count);
2243 }
2244
2245 /* Cops - Section : Gate Specifications */
2246 void cops_gate_specs(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2247
2248      proto_tree *stt;
2249
2250      /* Create a subtree */
2251      stt = info_to_cops_subtree(tvb,st,n,offset,"Gate Specifications");
2252
2253      /* Direction */
2254      info_to_display(tvb,stt,offset,1,"Direction",table_cops_direction,FMT_DEC,&hf_cops_pc_direction);
2255      offset += 1;
2256
2257      /* Protocol ID */
2258      info_to_display(tvb,stt,offset,1,"Protocol ID",NULL,FMT_DEC,&hf_cops_pc_protocol_id);
2259      offset += 1;
2260
2261      /* Flags */
2262      info_to_display(tvb,stt,offset,1,"Flags",NULL,FMT_DEC,&hf_cops_pc_gate_spec_flags);
2263      offset += 1;
2264
2265      /* Session Class */
2266      info_to_display(tvb,stt,offset,1,"Session Class",table_cops_session_class,FMT_DEC,&hf_cops_pc_session_class);
2267      offset += 1;
2268
2269      /* Source IP Address */
2270      info_to_display(tvb,stt,offset,4,"Source IP Address",NULL,FMT_IP,&hf_cops_pc_src_ip);
2271      offset += 4;
2272
2273      /* Destination IP Address */
2274      info_to_display(tvb,stt,offset,4,"Destination IP Address",NULL,FMT_IP,&hf_cops_pc_dest_ip);
2275      offset += 4;
2276
2277      /* Source IP Port */
2278      info_to_display(tvb,stt,offset,2,"Source IP Port",NULL,FMT_DEC,&hf_cops_pc_src_port);
2279      offset += 2;
2280
2281      /* Destination IP Port */
2282      info_to_display(tvb,stt,offset,2,"Destination IP Port",NULL,FMT_DEC,&hf_cops_pc_dest_port);
2283      offset += 2;
2284
2285      /* DiffServ Code Point */
2286      info_to_display(tvb,stt,offset,1,"DS Field (DSCP or TOS)",NULL,FMT_HEX,&hf_cops_pc_ds_field);
2287      offset += 1;
2288
2289      /* 3 octets Not specified */
2290      offset += 3;
2291
2292      /* Timer T1 Value */
2293      info_to_display(tvb,stt,offset,2,"Timer T1 Value (sec)",NULL,FMT_DEC,&hf_cops_pc_t1_value);
2294      offset += 2;
2295
2296      /* Reserved */
2297      info_to_display(tvb,stt,offset,2,"Reserved",NULL,FMT_DEC,&hf_cops_pc_reserved);
2298      offset += 2;
2299
2300      /* Timer T7 Value */
2301      info_to_display(tvb,stt,offset,2,"Timer T7 Value (sec)",NULL,FMT_DEC,&hf_cops_pc_t7_value);
2302      offset += 2;
2303
2304      /* Timer T8 Value */
2305      info_to_display(tvb,stt,offset,2,"Timer T8 Value (sec)",NULL,FMT_DEC,&hf_cops_pc_t8_value);
2306      offset += 2;
2307
2308      /* Token Bucket Rate */
2309      info_to_display(tvb,stt,offset,4,"Token Bucket Rate",NULL,FMT_FLT,&hf_cops_pc_token_bucket_rate);
2310      offset += 4;
2311
2312      /* Token Bucket Size */
2313      info_to_display(tvb,stt,offset,4,"Token Bucket Size",NULL,FMT_FLT,&hf_cops_pc_token_bucket_size);
2314      offset += 4;
2315
2316      /* Peak Data Rate */
2317      info_to_display(tvb,stt,offset,4,"Peak Data Rate",NULL,FMT_FLT,&hf_cops_pc_peak_data_rate);
2318      offset += 4;
2319
2320      /* Minimum Policed Unit */
2321      info_to_display(tvb,stt,offset,4,"Minimum Policed Unit",NULL,FMT_DEC,&hf_cops_pc_min_policed_unit);
2322      offset += 4;
2323
2324      /* Maximum Packet Size */
2325      info_to_display(tvb,stt,offset,4,"Maximum Packet Size",NULL,FMT_DEC,&hf_cops_pc_max_packet_size);
2326      offset += 4;
2327
2328      /* Rate */
2329      info_to_display(tvb,stt,offset,4,"Rate",NULL,FMT_FLT,&hf_cops_pc_spec_rate);
2330      offset += 4;
2331
2332      /* Slack Term */
2333      info_to_display(tvb,stt,offset,4,"Slack Term",NULL,FMT_DEC,&hf_cops_pc_slack_term);
2334 }
2335
2336 /* Cops - Section : Electronic Surveillance Parameters  */
2337 void  cops_surveillance_parameters(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2338
2339      proto_tree *stt;
2340      guint8 *bcid_str;
2341
2342      /* Create a subtree */
2343      stt = info_to_cops_subtree(tvb,st,n,offset,"Electronic Surveillance Parameters");
2344
2345      /* DF IP Address for CDC */
2346      info_to_display(tvb,stt,offset,4,"DF IP Address for CDC", NULL,FMT_IP,&hf_cops_pc_dfcdc_ip);
2347      offset += 4;
2348
2349      /* DF IP Port for CDC */
2350      info_to_display(tvb,stt,offset,2,"DF IP Port for CDC",NULL,FMT_DEC,&hf_cops_pc_dfcdc_ip_port);
2351      offset += 2;
2352
2353      /* Flags */
2354      info_to_display(tvb,stt,offset,2,"Flags",NULL,FMT_HEX,&hf_cops_pc_gate_spec_flags);
2355      offset += 2;
2356
2357      /* DF IP Address for CCC */
2358      info_to_display(tvb,stt,offset,4,"DF IP Address for CCC", NULL,FMT_IP,&hf_cops_pc_dfccc_ip);
2359      offset += 4;
2360
2361      /* DF IP Port for CCC */
2362      info_to_display(tvb,stt,offset,2,"DF IP Port for CCC",NULL,FMT_DEC,&hf_cops_pc_dfccc_ip_port);
2363      offset += 2;
2364
2365      /* Reserved */
2366      info_to_display(tvb,stt,offset,2,"Reserved",NULL,FMT_HEX,&hf_cops_pc_reserved);
2367      offset += 2;
2368
2369      /* CCCID */
2370      info_to_display(tvb,stt,offset,4,"CCCID", NULL,FMT_HEX,&hf_cops_pc_srks_ip);
2371      offset += 4;
2372
2373      /* BCID Timestamp */
2374      info_to_display(tvb,stt,offset,4,"BCID - Timestamp",NULL,FMT_HEX,&hf_cops_pc_bcid_ts);
2375      offset += 4;
2376
2377      /* BCID Element ID */
2378      bcid_str = tvb_get_string(tvb, offset, 8);
2379      proto_tree_add_text(stt, tvb, offset, 8,"%-28s : '%s'","BCID - Element ID",bcid_str);
2380      offset += 8;
2381
2382      /* BCID Time Zone */
2383      bcid_str = tvb_get_string(tvb, offset, 8);
2384      proto_tree_add_text(stt, tvb, offset, 8,"%-28s : '%s'","BCID - Time Zone",bcid_str);
2385      offset += 8;
2386
2387      /* BCID Event Counter */
2388      info_to_display(tvb,stt,offset,4,"BCID - Event Counter",NULL,FMT_DEC,&hf_cops_pc_bcid_ev);
2389 }
2390
2391 /* Cops - Section : Event Gereration-Info */
2392 void  cops_event_generation_info(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2393
2394      proto_tree *stt;
2395      guint8 *bcid_str;
2396
2397      /* Create a subtree */
2398      stt = info_to_cops_subtree(tvb,st,n,offset,"Event Generation Info");
2399
2400      /* Primary Record Keeping Server IP Address */
2401      info_to_display(tvb,stt,offset,4,"PRKS IP Address", NULL,FMT_IP,&hf_cops_pc_prks_ip);
2402      offset += 4;
2403
2404      /* Primary Record Keeping Server IP Port */
2405      info_to_display(tvb,stt,offset,2,"PRKS IP Port",NULL,FMT_DEC,&hf_cops_pc_prks_ip_port);
2406      offset += 2;
2407
2408      /* Flags */
2409      info_to_display(tvb,stt,offset,1,"Flags",NULL,FMT_HEX,&hf_cops_pc_gate_spec_flags);
2410      offset += 1;
2411
2412      /* Reserved */
2413      info_to_display(tvb,stt,offset,1,"Reserved",NULL,FMT_HEX,&hf_cops_pc_reserved);
2414      offset += 1;
2415
2416      /* Secundary Record Keeping Server IP Address */
2417      info_to_display(tvb,stt,offset,4,"SRKS IP Address", NULL,FMT_IP,&hf_cops_pc_srks_ip);
2418      offset += 4;
2419
2420      /* Secundary Record Keeping Server IP Port */
2421      info_to_display(tvb,stt,offset,2,"SRKS IP Port",NULL,FMT_DEC,&hf_cops_pc_srks_ip_port);
2422      offset += 2;
2423
2424      /* Flags */
2425      info_to_display(tvb,stt,offset,1,"Flags",NULL,FMT_DEC,&hf_cops_pc_gate_spec_flags);
2426      offset += 1;
2427
2428      /* Reserved */
2429      info_to_display(tvb,stt,offset,1,"Reserved",NULL,FMT_HEX,&hf_cops_pc_reserved);
2430      offset += 1;
2431
2432      /* BCID Timestamp */
2433      info_to_display(tvb,stt,offset,4,"BCID - Timestamp",NULL,FMT_HEX,&hf_cops_pc_bcid_ts);
2434      offset += 4;
2435
2436      /* BCID Element ID */
2437      bcid_str = tvb_get_string(tvb, offset, 8);
2438      proto_tree_add_text(stt, tvb, offset, 8,"%-28s : '%s'","BCID - Element ID",bcid_str);
2439      offset += 8;
2440
2441      /* BCID Time Zone */
2442      bcid_str = tvb_get_string(tvb, offset, 8);
2443      proto_tree_add_text(stt, tvb, offset, 8,"%-28s : '%s'","BCID - Time Zone",bcid_str);
2444      offset += 8;
2445
2446      /* BCID Event Counter */
2447      info_to_display(tvb,stt,offset,4,"BCID - Event Counter",NULL,FMT_DEC,&hf_cops_pc_bcid_ev);
2448 }
2449
2450 /* Cops - Section : Remote Gate */
2451 void cops_remote_gate_info(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2452
2453      proto_tree *stt;
2454
2455      /* Create a subtree */
2456      stt = info_to_cops_subtree(tvb,st,n,offset,"Remote Gate Info");
2457
2458      /* CMTS IP Address */
2459      info_to_display(tvb,stt,offset,4,"CMTS IP Address", NULL,FMT_IP,&hf_cops_pc_cmts_ip);
2460      offset += 4;
2461
2462      /* CMTS IP Port */
2463      info_to_display(tvb,stt,offset,2,"CMTS IP Port",NULL,FMT_DEC,&hf_cops_pc_cmts_ip_port);
2464      offset += 2;
2465
2466      /* Flags */
2467      info_to_display(tvb,stt,offset,2,"Flags",NULL,FMT_DEC,&hf_cops_pc_remote_flags);
2468      offset += 2;
2469
2470      /* Remote Gate ID */
2471      info_to_display(tvb,stt,offset,4,"Remote Gate ID", NULL,FMT_HEX,&hf_cops_pc_remote_gate_id);
2472      offset += 4;
2473
2474      /* Algorithm */
2475      info_to_display(tvb,stt,offset,2,"Algorithm", NULL,FMT_IP,&hf_cops_pc_algorithm);
2476      offset += 2;
2477
2478      /* Reserved */
2479      info_to_display(tvb,stt,offset,4,"Reserved", NULL,FMT_IP,&hf_cops_pc_reserved);
2480      offset += 4;
2481
2482      /* Security Key */
2483      info_to_display(tvb,stt,offset,4,"Security Key", NULL,FMT_HEX,&hf_cops_pc_key);
2484      offset += 4;
2485
2486      /* Security Key */
2487      info_to_display(tvb,stt,offset,4,"Security Key (cont)", NULL,FMT_HEX,&hf_cops_pc_key);
2488      offset += 4;
2489
2490      /* Security Key */
2491      info_to_display(tvb,stt,offset,4,"Security Key (cont)", NULL,FMT_HEX,&hf_cops_pc_key);
2492      offset += 4;
2493
2494      /* Security Key */
2495      info_to_display(tvb,stt,offset,4,"Security Key (cont)", NULL,FMT_HEX,&hf_cops_pc_key);
2496 }
2497
2498 /* Cops - Section : PacketCable reason */
2499 void cops_packetcable_reason(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2500
2501      proto_tree *stt;
2502      guint16  code16;
2503
2504      /* Create a subtree */
2505      stt = info_to_cops_subtree(tvb,st,n,offset,"PacketCable Reason");
2506
2507      /* Reason Code */
2508      code16 = tvb_get_ntohs(tvb,offset);
2509      proto_tree_add_uint_format(stt, hf_cops_pc_reason_code,tvb, offset, 2,
2510        code16, "%-28s : %s (%u)","Reason Code",
2511        val_to_str(code16, table_cops_reason_code, "Unknown (0x%04x)"),code16);
2512      offset += 2;
2513
2514      if ( code16 == 0 ) {
2515         /* Reason Sub Code with Delete */
2516         info_to_display(tvb,stt,offset,2,"Reason Sub Code",table_cops_reason_subcode_delete,FMT_DEC,&hf_cops_pc_delete_subcode);
2517      } else {
2518         /* Reason Sub Code with Close */
2519         info_to_display(tvb,stt,offset,2,"Reason Sub Code",table_cops_reason_subcode_close,FMT_DEC,&hf_cops_pc_close_subcode);
2520      }
2521 }
2522
2523 /* Cops - Section : PacketCable error */
2524 void cops_packetcable_error(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2525
2526      proto_tree *stt;
2527
2528      /* Create a subtree */
2529      stt = info_to_cops_subtree(tvb,st,n,offset,"PacketCable Error");
2530
2531      /* Error Code */
2532      info_to_display(tvb,stt,offset,2,"Error Code",table_cops_packetcable_error,FMT_DEC,&hf_cops_pc_packetcable_err_code);
2533      offset += 2;
2534
2535      /* Error Sub Code */
2536      info_to_display(tvb,stt,offset,2,"Error Sub Code",NULL,FMT_HEX,&hf_cops_pc_packetcable_sub_code);
2537
2538 }
2539
2540 /* Analyze the PacketCable objects */
2541 void cops_analyze_packetcable_obj(tvbuff_t *tvb, proto_tree *tree, guint32 offset) {
2542
2543     gint remdata;
2544     guint16 object_len;
2545     guint8 s_num, s_type;
2546
2547     /* Only if this option is enabled by the Gui */
2548     if ( cops_packetcable == FALSE ) {
2549        return;
2550     }
2551
2552     /* Do the remaining client specific objects */
2553     remdata = tvb_length_remaining(tvb, offset);
2554     while (remdata > 4) {
2555
2556        /* In case we have remaining data, then lets try to get this analyzed */
2557        object_len   = tvb_get_ntohs(tvb, offset);
2558        if (object_len < 4) {
2559         proto_tree_add_text(tree, tvb, offset, 2,
2560             "Incorrect PacketCable object length %u < 4", object_len);
2561         return;
2562        }
2563         
2564        s_num        = tvb_get_guint8(tvb, offset + 2);
2565        s_type       = tvb_get_guint8(tvb, offset + 3);
2566
2567        /* Tune offset */
2568        offset += 4;
2569
2570        /* Perform the appropriate functions */
2571        switch (s_num){
2572         case 1:
2573                if (s_type == 1) {
2574                   cops_transaction_id(tvb, tree, object_len, offset);
2575                }
2576                break;
2577         case 2:
2578                if (s_type == 1) {
2579                   cops_subscriber_id_v4(tvb, tree, object_len, offset);
2580                }
2581                break;
2582         case 3:
2583                if (s_type == 1) {
2584                   cops_gate_id(tvb, tree, object_len, offset);
2585                }
2586                break;
2587         case 4:
2588                if (s_type == 1) {
2589                   cops_activity_count(tvb, tree, object_len, offset);
2590                }
2591                break;
2592         case 5:
2593                if (s_type == 1) {
2594                   cops_gate_specs(tvb, tree, object_len, offset);
2595                }
2596                break;
2597         case 6:
2598                if (s_type == 1) {
2599                   cops_remote_gate_info(tvb, tree, object_len, offset);
2600                }
2601                break;
2602         case 7:
2603                if (s_type == 1) {
2604                   cops_event_generation_info(tvb, tree, object_len, offset);
2605                }
2606                break;
2607         case 9:
2608                if (s_type == 1) {
2609                   cops_packetcable_error(tvb, tree, object_len, offset);
2610                }
2611                break;
2612         case 10:
2613                if (s_type == 1) {
2614                   cops_surveillance_parameters(tvb, tree, object_len, offset);
2615                }
2616                break;
2617         case 13:
2618                if (s_type == 1) {
2619                   cops_packetcable_reason(tvb, tree, object_len, offset);
2620                }
2621                break;
2622        }
2623
2624        /* Tune offset */
2625        offset += object_len-4;
2626
2627        /* See what we can still get from the buffer */
2628        remdata = tvb_length_remaining(tvb, offset);
2629     }
2630 }
2631
2632 /* End of PacketCable Addition */
2633
2634