1bc0cc13a2036023f43b0856806add0c34cd1bd2
[obnox/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  *    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.44 2004/04/15 09:24:07 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_delete_subcode = -1;
550 static gint hf_cops_pc_dest_ip = -1;
551 static gint hf_cops_pc_dest_port = -1;
552 static gint hf_cops_pc_direction = -1;
553 static gint hf_cops_pc_ds_field = -1;
554 static gint hf_cops_pc_gate_id = -1;
555 static gint hf_cops_pc_gate_spec_flags = -1;
556 static gint hf_cops_pc_gate_command_type = -1;
557 static gint hf_cops_pc_key = -1;
558 static gint hf_cops_pc_max_packet_size = -1;
559 static gint hf_cops_pc_min_policed_unit = -1;
560 static gint hf_cops_pc_packetcable_err_code = -1;
561 static gint hf_cops_pc_packetcable_sub_code = -1;
562 static gint hf_cops_pc_peak_data_rate = -1;
563 static gint hf_cops_pc_protocol_id = -1;
564 static gint hf_cops_pc_reason_code = -1;
565 static gint hf_cops_pc_remote_flags = -1;
566 static gint hf_cops_pc_remote_gate_id = -1;
567 static gint hf_cops_pc_reserved = -1;
568 static gint hf_cops_pc_session_class = -1;
569 static gint hf_cops_pc_slack_term = -1;
570 static gint hf_cops_pc_spec_rate = -1;
571 static gint hf_cops_pc_src_ip = -1;
572 static gint hf_cops_pc_src_port = -1;
573 static gint hf_cops_pc_subscriber_id = -1;
574 static gint hf_cops_pc_t1_value = -1;
575 static gint hf_cops_pc_t7_value = -1;
576 static gint hf_cops_pc_t8_value = -1;
577 static gint hf_cops_pc_token_bucket_rate = -1;
578 static gint hf_cops_pc_token_bucket_size = -1;
579 static gint hf_cops_pc_transaction_id = -1;
580
581 /* Initialize the subtree pointers */
582 static gint ett_cops = -1;
583 static gint ett_cops_ver_flags = -1;
584 static gint ett_cops_obj = -1;
585 static gint ett_cops_pr_obj = -1;
586 static gint ett_cops_obj_data = -1;
587 static gint ett_cops_r_type_flags = -1;
588 static gint ett_cops_itf = -1;
589 static gint ett_cops_reason = -1;
590 static gint ett_cops_decision = -1;
591 static gint ett_cops_error = -1;
592 static gint ett_cops_clientsi = -1;
593 static gint ett_cops_asn1 = -1;
594 static gint ett_cops_gperror = -1;
595 static gint ett_cops_cperror = -1;
596 static gint ett_cops_pdp = -1;
597
598 /* For PacketCable */
599 static gint ett_cops_subtree = -1;
600
601 void proto_reg_handoff_cops(void);
602
603 static guint get_cops_pdu_len(tvbuff_t *tvb, int offset);
604 static void dissect_cops_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
605
606 static int dissect_cops_object(tvbuff_t *tvb, guint32 offset, proto_tree *tree);
607 static void dissect_cops_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
608                                      guint8 c_num, guint8 c_type, guint16 len);
609
610 static void dissect_cops_pr_objects(tvbuff_t *tvb, guint32 offset, proto_tree *tree, guint16 pr_len);
611 static int dissect_cops_pr_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
612                                        guint8 s_num, guint8 s_type, guint16 len);
613
614 /* Added for PacketCable */
615 proto_tree *cops_to_subtree(tvbuff_t *, proto_tree *, int, int, char *);
616 void   cops_to_disp_fmt(tvbuff_t *, proto_item *, int, int, char *, const value_string *, int, gint *);
617 void   cops_transaction_id(tvbuff_t *, proto_tree *, guint, guint32);
618 void   cops_subscriber_id_v4(tvbuff_t *, proto_tree *, guint, guint32);
619 void   cops_gate_id(tvbuff_t *, proto_tree *, guint, guint32);
620 void   cops_activity_count(tvbuff_t *, proto_tree *, guint, guint32);
621 void   cops_gate_specs(tvbuff_t *, proto_tree *, guint, guint32);
622 void   cops_remote_gate_info(tvbuff_t *, proto_tree *, guint, guint32);
623 void   cops_packetcable_reason(tvbuff_t *, proto_tree *, guint, guint32);
624 void   cops_packetcable_error(tvbuff_t *, proto_tree *, guint, guint32);
625 void   cops_analyze_packetcable_obj(tvbuff_t *, proto_tree *, guint32);
626
627 static packet_info *cpinfo;
628 static guint8 opcode_idx;
629 static gboolean cops_packetcable = FALSE;
630 /* End of addition for PacketCable */ 
631
632
633 /* Code to actually dissect the packets */
634 static void
635 dissect_cops(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
636 {
637   tcp_dissect_pdus(tvb, pinfo, tree, cops_desegment, 8,
638                    get_cops_pdu_len, dissect_cops_pdu);
639 }
640
641 static guint
642 get_cops_pdu_len(tvbuff_t *tvb, int offset)
643 {
644   /*
645    * Get the length of the COPS message.
646    */
647   return tvb_get_ntohl(tvb, offset + 4);
648 }
649
650 static void
651 dissect_cops_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
652 {
653   guint8 op_code;
654   int object_len;
655
656   if (check_col(pinfo->cinfo, COL_PROTOCOL))
657     col_set_str(pinfo->cinfo, COL_PROTOCOL, "COPS");
658   if (check_col(pinfo->cinfo, COL_INFO))
659     col_clear(pinfo->cinfo, COL_INFO);
660
661   op_code = tvb_get_guint8(tvb, 1);
662   if (check_col(pinfo->cinfo, COL_INFO))
663     col_add_fstr(pinfo->cinfo, COL_INFO, "COPS %s",
664                  val_to_str(op_code, cops_op_code_vals, "Unknown Op Code"));
665
666   /* PacketCable: Remember the next two values to manipulate the info field in the Gui */
667   cpinfo = pinfo;
668   opcode_idx = op_code;
669         
670   if (tree) {
671     proto_item *ti, *tv;
672     proto_tree *cops_tree, *ver_flags_tree;
673     guint32 msg_len;
674     guint32 offset = 0;
675     guint8 ver_flags;
676     gint garbage;
677
678     ti = proto_tree_add_item(tree, proto_cops, tvb, offset, -1, FALSE);
679     cops_tree = proto_item_add_subtree(ti, ett_cops);
680
681     /* Version and flags share the same byte, put them in a subtree */
682     ver_flags = tvb_get_guint8(tvb, offset);
683     tv = proto_tree_add_uint_format(cops_tree, hf_cops_ver_flags, tvb, offset, 1,
684                                       ver_flags, "Version: %u, Flags: %s",
685                                       hi_nibble(ver_flags),
686                                       val_to_str(lo_nibble(ver_flags), cops_flags_vals, "Unknown"));
687     ver_flags_tree = proto_item_add_subtree(tv, ett_cops_ver_flags);
688     proto_tree_add_uint(ver_flags_tree, hf_cops_version, tvb, offset, 1, ver_flags);
689     proto_tree_add_uint(ver_flags_tree, hf_cops_flags, tvb, offset, 1, ver_flags);
690     offset++;
691
692     proto_tree_add_item(cops_tree, hf_cops_op_code, tvb, offset, 1, FALSE);
693     offset ++;
694     proto_tree_add_item(cops_tree, hf_cops_client_type, tvb, offset, 2, FALSE);
695     offset += 2;
696
697     msg_len = tvb_get_ntohl(tvb, offset);
698     proto_tree_add_uint(cops_tree, hf_cops_msg_len, tvb, offset, 4, msg_len);
699     offset += 4;
700
701     while (tvb_reported_length_remaining(tvb, offset) >= COPS_OBJECT_HDR_SIZE) {
702       object_len = dissect_cops_object(tvb, offset, cops_tree);
703       if (object_len < 0)
704         return;
705       offset += object_len;
706     }
707
708     garbage = tvb_length_remaining(tvb, offset);
709     if (garbage > 0)
710       proto_tree_add_text(cops_tree, tvb, offset, garbage,
711                           "Trailing garbage: %d byte%s", garbage,
712                           plurality(garbage, "", "s"));
713   }
714 }
715
716 static char *cops_c_type_to_str(guint8 c_num, guint8 c_type)
717 {
718   switch (c_num) {
719   case COPS_OBJ_HANDLE:
720     if (c_type == 1)
721       return "Client Handle";
722     break;
723   case COPS_OBJ_IN_INT:
724   case COPS_OBJ_OUT_INT:
725     if (c_type == 1)
726       return "IPv4 Address + Interface";
727     else if (c_type == 2)
728       return "IPv6 Address + Interface";
729     break;
730   case COPS_OBJ_DECISION:
731   case COPS_OBJ_LPDPDECISION:
732     if (c_type == 1)
733       return "Decision Flags (Mandatory)";
734     else if (c_type == 2)
735       return "Stateless Data";
736     else if (c_type == 3)
737       return "Replacement Data";
738     else if (c_type == 4)
739       return "Client Specific Decision Data";
740     else if (c_type == 5)
741       return "Named Decision Data";
742     break;
743   case COPS_OBJ_CLIENTSI:
744     if (c_type == 1)
745       return "Signaled ClientSI";
746     else if (c_type == 2)
747       return "Named ClientSI";
748     break;
749   case COPS_OBJ_KATIMER:
750     if (c_type == 1)
751       return "Keep-alive timer value";
752     break;
753   case COPS_OBJ_PDPREDIRADDR:
754   case COPS_OBJ_LASTPDPADDR:
755     if (c_type == 1)
756       return "IPv4 Address + TCP Port";
757     else if (c_type == 2)
758       return "IPv6 Address + TCP Port";
759     break;
760   case COPS_OBJ_ACCTTIMER:
761     if (c_type == 1)
762       return "Accounting timer value";
763     break;
764   case COPS_OBJ_INTEGRITY:
765     if (c_type == 1)
766       return "HMAC digest";
767     break;
768   }
769
770   return "";
771 }
772
773 static int dissect_cops_object(tvbuff_t *tvb, guint32 offset, proto_tree *tree)
774 {
775   guint16 object_len, contents_len;
776   guint8 c_num, c_type;
777   proto_item *ti;
778   proto_tree *obj_tree;
779   char *type_str;
780
781   object_len = tvb_get_ntohs(tvb, offset);
782   if (object_len < COPS_OBJECT_HDR_SIZE) {
783     /* Bogus! */
784     proto_tree_add_text(tree, tvb, offset, 2,
785                         "Bad COPS object length: %u, should be at least %u",
786                         object_len, COPS_OBJECT_HDR_SIZE);
787     return -1;
788   }
789   c_num = tvb_get_guint8(tvb, offset + 2);
790   c_type = tvb_get_guint8(tvb, offset + 3);
791
792   ti = proto_tree_add_uint_format(tree, hf_cops_obj_c_num, tvb, offset, object_len, c_num,
793                                   "%s: %s", val_to_str(c_num, cops_c_num_vals, "Unknown"),
794                                   cops_c_type_to_str(c_num, c_type));
795   obj_tree = proto_item_add_subtree(ti, ett_cops_obj);
796
797   proto_tree_add_uint(obj_tree, hf_cops_obj_len, tvb, offset, 2, object_len);
798   offset += 2;
799
800   proto_tree_add_uint(obj_tree, hf_cops_obj_c_num, tvb, offset, 1, c_num);
801   offset++;
802
803   type_str = cops_c_type_to_str(c_num, c_type);
804   proto_tree_add_text(obj_tree, tvb, offset, 1, "C-Type: %s%s%u%s",
805                       type_str,
806                       strlen(type_str) ? " (" : "",
807                       c_type,
808                       strlen(type_str) ? ")" : "");
809   offset++;
810
811   contents_len = object_len - COPS_OBJECT_HDR_SIZE;
812   dissect_cops_object_data(tvb, offset, obj_tree, c_num, c_type, contents_len);
813
814   /* Pad to 32bit boundary */
815   if (object_len % sizeof (guint32))
816     object_len += (sizeof (guint32) - object_len % sizeof (guint32));
817
818   return object_len;
819 }
820
821 static void dissect_cops_pr_objects(tvbuff_t *tvb, guint32 offset, proto_tree *tree, guint16 pr_len)
822 {
823   guint16 object_len, contents_len;
824   guint8 s_num, s_type;
825   char *type_str;
826   int ret;
827   proto_tree *cops_pr_tree, *obj_tree;
828   proto_item *ti;
829
830   cops_pr_tree = proto_item_add_subtree(tree, ett_cops_pr_obj);
831
832   while (pr_len >= COPS_OBJECT_HDR_SIZE) {
833     object_len = tvb_get_ntohs(tvb, offset);
834     if (object_len < COPS_OBJECT_HDR_SIZE) {
835       /* Bogus! */
836       proto_tree_add_text(tree, tvb, offset, 2,
837                           "Bad COPS PR object length: %u, should be at least %u",
838                           object_len, COPS_OBJECT_HDR_SIZE);
839       return;
840     }
841     s_num = tvb_get_guint8(tvb, offset + 2);
842
843     ti = proto_tree_add_uint_format(cops_pr_tree, hf_cops_obj_s_num, tvb, offset, object_len, s_num,
844                                     "%s", val_to_str(s_num, cops_s_num_vals, "Unknown"));
845     obj_tree = proto_item_add_subtree(cops_pr_tree, ett_cops_pr_obj);
846
847     proto_tree_add_uint(obj_tree, hf_cops_obj_len, tvb, offset, 2, object_len);
848     offset += 2;
849     pr_len -= 2;
850
851     proto_tree_add_uint(obj_tree, hf_cops_obj_s_num, tvb, offset, 1, s_num);
852     offset++;
853     pr_len--;
854
855     s_type = tvb_get_guint8(tvb, offset);
856     type_str = val_to_str(s_type, cops_s_type_vals, "Unknown");
857     proto_tree_add_text(obj_tree, tvb, offset, 1, "S-Type: %s%s%u%s",
858                         type_str,
859                         strlen(type_str) ? " (" : "",
860                         s_type,
861                         strlen(type_str) ? ")" : "");
862     offset++;
863     pr_len--;
864
865     contents_len = object_len - COPS_OBJECT_HDR_SIZE;
866     ret = dissect_cops_pr_object_data(tvb, offset, obj_tree, s_num, s_type, contents_len);
867     if (ret < 0)
868       break;
869
870     /*Pad to 32bit boundary */
871     if (object_len % sizeof (guint32))
872       object_len += (sizeof (guint32) - object_len % sizeof (guint32));
873
874     pr_len -= object_len - COPS_OBJECT_HDR_SIZE;
875     offset += object_len - COPS_OBJECT_HDR_SIZE;
876   }
877 }
878
879 static void dissect_cops_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
880                                      guint8 c_num, guint8 c_type, guint16 len)
881 {
882   proto_item *ti;
883   proto_tree *r_type_tree, *itf_tree, *reason_tree, *dec_tree, *error_tree, *clientsi_tree, *pdp_tree;
884   guint16 r_type, m_type, reason, reason_sub, cmd_code, cmd_flags, error, error_sub, tcp_port;
885   guint32 ipv4addr, ifindex;
886   struct e_in6_addr ipv6addr;
887
888   switch (c_num) {
889   case COPS_OBJ_CONTEXT:
890     r_type = tvb_get_ntohs(tvb, offset);
891     m_type = tvb_get_ntohs(tvb, offset + 2);
892     ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: R-Type: %s, M-Type: %u",
893                              val_to_str(r_type, cops_r_type_vals, "Unknown"),
894                              m_type);
895
896     r_type_tree = proto_item_add_subtree(ti, ett_cops_r_type_flags);
897     proto_tree_add_uint(r_type_tree, hf_cops_r_type_flags, tvb, offset, 2, r_type);
898     offset += 2;
899     proto_tree_add_uint(r_type_tree, hf_cops_m_type_flags, tvb, offset, 2, m_type);
900
901     break;
902   case COPS_OBJ_IN_INT:
903   case COPS_OBJ_OUT_INT:
904     if (c_type == 1) {          /* IPv4 */
905       tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset, 4);
906       ifindex = tvb_get_ntohl(tvb, offset + 4);
907       ti = proto_tree_add_text(tree, tvb, offset, 8, "Contents: IPv4 address %s, ifIndex: %u",
908                                ip_to_str((guint8 *)&ipv4addr), ifindex);
909       itf_tree = proto_item_add_subtree(ti, ett_cops_itf);
910       proto_tree_add_ipv4(itf_tree,
911                           (c_num == COPS_OBJ_IN_INT) ? hf_cops_in_int_ipv4 : hf_cops_out_int_ipv4,
912                           tvb, offset, 4, ipv4addr);
913       offset += 4;
914     } else if (c_type == 2) {   /* IPv6 */
915       tvb_memcpy(tvb, (guint8 *)&ipv6addr, offset, sizeof ipv6addr);
916       ifindex = tvb_get_ntohl(tvb, offset + sizeof ipv6addr);
917       ti = proto_tree_add_text(tree, tvb, offset, 20, "Contents: IPv6 address %s, ifIndex: %u",
918                                ip6_to_str(&ipv6addr), ifindex);
919       itf_tree = proto_item_add_subtree(ti, ett_cops_itf);
920       proto_tree_add_ipv6(itf_tree,
921                           (c_num == COPS_OBJ_IN_INT) ? hf_cops_in_int_ipv6 : hf_cops_out_int_ipv6,
922                           tvb, offset, 16, (guint8 *)&ipv6addr);
923       offset += 16;
924     } else {
925       break;
926     }
927     proto_tree_add_uint(itf_tree, hf_cops_int_ifindex, tvb, offset, 4, ifindex);
928
929     break;
930   case COPS_OBJ_REASON:
931     reason = tvb_get_ntohs(tvb, offset);
932     reason_sub = tvb_get_ntohs(tvb, offset + 2);
933     ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Reason-Code: %s, Reason Sub-code: 0x%04x",
934                              val_to_str(reason, cops_reason_vals, "<Unknown value>"), reason_sub);
935     reason_tree = proto_item_add_subtree(ti, ett_cops_reason);
936     proto_tree_add_uint(reason_tree, hf_cops_reason, tvb, offset, 2, reason);
937     offset += 2;
938     if (reason == 13) {
939       proto_tree_add_text(reason_tree, tvb, offset, 2, "Reason Sub-code: "
940                           "Unknown object's C-Num %u, C-Type %u",
941                           tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
942     } else
943       proto_tree_add_uint(reason_tree, hf_cops_reason_sub, tvb, offset, 2, reason_sub);
944
945     break;
946   case COPS_OBJ_DECISION:
947   case COPS_OBJ_LPDPDECISION:
948     if (c_type == 1) {
949       cmd_code = tvb_get_ntohs(tvb, offset);
950       cmd_flags = tvb_get_ntohs(tvb, offset + 2);
951       ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Command-Code: %s, Flags: %s",
952                                val_to_str(cmd_code, cops_dec_cmd_code_vals, "<Unknown value>"),
953                                val_to_str(cmd_flags, cops_dec_cmd_flag_vals, "<Unknown flag>"));
954       dec_tree = proto_item_add_subtree(ti, ett_cops_decision);
955       proto_tree_add_uint(dec_tree, hf_cops_dec_cmd_code, tvb, offset, 2, cmd_code);
956       offset += 2;
957       proto_tree_add_uint(dec_tree, hf_cops_dec_flags, tvb, offset, 2, cmd_flags);
958     } else if (c_type == 5) { /*COPS-PR Data*/
959       ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: %u bytes", len);
960       dec_tree = proto_item_add_subtree(ti, ett_cops_decision);
961       dissect_cops_pr_objects(tvb, offset, dec_tree, len);
962     }
963
964     /* PacketCable : Analyze the remaining data if available */
965     cops_analyze_packetcable_obj(tvb, tree, offset);
966           
967     break;
968   case COPS_OBJ_ERROR:
969     if (c_type != 1)
970       break;
971
972     error = tvb_get_ntohs(tvb, offset);
973     error_sub = tvb_get_ntohs(tvb, offset + 2);
974     ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
975                              val_to_str(error, cops_error_vals, "<Unknown value>"), error_sub);
976     error_tree = proto_item_add_subtree(ti, ett_cops_error);
977     proto_tree_add_uint(error_tree, hf_cops_error, tvb, offset, 2, error);
978     offset += 2;
979     if (error == 13) {
980       proto_tree_add_text(error_tree, tvb, offset, 2, "Error Sub-code: "
981                           "Unknown object's C-Num %u, C-Type %u",
982                           tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
983     } else
984       proto_tree_add_uint(error_tree, hf_cops_error_sub, tvb, offset, 2, error_sub);
985
986     break;
987   case COPS_OBJ_CLIENTSI:
988
989     /* For PacketCable */
990     if (c_type == 1) {
991        cops_analyze_packetcable_obj(tvb, tree, offset);
992        break;
993     }
994
995     if (c_type != 2) /*Not COPS-PR data*/
996       break;
997
998     ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: %u bytes", len);
999     clientsi_tree = proto_item_add_subtree(ti, ett_cops_clientsi);
1000
1001     dissect_cops_pr_objects(tvb, offset, clientsi_tree, len);
1002
1003     break;
1004   case COPS_OBJ_KATIMER:
1005     if (c_type != 1)
1006       break;
1007
1008     proto_tree_add_item(tree, hf_cops_katimer, tvb, offset + 2, 2, FALSE);
1009     if (tvb_get_ntohs(tvb, offset + 2) == 0)
1010       proto_tree_add_text(tree, tvb, offset, 0, "Value of zero implies infinity.");
1011
1012     break;
1013   case COPS_OBJ_PEPID:
1014     if (c_type != 1)
1015       break;
1016
1017     if (tvb_strnlen(tvb, offset, len) == -1)
1018       proto_tree_add_text(tree, tvb, offset, len, "<PEP Id is not a NUL terminated ASCII string>");
1019     else
1020       proto_tree_add_item(tree, hf_cops_pepid, tvb, offset,
1021                           tvb_strnlen(tvb, offset, len) + 1, FALSE);
1022
1023     break;
1024   case COPS_OBJ_REPORT_TYPE:
1025     if (c_type != 1)
1026       break;
1027
1028     proto_tree_add_item(tree, hf_cops_report_type, tvb, offset, 2, FALSE);
1029
1030     break;
1031   case COPS_OBJ_PDPREDIRADDR:
1032   case COPS_OBJ_LASTPDPADDR:
1033     if (c_type == 1) {          /* IPv4 */
1034       tvb_memcpy(tvb, (guint8 *)&ipv4addr, offset, 4);
1035       tcp_port = tvb_get_ntohs(tvb, offset + 4 + 2);
1036       ti = proto_tree_add_text(tree, tvb, offset, 8, "Contents: IPv4 address %s, TCP Port Number: %u",
1037                                ip_to_str((guint8 *)&ipv4addr), tcp_port);
1038       pdp_tree = proto_item_add_subtree(ti, ett_cops_pdp);
1039       proto_tree_add_ipv4(pdp_tree,
1040                           (c_num == COPS_OBJ_PDPREDIRADDR) ? hf_cops_pdprediraddr_ipv4 : hf_cops_lastpdpaddr_ipv4,
1041                           tvb, offset, 4, ipv4addr);
1042       offset += 4;
1043     } else if (c_type == 2) {   /* IPv6 */
1044       tvb_memcpy(tvb, (guint8 *)&ipv6addr, offset, sizeof ipv6addr);
1045       tcp_port = tvb_get_ntohs(tvb, offset + sizeof ipv6addr + 2);
1046       ti = proto_tree_add_text(tree, tvb, offset, 20, "Contents: IPv6 address %s, TCP Port Number: %u",
1047                                ip6_to_str(&ipv6addr), tcp_port);
1048       pdp_tree = proto_item_add_subtree(ti, ett_cops_pdp);
1049       proto_tree_add_ipv6(pdp_tree,
1050                           (c_num == COPS_OBJ_PDPREDIRADDR) ? hf_cops_pdprediraddr_ipv6 : hf_cops_lastpdpaddr_ipv6,
1051                           tvb, offset, 16, (guint8 *)&ipv6addr);
1052       offset += 16;
1053     } else {
1054       break;
1055     }
1056     offset += 2;
1057     proto_tree_add_uint(pdp_tree, hf_cops_pdp_tcp_port, tvb, offset, 2, tcp_port);
1058
1059     break;
1060   case COPS_OBJ_ACCTTIMER:
1061     if (c_type != 1)
1062       break;
1063
1064     proto_tree_add_item(tree, hf_cops_accttimer, tvb, offset + 2, 2, FALSE);
1065     if (tvb_get_ntohs(tvb, offset + 2) == 0)
1066       proto_tree_add_text(tree, tvb, offset, 0, "Value of zero means "
1067                           "there SHOULD be no unsolicited accounting updates.");
1068
1069     break;
1070   case COPS_OBJ_INTEGRITY:
1071     if (c_type != 1)
1072       break;      /* Not HMAC digest */
1073
1074     proto_tree_add_item(tree, hf_cops_key_id, tvb, offset, 4, FALSE);
1075     proto_tree_add_item(tree, hf_cops_seq_num, tvb, offset + 4, 4, FALSE);
1076     proto_tree_add_text(tree, tvb, offset + 8 , len - 8, "Contents: Keyed Message Digest");
1077
1078     break;
1079   default:
1080     proto_tree_add_text(tree, tvb, offset, len, "Contents: %u bytes", len);
1081
1082     break;
1083   }
1084 }
1085
1086 #ifdef HAVE_NET_SNMP
1087 static guchar*format_asn_value (struct variable_list *variable, subid_t *variable_oid,
1088                                 guint variable_oid_length, u_char type_from_packet)
1089 {
1090   struct tree *subtree=tree_head;
1091   
1092   guchar *buf=NULL;
1093   size_t buf_len=0;
1094   size_t out_len=0;
1095   
1096   /*Get the ASN.1 type etc. from the PIB-MIB. If unsuccessful use the type from packet*/
1097   subtree = get_tree(variable_oid,variable_oid_length, subtree);
1098   
1099   if (subtree->type == 0)
1100     variable->type= type_from_packet;
1101   
1102   buf_len = SPRINT_MAX_LEN; /*defined in NET-SNMP's snmp-impl.h*/
1103   buf = g_malloc(buf_len);
1104   *buf = '\0';
1105   out_len = 0;
1106  
1107   /*If the ASN.1 type was found from PIB-MIB, use it for decoding*/
1108   if (!variable->type)
1109     variable->type=mib_to_asn_type(subtree->type);
1110  
1111   if (!sprint_realloc_by_type(&buf, &buf_len, &out_len, TRUE, variable, subtree->enums, subtree->hint, NULL))
1112     sprintf(buf,"%s","sprint_realloc_by_type failed");
1113   
1114   return buf;
1115 }
1116 #endif  /* HAVE_NET_SNMP */
1117
1118 static int decode_cops_pr_asn1_data(tvbuff_t *tvb, guint32 offset,
1119     proto_tree *tree, guint asnlen, guint8 cops_pr_obj
1120 #ifndef HAVE_NET_SNMP
1121                                                   _U_
1122 #endif
1123     )
1124 {
1125   ASN1_SCK asn1;
1126   int start;
1127   gboolean def;
1128   guint length;
1129
1130   guint vb_length;
1131   gushort vb_type;
1132   gchar *vb_type_name;
1133
1134   int ret;
1135   guint cls, con, tag;
1136   subid_t epd_attribute_index=0;
1137
1138   gint32 vb_integer_value;
1139   guint32 vb_uinteger_value;
1140
1141   guint8 *vb_octet_string;
1142
1143   subid_t *vb_oid;
1144   guint vb_oid_length;
1145
1146   gchar *vb_display_string;
1147   gchar *vb_display_string2;
1148
1149 #ifdef HAVE_NET_SNMP
1150   struct variable_list variable;
1151   long value;
1152 #endif  /* HAVE_NET_SNMP */
1153   
1154   unsigned int i;
1155   gchar *buf;
1156   int len;
1157
1158   while (asnlen > 0) { /*while there is ASN stuff to be decoded*/
1159
1160     epd_attribute_index++;
1161 #ifdef HAVE_NET_SNMP
1162     last_decoded_prid_oid[last_decoded_prid_oid_length-1]=epd_attribute_index;
1163 #endif  /* HAVE_NET_SNMP */
1164     asn1_open(&asn1, tvb, offset);
1165
1166     /* parse the type of the object */
1167
1168     start = asn1.offset;
1169
1170     ret = asn1_header_decode (&asn1, &cls, &con, &tag, &def, &vb_length);
1171     if (ret != ASN1_ERR_NOERROR)
1172       return 0;
1173     if (!def)
1174       return ASN1_ERR_LENGTH_NOT_DEFINITE;
1175
1176     /* Convert the class, constructed flag, and tag to a type. */
1177     vb_type_name = cops_tag_cls2syntax(tag, cls, &vb_type);
1178     if (vb_type_name == NULL) {
1179       /*
1180        * Unsupported type.
1181        * Dissect the value as an opaque string of octets.
1182        */
1183       vb_type_name = "unsupported type";
1184       vb_type = COPS_OPAQUE;
1185     }
1186
1187     /* parse the value */
1188
1189     switch (vb_type) {
1190
1191     case COPS_INTEGER:
1192       ret = asn1_int32_value_decode(&asn1, vb_length, &vb_integer_value);
1193       if (ret != ASN1_ERR_NOERROR)
1194         return ret;
1195       length = asn1.offset - start;
1196       if (tree) {
1197 #ifdef HAVE_NET_SNMP
1198         if (cops_typefrommib == TRUE)
1199         {
1200           variable.type = 0;
1201           value = vb_integer_value;
1202           variable.val.integer = &value;
1203           variable.val_len = vb_length ;
1204           vb_display_string=format_asn_value(&variable, 
1205                                              last_decoded_prid_oid,last_decoded_prid_oid_length,ASN_INTEGER);
1206    
1207           proto_tree_add_text(tree, asn1.tvb, offset, length,
1208                               "Value: %s", vb_display_string);
1209           g_free(vb_display_string);
1210         }
1211         else
1212 #endif /* HAVE_NET_SNMP */
1213           proto_tree_add_text(tree, asn1.tvb, offset, length,
1214                               "Value: %s: %d (%#x)", vb_type_name,
1215                               vb_integer_value, vb_integer_value);
1216       }
1217       break;
1218
1219     case COPS_UNSIGNED32:
1220     case COPS_TIMETICKS:
1221       ret = asn1_uint32_value_decode(&asn1, vb_length, &vb_uinteger_value);
1222       if (ret != ASN1_ERR_NOERROR)
1223         return ret;
1224       length = asn1.offset - start;
1225       if (tree) {
1226 #ifdef HAVE_NET_SNMP
1227         if (cops_typefrommib == TRUE)
1228         {
1229           variable.type = 0;
1230           value = vb_uinteger_value;
1231           variable.val.integer = &value;
1232           variable.val_len = vb_length;
1233
1234           vb_display_string=format_asn_value(&variable,
1235                                              last_decoded_prid_oid,last_decoded_prid_oid_length,ASN_UINTEGER);
1236      
1237           proto_tree_add_text(tree, asn1.tvb, offset, length, "Value %s: %s",vb_type_name, vb_display_string);
1238   
1239           g_free(vb_display_string);
1240         }
1241         else
1242 #endif /* HAVE_NET_SNMP */
1243           proto_tree_add_text(tree, asn1.tvb, offset, length,
1244                               "Value: %s: %u (%#x)", vb_type_name,
1245                               vb_uinteger_value, vb_uinteger_value);
1246       }
1247       break;
1248
1249     case COPS_OCTETSTR:
1250     case COPS_IPADDR:
1251     case COPS_OPAQUE:
1252     case COPS_UNSIGNED64:
1253     case COPS_INTEGER64:
1254       ret = asn1_string_value_decode (&asn1, vb_length, &vb_octet_string);
1255       if (ret != ASN1_ERR_NOERROR)
1256         return ret;
1257       length = asn1.offset - start;
1258       if (tree) {
1259 #ifdef HAVE_NET_SNMP
1260         if (cops_typefrommib == TRUE)
1261         {
1262           variable.type = 0;
1263           variable.val.string = vb_octet_string;
1264           variable.val_len = vb_length;
1265           vb_display_string = format_asn_value(&variable, 
1266                                                last_decoded_prid_oid,last_decoded_prid_oid_length,ASN_OCTET_STR);
1267           proto_tree_add_text(tree, asn1.tvb, offset, length,
1268                               "Value: %s (ASN.1 type from packet: %s)", vb_display_string, vb_type_name);
1269        
1270           g_free(vb_display_string);
1271         }
1272         else
1273         {
1274 #endif /* HAVE_NET_SNMP */
1275           for (i = 0; i < vb_length; i++) {
1276             if (!(isprint(vb_octet_string[i]) ||isspace(vb_octet_string[i])))
1277               break;
1278           }
1279
1280           /*
1281            * If some characters are not printable, display the string as bytes.
1282            */
1283           if (i < vb_length) {
1284             /*
1285              * We stopped, due to a non-printable character, before we got
1286              * to the end of the string.
1287              */
1288             vb_display_string = g_malloc(4*vb_length);
1289             buf = &vb_display_string[0];
1290             len = sprintf(buf, "%03u", vb_octet_string[0]);
1291             buf += len;
1292             for (i = 1; i < vb_length; i++) {
1293               len = sprintf(buf, ".%03u", vb_octet_string[i]);
1294               buf += len;
1295             }
1296             proto_tree_add_text(tree, asn1.tvb, offset, length,
1297                                 "Value: %s: %s", vb_type_name, vb_display_string);
1298             g_free(vb_display_string);
1299           } else {
1300             proto_tree_add_text(tree, asn1.tvb, offset, length,
1301                                 "Value: %s: %.*s", vb_type_name, (int)vb_length,
1302                                 SAFE_STRING(vb_octet_string));
1303           }
1304 #ifdef HAVE_NET_SNMP
1305         }
1306 #endif /* HAVE_NET_SNMP */
1307       }
1308       g_free(vb_octet_string);
1309       break;
1310
1311     case COPS_NULL:
1312       ret = asn1_null_decode (&asn1, vb_length);
1313       if (ret != ASN1_ERR_NOERROR)
1314         return ret;
1315       length = asn1.offset - start;
1316       if (tree)
1317         proto_tree_add_text(tree, asn1.tvb, offset, length, "Value: %s", vb_type_name);
1318       break;
1319
1320     case COPS_OBJECTID:
1321       ret = asn1_oid_value_decode (&asn1, vb_length, &vb_oid, &vb_oid_length);
1322       if (ret != ASN1_ERR_NOERROR)
1323         return ret;
1324       length = asn1.offset - start;
1325
1326       if (tree) {
1327         if (cops_pr_obj == COPS_OBJ_PPRID){
1328           /*we're decoding Prefix PRID, that doesn't have a instance Id,
1329            *Use full length of the OID when decoding it.
1330            */
1331           new_format_oid(vb_oid,vb_oid_length,&vb_display_string,&vb_display_string2);
1332
1333           if (!vb_display_string2)   /*if OID couldn't be decoded, print only numeric format*/
1334             proto_tree_add_text(tree, asn1.tvb, offset, length,
1335                                 "Value: %s: %s", vb_type_name, vb_display_string);
1336           else
1337             proto_tree_add_text(tree, asn1.tvb, offset, length,
1338                                 "Value: %s: %s (%s)", vb_type_name,
1339                                 vb_display_string,
1340                                 vb_display_string2);
1341         }
1342         else { /*we're decoding PRID, Error PRID or EPD*/
1343           /*strip the instance Id from the OIDs before decoding and paste it back during printing*/
1344           new_format_oid(vb_oid,vb_oid_length-1,&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.%lu", vb_type_name,
1349                                 vb_display_string,
1350                                 (unsigned long)vb_oid[vb_oid_length-1]);
1351           else
1352             proto_tree_add_text(tree, asn1.tvb, offset, length,
1353                                 "Value: %s: %s.%lu (%s.%lu)", vb_type_name,
1354                                 vb_display_string,
1355                                 (unsigned long)vb_oid[vb_oid_length-1],
1356                                 vb_display_string2,
1357                                 (unsigned long)vb_oid[vb_oid_length-1]);
1358         }
1359 #ifdef HAVE_NET_SNMP
1360         if (cops_pr_obj != COPS_OBJ_EPD) {
1361           /* we're not decoding EPD, so let's store the OID of the PRID so that later
1362              when we're decoding this PRID's EPD we can finetune the output.*/
1363           memcpy(last_decoded_prid_oid,vb_oid,vb_oid_length*sizeof(subid_t));
1364           last_decoded_prid_oid_length=vb_oid_length;
1365         }
1366 #endif /* HAVE_NET_SNMP */
1367         
1368       g_free(vb_display_string);
1369       if(vb_display_string2)
1370         g_free(vb_display_string2);
1371       }
1372       g_free(vb_oid);
1373       break;
1374
1375     default:
1376       g_assert_not_reached();
1377       return ASN1_ERR_WRONG_TYPE;
1378     }
1379
1380     asn1_close(&asn1,&offset);
1381
1382     asnlen -= length;
1383   }
1384   epd_attribute_index=0;
1385   return 0;
1386 }
1387
1388 static int dissect_cops_pr_object_data(tvbuff_t *tvb, guint32 offset, proto_tree *tree,
1389                                        guint8 s_num, guint8 s_type, guint16 len)
1390 {
1391   proto_item *ti;
1392   proto_tree *asn1_object_tree, *gperror_tree, *cperror_tree;
1393   guint16 gperror=0, gperror_sub=0, cperror=0, cperror_sub=0;
1394
1395   switch (s_num){
1396   case COPS_OBJ_PRID:
1397    if (s_type != 1) /* Not Provisioning Instance Identifier (PRID) */
1398       break;
1399
1400     ti=proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1401     asn1_object_tree = proto_item_add_subtree(ti, ett_cops_asn1);
1402
1403     decode_cops_pr_asn1_data(tvb, offset, asn1_object_tree, len, COPS_OBJ_PRID);
1404
1405     break;
1406   case COPS_OBJ_PPRID:
1407     if (s_type != 1) /* Not Prefix Provisioning Instance Identifier (PPRID) */
1408       break;
1409
1410     ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1411     asn1_object_tree = proto_item_add_subtree(ti, ett_cops_asn1);
1412
1413     decode_cops_pr_asn1_data(tvb, offset, asn1_object_tree, len, COPS_OBJ_PPRID);
1414
1415     break;
1416   case COPS_OBJ_EPD:
1417     if (s_type != 1) /* Not  Encoded Provisioning Instance Data (EPD) */
1418       break;
1419
1420     ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1421     asn1_object_tree = proto_item_add_subtree(ti, ett_cops_asn1);
1422
1423     decode_cops_pr_asn1_data(tvb, offset, asn1_object_tree, len, COPS_OBJ_EPD);
1424
1425     break;
1426   case COPS_OBJ_GPERR:
1427     if (s_type != 1) /* Not Global Provisioning Error Object (GPERR) */
1428       break;
1429
1430     gperror = tvb_get_ntohs(tvb, offset);
1431     gperror_sub = tvb_get_ntohs(tvb, offset + 2);
1432     ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
1433                        val_to_str(gperror, cops_gperror_vals, "<Unknown value>"), gperror_sub);
1434     gperror_tree = proto_item_add_subtree(ti, ett_cops_gperror);
1435     proto_tree_add_uint(gperror_tree, hf_cops_gperror, tvb, offset, 2, gperror);
1436     offset += 2;
1437     if (cperror == 13) {
1438       proto_tree_add_text(gperror_tree, tvb, offset, 2, "Error Sub-code: "
1439                           "Unknown object's C-Num %u, C-Type %u",
1440                           tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
1441     } else
1442       proto_tree_add_uint(gperror_tree, hf_cops_gperror_sub, tvb, offset, 2, gperror_sub);
1443
1444     break;
1445   case COPS_OBJ_CPERR:
1446     if (s_type != 1) /*Not PRC Class Provisioning Error Object (CPERR) */
1447       break;
1448
1449     break;
1450
1451     cperror = tvb_get_ntohs(tvb, offset);
1452     cperror_sub = tvb_get_ntohs(tvb, offset + 2);
1453     ti = proto_tree_add_text(tree, tvb, offset, 4, "Contents: Error-Code: %s, Error Sub-code: 0x%04x",
1454                        val_to_str(cperror, cops_cperror_vals, "<Unknown value>"), cperror_sub);
1455     cperror_tree = proto_item_add_subtree(ti, ett_cops_cperror);
1456     proto_tree_add_uint(cperror_tree, hf_cops_cperror, tvb, offset, 2, cperror);
1457     offset += 2;
1458     if (cperror == 13) {
1459       proto_tree_add_text(cperror_tree, tvb, offset, 2, "Error Sub-code: "
1460                           "Unknown object's S-Num %u, C-Type %u",
1461                           tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1));
1462     } else
1463       proto_tree_add_uint(cperror_tree, hf_cops_cperror_sub, tvb, offset, 2, cperror_sub);
1464
1465     break;
1466   case COPS_OBJ_ERRPRID:
1467     if (s_type != 1) /*Not  Error Provisioning Instance Identifier (ErrorPRID)*/
1468       break;
1469
1470     ti = proto_tree_add_text(tree, tvb, offset, len, "Contents:");
1471     asn1_object_tree = proto_item_add_subtree(ti, ett_cops_asn1);
1472
1473     decode_cops_pr_asn1_data(tvb, offset, asn1_object_tree, len, COPS_OBJ_ERRPRID);
1474
1475     break;
1476   default:
1477     proto_tree_add_text(tree, tvb, offset, len, "Contents: %u bytes", len);
1478     break;
1479   }
1480
1481   return 0;
1482 }
1483
1484
1485 /* Register the protocol with Ethereal */
1486 void proto_register_cops(void)
1487 {
1488   /* Setup list of header fields */
1489   static hf_register_info hf[] = {
1490     { &hf_cops_ver_flags,
1491       { "Version and Flags",           "cops.ver_flags",
1492       FT_UINT8, BASE_HEX, NULL, 0x0,
1493       "Version and Flags in COPS Common Header", HFILL }
1494     },
1495     { &hf_cops_version,
1496       { "Version",           "cops.version",
1497       FT_UINT8, BASE_DEC, NULL, 0xF0,
1498       "Version in COPS Common Header", HFILL }
1499     },
1500     { &hf_cops_flags,
1501       { "Flags",           "cops.flags",
1502       FT_UINT8, BASE_HEX, VALS(cops_flags_vals), 0x0F,
1503       "Flags in COPS Common Header", HFILL }
1504     },
1505     { &hf_cops_op_code,
1506       { "Op Code",           "cops.op_code",
1507       FT_UINT8, BASE_DEC, VALS(cops_op_code_vals), 0x0,
1508       "Op Code in COPS Common Header", HFILL }
1509     },
1510     { &hf_cops_client_type,
1511       { "Client Type",           "cops.client_type",
1512       FT_UINT16, BASE_DEC, NULL, 0x0,
1513       "Client Type in COPS Common Header", HFILL }
1514     },
1515     { &hf_cops_msg_len,
1516       { "Message Length",           "cops.msg_len",
1517       FT_UINT32, BASE_DEC, NULL, 0x0,
1518       "Message Length in COPS Common Header", HFILL }
1519     },
1520     { &hf_cops_obj_len,
1521       { "Object Length",           "cops.obj.len",
1522       FT_UINT32, BASE_DEC, NULL, 0x0,
1523       "Object Length in COPS Object Header", HFILL }
1524     },
1525     { &hf_cops_obj_c_num,
1526       { "C-Num",           "cops.c_num",
1527       FT_UINT8, BASE_DEC, VALS(cops_c_num_vals), 0x0,
1528       "C-Num in COPS Object Header", HFILL }
1529     },
1530     { &hf_cops_obj_c_type,
1531       { "C-Type",           "cops.c_type",
1532       FT_UINT8, BASE_DEC, NULL, 0x0,
1533       "C-Type in COPS Object Header", HFILL }
1534     },
1535
1536     { &hf_cops_obj_s_num,
1537       { "S-Num",           "cops.s_num",
1538       FT_UINT8, BASE_DEC, VALS(cops_s_num_vals), 0x0,
1539       "S-Num in COPS-PR Object Header", HFILL }
1540     },
1541     { &hf_cops_obj_s_type,
1542       { "S-Type",           "cops.s_type",
1543       FT_UINT8, BASE_DEC, NULL, 0x0,
1544       "S-Type in COPS-PR Object Header", HFILL }
1545     },
1546
1547     { &hf_cops_r_type_flags,
1548       { "R-Type",           "cops.context.r_type",
1549       FT_UINT16, BASE_HEX, VALS(cops_r_type_vals), 0xFFFF,
1550       "R-Type in COPS Context Object", HFILL }
1551     },
1552     { &hf_cops_m_type_flags,
1553       { "M-Type",           "cops.context.m_type",
1554       FT_UINT16, BASE_HEX, NULL, 0xFFFF,
1555       "M-Type in COPS Context Object", HFILL }
1556     },
1557     { &hf_cops_in_int_ipv4,
1558       { "IPv4 address",           "cops.in-int.ipv4",
1559       FT_IPv4, 0, NULL, 0xFFFF,
1560       "IPv4 address in COPS IN-Int object", HFILL }
1561     },
1562     { &hf_cops_in_int_ipv6,
1563       { "IPv6 address",           "cops.in-int.ipv6",
1564       FT_IPv6, 0, NULL, 0xFFFF,
1565       "IPv6 address in COPS IN-Int object", HFILL }
1566     },
1567     { &hf_cops_out_int_ipv4,
1568       { "IPv4 address",           "cops.out-int.ipv4",
1569       FT_IPv4, 0, NULL, 0xFFFF,
1570       "IPv4 address in COPS OUT-Int object", HFILL }
1571     },
1572     { &hf_cops_out_int_ipv6,
1573       { "IPv6 address",           "cops.out-int.ipv6",
1574       FT_IPv6, 0, NULL, 0xFFFF,
1575       "IPv6 address in COPS OUT-Int", HFILL }
1576     },
1577     { &hf_cops_int_ifindex,
1578       { "ifIndex",           "cops.in-out-int.ifindex",
1579       FT_UINT32, BASE_DEC, NULL, 0x0,
1580       "If SNMP is supported, corresponds to MIB-II ifIndex", HFILL }
1581     },
1582     { &hf_cops_reason,
1583       { "Reason",           "cops.reason",
1584       FT_UINT16, BASE_DEC, VALS(cops_reason_vals), 0,
1585       "Reason in Reason object", HFILL }
1586     },
1587     { &hf_cops_reason_sub,
1588       { "Reason Sub-code",           "cops.reason_sub",
1589       FT_UINT16, BASE_HEX, NULL, 0,
1590       "Reason Sub-code in Reason object", HFILL }
1591     },
1592     { &hf_cops_dec_cmd_code,
1593       { "Command-Code",           "cops.decision.cmd",
1594       FT_UINT16, BASE_DEC, VALS(cops_dec_cmd_code_vals), 0,
1595       "Command-Code in Decision/LPDP Decision object", HFILL }
1596     },
1597     { &hf_cops_dec_flags,
1598       { "Flags",           "cops.decision.flags",
1599       FT_UINT16, BASE_HEX, VALS(cops_dec_cmd_flag_vals), 0xffff,
1600       "Flags in Decision/LPDP Decision object", HFILL }
1601     },
1602     { &hf_cops_error,
1603       { "Error",           "cops.error",
1604       FT_UINT16, BASE_DEC, VALS(cops_error_vals), 0,
1605       "Error in Error object", HFILL }
1606     },
1607     { &hf_cops_error_sub,
1608       { "Error Sub-code",           "cops.error_sub",
1609       FT_UINT16, BASE_HEX, NULL, 0,
1610       "Error Sub-code in Error object", HFILL }
1611     },
1612     { &hf_cops_katimer,
1613       { "Contents: KA Timer Value",           "cops.katimer.value",
1614       FT_UINT16, BASE_DEC, NULL, 0,
1615       "Keep-Alive Timer Value in KATimer object", HFILL }
1616     },
1617     { &hf_cops_pepid,
1618       { "Contents: PEP Id",           "cops.pepid.id",
1619       FT_STRING, BASE_NONE, NULL, 0,
1620       "PEP Id in PEPID object", HFILL }
1621     },
1622     { &hf_cops_report_type,
1623       { "Contents: Report-Type",           "cops.report_type",
1624       FT_UINT16, BASE_DEC, VALS(cops_report_type_vals), 0,
1625       "Report-Type in Report-Type object", HFILL }
1626     },
1627     { &hf_cops_pdprediraddr_ipv4,
1628       { "IPv4 address",           "cops.pdprediraddr.ipv4",
1629       FT_IPv4, 0, NULL, 0xFFFF,
1630       "IPv4 address in COPS PDPRedirAddr object", HFILL }
1631     },
1632     { &hf_cops_pdprediraddr_ipv6,
1633       { "IPv6 address",           "cops.pdprediraddr.ipv6",
1634       FT_IPv6, 0, NULL, 0xFFFF,
1635       "IPv6 address in COPS PDPRedirAddr object", HFILL }
1636     },
1637     { &hf_cops_lastpdpaddr_ipv4,
1638       { "IPv4 address",           "cops.lastpdpaddr.ipv4",
1639       FT_IPv4, 0, NULL, 0xFFFF,
1640       "IPv4 address in COPS LastPDPAddr object", HFILL }
1641     },
1642     { &hf_cops_lastpdpaddr_ipv6,
1643       { "IPv6 address",           "cops.lastpdpaddr.ipv6",
1644       FT_IPv6, 0, NULL, 0xFFFF,
1645       "IPv6 address in COPS LastPDPAddr object", HFILL }
1646     },
1647     { &hf_cops_pdp_tcp_port,
1648       { "TCP Port Number",           "cops.pdp.tcp_port",
1649       FT_UINT32, BASE_DEC, NULL, 0x0,
1650        "TCP Port Number of PDP in PDPRedirAddr/LastPDPAddr object", HFILL }
1651     },
1652     { &hf_cops_accttimer,
1653       { "Contents: ACCT Timer Value",           "cops.accttimer.value",
1654       FT_UINT16, BASE_DEC, NULL, 0,
1655       "Accounting Timer Value in AcctTimer object", HFILL }
1656     },
1657     { &hf_cops_key_id,
1658       { "Contents: Key ID",           "cops.integrity.key_id",
1659       FT_UINT32, BASE_DEC, NULL, 0,
1660       "Key ID in Integrity object", HFILL }
1661     },
1662     { &hf_cops_seq_num,
1663       { "Contents: Sequence Number",           "cops.integrity.seq_num",
1664       FT_UINT32, BASE_DEC, NULL, 0,
1665       "Sequence Number in Integrity object", HFILL }
1666     },
1667     { &hf_cops_gperror,
1668       { "Error",           "cops.gperror",
1669       FT_UINT16, BASE_DEC, VALS(cops_gperror_vals), 0,
1670       "Error in Error object", HFILL }
1671     },
1672     { &hf_cops_gperror_sub,
1673       { "Error Sub-code",           "cops.gperror_sub",
1674       FT_UINT16, BASE_HEX, NULL, 0,
1675       "Error Sub-code in Error object", HFILL }
1676     },
1677     { &hf_cops_cperror,
1678       { "Error",           "cops.cperror",
1679       FT_UINT16, BASE_DEC, VALS(cops_cperror_vals), 0,
1680       "Error in Error object", HFILL }
1681     },
1682     { &hf_cops_cperror_sub,
1683       { "Error Sub-code",           "cops.cperror_sub",
1684       FT_UINT16, BASE_HEX, NULL, 0,
1685       "Error Sub-code in Error object", HFILL }
1686     },
1687
1688     /* Added for PacketCable */
1689
1690     { &hf_cops_subtree,
1691       { "Object Subtree", "cops.pc_subtree",
1692         FT_UINT16, BASE_HEX, NULL, 0,
1693         "Object Subtree", HFILL }
1694     },          
1695     { &hf_cops_pc_ds_field,
1696       { "DS Field (DSCP or TOS)", "cops.pc_ds_field",
1697         FT_UINT8, BASE_HEX, NULL, 0x00,
1698         "DS Field (DSCP or TOS)", HFILL }
1699     },        
1700     { &hf_cops_pc_direction,
1701       { "Direction", "cops.pc_direction",
1702         FT_UINT8, BASE_HEX, NULL, 0x00,
1703         "Direction", HFILL }
1704     },        
1705     { &hf_cops_pc_gate_spec_flags,
1706       { "Flags", "cops.pc_gate_spec_flags",
1707         FT_UINT8, BASE_HEX, NULL, 0x00,
1708         "Flags", HFILL }
1709     },        
1710     { &hf_cops_pc_protocol_id,
1711       { "Protocol ID", "cops.pc_protocol_id",
1712         FT_UINT8, BASE_HEX, NULL, 0x00,
1713         "Protocol ID", HFILL }
1714     },        
1715     { &hf_cops_pc_session_class,
1716       { "Session Class", "cops.pc_session_class",
1717         FT_UINT8, BASE_HEX, NULL, 0x00,
1718         "Session Class", HFILL }
1719     },        
1720     { &hf_cops_pc_algorithm,
1721       { "Algorithm", "cops.pc_algorithm",
1722         FT_UINT16, BASE_HEX, NULL, 0x00,
1723         "Algorithm", HFILL }
1724     },        
1725     { &hf_cops_pc_cmts_ip_port,
1726       { "CMTS IP Port", "cops.pc_cmts_ip_port",
1727         FT_UINT16, BASE_HEX, NULL, 0x00,
1728         "CMTS IP Port", HFILL }
1729     },        
1730     { &hf_cops_pc_dest_port,
1731       { "Destination IP Port", "cops.pc_dest_port",
1732         FT_UINT16, BASE_HEX, NULL, 0x00,
1733         "Destination IP Port", HFILL }
1734     },        
1735     { &hf_cops_pc_packetcable_err_code,
1736       { "Error Code", "cops.pc_packetcable_err_code",
1737         FT_UINT16, BASE_HEX, NULL, 0x00,
1738         "Error Code", HFILL }
1739     },        
1740     { &hf_cops_pc_packetcable_sub_code,
1741       { "Error Sub Code", "cops.pc_packetcable_sub_code",
1742         FT_UINT16, BASE_HEX, NULL, 0x00,
1743         "Error Sub Code", HFILL }
1744     },        
1745     { &hf_cops_pc_remote_flags,
1746       { "Flags", "cops.pc_remote_flags",
1747         FT_UINT16, BASE_HEX, NULL, 0x00,
1748         "Flags", HFILL }
1749     },        
1750     { &hf_cops_pc_close_subcode,
1751       { "Reason Sub Code", "cops.pc_close_subcode",
1752         FT_UINT16, BASE_HEX, NULL, 0x00,
1753         "Reason Sub Code", HFILL }
1754     },
1755     { &hf_cops_pc_gate_command_type,
1756       { "Gate Command Type", "cops.pc_gate_command_type",
1757         FT_UINT16, BASE_HEX, NULL, 0x00,
1758         "Gate Command Type", HFILL }
1759     },
1760     { &hf_cops_pc_reason_code,
1761       { "Reason Code", "cops.pc_reason_code",
1762         FT_UINT16, BASE_HEX, NULL, 0x00,
1763         "Reason Code", HFILL }
1764     },        
1765     { &hf_cops_pc_delete_subcode,
1766       { "Reason Sub Code", "cops.pc_delete_subcode",
1767         FT_UINT16, BASE_HEX, NULL, 0x00,
1768         "Reason Sub Code", HFILL }
1769     },        
1770     { &hf_cops_pc_src_port,
1771       { "Source IP Port", "cops.pc_src_port",
1772         FT_UINT16, BASE_HEX, NULL, 0x00,
1773         "Source IP Port", HFILL }
1774     },        
1775     { &hf_cops_pc_t1_value,
1776       { "Timer T1 Value (sec)", "cops.pc_t1_value",
1777         FT_UINT16, BASE_HEX, NULL, 0x00,
1778         "Timer T1 Value (sec)", HFILL }
1779     },        
1780     { &hf_cops_pc_t7_value,
1781       { "Timer T7 Value (sec)", "cops.pc_t7_value",
1782         FT_UINT16, BASE_HEX, NULL, 0x00,
1783         "Timer T7 Value (sec)", HFILL }
1784     },        
1785     { &hf_cops_pc_t8_value,
1786       { "Timer T8 Value (sec)", "cops.pc_t8_value",
1787         FT_UINT16, BASE_HEX, NULL, 0x00,
1788         "Timer T8 Value (sec)", HFILL }
1789     },        
1790     { &hf_cops_pc_transaction_id,
1791       { "Transaction Identifier", "cops.pc_transaction_id",
1792         FT_UINT16, BASE_HEX, NULL, 0x00,
1793         "Transaction Identifier", HFILL }
1794     },        
1795     { &hf_cops_pc_cmts_ip,
1796       { "CMTS IP Address", "cops.pc_cmts_ip",
1797         FT_UINT32, BASE_HEX, NULL, 0x00,
1798         "CMTS IP Address", HFILL }
1799     },        
1800     { &hf_cops_pc_activity_count,
1801       { "Count", "cops.pc_activity_count",
1802         FT_UINT32, BASE_HEX, NULL, 0x00,
1803         "Count", HFILL }
1804     },        
1805     { &hf_cops_pc_dest_ip,
1806       { "Destination IP Address", "cops.pc_dest_ip",
1807         FT_UINT32, BASE_HEX, NULL, 0x00,
1808         "Destination IP Address", HFILL }
1809     },        
1810     { &hf_cops_pc_gate_id,
1811       { "Gate Identifier", "cops.pc_gate_id",
1812         FT_UINT32, BASE_HEX, NULL, 0x00,
1813         "Gate Identifier", HFILL }
1814     },        
1815     { &hf_cops_pc_max_packet_size,
1816       { "Maximum Packet Size", "cops.pc_max_packet_size",
1817         FT_UINT32, BASE_HEX, NULL, 0x00,
1818         "Maximum Packet Size", HFILL }
1819     },        
1820     { &hf_cops_pc_min_policed_unit,
1821       { "Minimum Policed Unit", "cops.pc_min_policed_unit",
1822         FT_UINT32, BASE_HEX, NULL, 0x00,
1823         "Minimum Policed Unit", HFILL }
1824     },        
1825     { &hf_cops_pc_peak_data_rate,
1826       { "Peak Data Rate", "cops.pc_peak_data_rate",
1827         FT_UINT32, BASE_HEX, NULL, 0x00,
1828         "Peak Data Rate", HFILL }
1829     },        
1830     { &hf_cops_pc_spec_rate,
1831       { "Rate", "cops.pc_spec_rate",
1832         FT_UINT32, BASE_HEX, NULL, 0x00,
1833         "Rate", HFILL }
1834     },        
1835     { &hf_cops_pc_remote_gate_id,
1836       { "Remote Gate ID", "cops.pc_remote_gate_id",
1837         FT_UINT32, BASE_HEX, NULL, 0x00,
1838         "Remote Gate ID", HFILL }
1839     },        
1840     { &hf_cops_pc_reserved,
1841       { "Reserved", "cops.pc_reserved",
1842         FT_UINT32, BASE_HEX, NULL, 0x00,
1843         "Reserved", HFILL }
1844     },        
1845     { &hf_cops_pc_key,
1846       { "Security Key", "cops.pc_key",
1847         FT_UINT32, BASE_HEX, NULL, 0x00,
1848         "Security Key", HFILL }
1849     },        
1850     { &hf_cops_pc_slack_term,
1851       { "Slack Term", "cops.pc_slack_term",
1852         FT_UINT32, BASE_HEX, NULL, 0x00,
1853         "Slack Term", HFILL }
1854     },        
1855     { &hf_cops_pc_src_ip,
1856       { "Source IP Address", "cops.pc_src_ip",
1857         FT_UINT32, BASE_HEX, NULL, 0x00,
1858         "Source IP Address", HFILL }
1859     },        
1860     { &hf_cops_pc_subscriber_id,
1861       { "Subscriber Identifier (IPv4)", "cops.pc_subscriber_id",
1862         FT_UINT32, BASE_HEX, NULL, 0x00,
1863         "Subscriber Identifier (IPv4)", HFILL }
1864     },        
1865     { &hf_cops_pc_token_bucket_rate,
1866       { "Token Bucket Rate", "cops.pc_token_bucket_rate",
1867         FT_UINT32, BASE_HEX, NULL, 0x00,
1868         "Token Bucket Rate", HFILL }
1869     },        
1870     { &hf_cops_pc_token_bucket_size,
1871       { "Token Bucket Size", "cops.pc_token_bucket_size",
1872         FT_UINT32, BASE_HEX, NULL, 0x00,
1873         "Token Bucket Size", HFILL }
1874     }
1875     /* End of addition for PacketCable */
1876
1877   };
1878
1879   /* Setup protocol subtree array */
1880   static gint *ett[] = {
1881     &ett_cops,
1882     &ett_cops_ver_flags,
1883     &ett_cops_obj,
1884     &ett_cops_pr_obj,
1885     &ett_cops_obj_data,
1886     &ett_cops_r_type_flags,
1887     &ett_cops_itf,
1888     &ett_cops_reason,
1889     &ett_cops_decision,
1890     &ett_cops_error,
1891     &ett_cops_clientsi,
1892     &ett_cops_asn1,
1893     &ett_cops_gperror,
1894     &ett_cops_cperror,
1895     &ett_cops_pdp,
1896     &ett_cops_subtree,    
1897   };
1898
1899   module_t* cops_module;
1900
1901   /* Register the protocol name and description */
1902   proto_cops = proto_register_protocol("Common Open Policy Service",
1903       "COPS", "cops");
1904
1905   /* Required function calls to register the header fields and subtrees used */
1906   proto_register_field_array(proto_cops, hf, array_length(hf));
1907   proto_register_subtree_array(ett, array_length(ett));
1908
1909   /* Register our configuration options for cops */
1910   cops_module = prefs_register_protocol(proto_cops, proto_reg_handoff_cops);
1911   prefs_register_uint_preference(cops_module,"tcp.cops_port",
1912                                  "COPS TCP Port",
1913                                  "Set the TCP port for COPS messages",
1914                                  10,&global_cops_tcp_port);
1915   prefs_register_bool_preference(cops_module, "desegment",
1916                                  "Desegment all COPS messages\nspanning multiple TCP segments",
1917                                  "Whether the COPS dissector should desegment all messages spanning multiple TCP segments",
1918                                  &cops_desegment);
1919         
1920   /* For PacketCable */
1921   prefs_register_bool_preference(cops_module, "packetcable",
1922                                  "Decode for PacketCable clients",
1923                                  "Decode the COPS messages using PacketCable clients",
1924                                  &cops_packetcable);
1925         
1926 #ifdef HAVE_NET_SNMP /*enable preference only if compiled with NET-SNMP*/
1927   prefs_register_bool_preference(cops_module, "typefrommib",
1928                                  "Decode COPS-PR ASN.1 types by reading them\nfrom PIBs (converted to MIBs)",
1929                                  "Whether the COPS dissector should decode COPS-PR ASN.1 types based on data types read from packet or PIBs (converted to MIBs)",
1930                                  &cops_typefrommib);
1931 #endif /*HAVE_NET_SNMP*/
1932 }
1933
1934 void proto_reg_handoff_cops(void)
1935 {
1936   static int cops_prefs_initialized = FALSE;
1937   static dissector_handle_t cops_handle;
1938   
1939   if (!cops_prefs_initialized) {
1940     cops_handle = create_dissector_handle(dissect_cops, proto_cops);
1941     cops_prefs_initialized = TRUE;
1942   } else
1943     dissector_delete("tcp.port",cops_tcp_port,cops_handle);
1944   
1945   /* Set our port numbers for future use */
1946   cops_tcp_port = global_cops_tcp_port;
1947   
1948   dissector_add("tcp.port", cops_tcp_port, cops_handle);
1949 }
1950
1951         
1952 /* Additions for PacketCable ( Added by Dick Gooris, Lucent Technologies ) */
1953
1954 /* Definitions for print formatting */
1955 #define   FMT_DEC   0
1956 #define   FMT_HEX   1
1957 #define   FMT_IP    2
1958 #define   FMT_FLT   3
1959
1960 /* Print the translated information in the display gui in a formatted way...
1961  * 
1962  * octets = The number of octets to obtain from the buffer
1963  *
1964  * vsp    = If not a NULL pointer, it points to an array with text, indexed by the obtained value
1965  * 
1966  * mode   = 0 -> print decimal value
1967  *          1 -> print hexadecial vaue
1968  *          2 -> print value as an ip address
1969  *          3 -> print value as an ieee float 
1970  * 
1971  * This function could well be generalized. Using this function in combination with the
1972  * separate function cops_to_subtree() for subtrees, will give great structure to table formatted messages
1973  * like PacketCable cops, and many other protocols.
1974  * 
1975  */
1976
1977 void cops_to_disp_fmt(tvbuff_t *tvb, proto_item *stt, int offset, int octets, char *str, const value_string *vsp, int mode,gint *hf_cops_parameter)
1978 {
1979
1980      guint8   code8  = 0;
1981      guint16  code16 = 0;
1982      guint32  code32 = 0L;
1983      guint32  codeip = 0L;      
1984      float    codefl = 0L;
1985         
1986      /* Print information elements in the specified way */
1987      switch (octets) {
1988              
1989      case 1:
1990              /* Get the octet */
1991              code8 = tvb_get_guint8( tvb, offset );
1992              if (vsp == NULL) {
1993                 /* Hexadecimal format */
1994                 if (mode==FMT_HEX)
1995                    proto_tree_add_uint_format(stt, *hf_cops_parameter,tvb, 
1996                        offset, octets, code8,"%-28s : 0x%02x",str,code8);                   
1997                 else
1998                    /* Print an 8 bits integer */
1999                    proto_tree_add_uint_format(stt, *hf_cops_parameter,tvb, 
2000                        offset, octets, code8,"%-28s : %u",str,code8);
2001              } else {
2002                if (mode==FMT_HEX)
2003                   /* Hexadecimal format */
2004                   proto_tree_add_uint_format(
2005                       stt, *hf_cops_parameter,tvb, offset, octets, code8,
2006                       "%-28s : %s (0x%02x)",str,val_to_str(code8, vsp, "Unknown"),code8);
2007                else
2008                   /* String table indexed */
2009                   proto_tree_add_uint_format(
2010                       stt, *hf_cops_parameter,tvb, offset, octets, code8,
2011                       "%-28s : %s (%u)",str,val_to_str(code8, vsp, "Unknown"),code8);
2012              }
2013              break;
2014
2015        case 2:
2016              
2017              /* Get the next two octets */
2018              code16 = tvb_get_ntohs(tvb,offset);
2019              if (vsp == NULL) {
2020                 /* Hexadecimal format */
2021                 if (mode==FMT_HEX)
2022                    proto_tree_add_uint_format(stt, *hf_cops_parameter,tvb, 
2023                        offset, octets, code16,"%-28s : 0x%04x",str,code16);
2024                 else
2025                    /* Print a 16 bits integer */
2026                    proto_tree_add_uint_format(stt, *hf_cops_parameter,tvb, 
2027                        offset, octets, code16,"%-28s : %u",str,code16);
2028              }  else {
2029                 if (mode==FMT_HEX)
2030                    /* Hexadecimal format */                           
2031                    proto_tree_add_uint_format(stt, *hf_cops_parameter,tvb, 
2032                        offset, octets, code16,"%-28s : %s (0x%04x)", str,
2033                        val_to_str(code16, vsp, "Unknown (0x%04x)"),code16);
2034                 else
2035                    /* Print a 16 bits integer */
2036                    proto_tree_add_uint_format(
2037                        stt, *hf_cops_parameter,tvb, offset, octets, code16,
2038                        "%-28s : %s (%u)",str,val_to_str(code16, vsp, "Unknown (0x%04x)"),code16);
2039              }
2040              break;
2041      
2042         case 4:
2043              
2044              /* Get the next four octets */
2045              switch (mode) {
2046                case FMT_FLT:  codefl  = tvb_get_ntohieee_float(tvb,offset);
2047                               break;
2048                case FMT_IP:   tvb_memcpy(tvb, (guint8 *)&code32, offset, 4);
2049                               codeip  = tvb_get_ntohl(tvb,offset);                   
2050                               break;
2051                default:       code32  = tvb_get_ntohl(tvb,offset);
2052              }
2053               
2054              if (vsp == NULL) {
2055                 /* Hexadecimal format */
2056                 if (mode==FMT_HEX) {
2057                    proto_tree_add_uint_format(stt, *hf_cops_parameter,tvb, 
2058                        offset, octets, code32,"%-28s : 0x%08x",str,code32);
2059                    break;
2060                 } 
2061                 /* Ip address format*/
2062                 if (mode==FMT_IP) {
2063                    proto_tree_add_uint_format(stt, *hf_cops_parameter,tvb, offset,octets,
2064                        codeip,"%-28s : %s",str,ip_to_str((guint8 *)&code32));
2065                    break;
2066                 }
2067                 /* Ieee float format */
2068                 if (mode==FMT_FLT) {
2069                    proto_tree_add_uint_format(stt, *hf_cops_parameter,tvb, offset, octets, 
2070                        codefl,"%-28s : %.10g",str,codefl);
2071                    break;
2072                 }
2073                 /* Print a 32 bits integer */
2074                 proto_tree_add_uint_format(stt, *hf_cops_parameter,tvb, offset, octets, 
2075                     code32,"%-28s : %u",str,code32);
2076              } else {
2077                 /* Hexadecimal format */                   
2078                 if (mode==FMT_HEX)
2079                    proto_tree_add_uint_format(stt, *hf_cops_parameter,tvb, offset, octets, 
2080                            code32,"%-28s : %s (0x%08x)",str,val_to_str(code32, vsp, "Unknown"),code32);
2081                 else
2082                    /* String table indexed */
2083                    proto_tree_add_uint_format(stt, *hf_cops_parameter,tvb, offset, octets, 
2084                        code32,"%-28s : %s (%u)",str,val_to_str(code32, vsp, "Unknown"),code32);
2085              }
2086              break;
2087      
2088         /* In case of more than 4 octets.... */
2089         default: {
2090              if (mode==FMT_HEX)
2091                 proto_tree_add_bytes(stt, *hf_cops_parameter,
2092                    tvb, offset, octets,  tvb_get_ptr(tvb, offset,octets));
2093              else
2094                 proto_tree_add_uint_format(stt, *hf_cops_parameter,
2095                    tvb, offset, octets, code32,"%s",str);
2096              break;
2097         }
2098      }
2099 }
2100
2101 /* Print the subtree information */
2102 proto_tree *cops_to_subtree(tvbuff_t *tvb, proto_tree *st, int n, int offset, char *str) {
2103      proto_item *tv;
2104
2105      tv  = proto_tree_add_uint_format( st, hf_cops_subtree, tvb, offset, n, (guint)NULL, str);
2106      return( proto_item_add_subtree( tv, ett_cops_subtree ) );
2107 }
2108
2109 /* Cops - Section : Transaction ID */
2110 void cops_transaction_id(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2111         
2112      proto_tree *stt;
2113      guint16  code16;
2114      char info[50];
2115
2116      /* Create a subtree */
2117      stt = cops_to_subtree(tvb,st,n,offset,"Transaction ID");
2118
2119      /* Transaction Identifier */
2120      cops_to_disp_fmt(tvb,stt,offset,2,"Transaction Identifier", NULL,FMT_DEC,&hf_cops_pc_transaction_id);
2121      offset +=2;
2122
2123      /* Gate Command Type */
2124      code16 = tvb_get_ntohs(tvb,offset);
2125      proto_tree_add_uint_format(stt, hf_cops_pc_gate_command_type,tvb, offset, 2, 
2126             code16,"%-28s : %s (%u)", "Gate Command Type",
2127             val_to_str(code16,table_cops_transaction_id, "Unknown (0x%04x)"),code16);
2128         
2129      /* Write the right data into the 'info field' on the Gui */
2130      sprintf(info,"COPS %-20s - ",val_to_str(opcode_idx,cops_op_code_vals, "Unknown"));
2131      strcat(info,val_to_str(code16,table_cops_transaction_id, "Unknown"));
2132
2133      if (check_col(cpinfo->cinfo, COL_INFO)) {
2134           col_clear(cpinfo->cinfo, COL_INFO); 
2135           col_add_str(cpinfo->cinfo, COL_INFO,info);
2136      }
2137         
2138 }
2139
2140 /* Cops - Section : Subscriber ID */
2141 void cops_subscriber_id_v4(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2142         
2143      proto_item *tv;
2144         
2145      /* Create a subtree */        
2146      tv = cops_to_subtree(tvb,st,n,offset,"Subscriber ID");
2147
2148      /* Subscriber Identifier */
2149      cops_to_disp_fmt(tvb,tv,offset,4,"Subscriber Identifier (IPv4)", NULL,FMT_IP,&hf_cops_pc_subscriber_id);
2150 }
2151
2152 /* Cops - Section : Gate ID */
2153 void cops_gate_id(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2154         
2155      proto_tree *stt;
2156         
2157      /* Create a subtree */        
2158      stt = cops_to_subtree(tvb,st,n,offset,"Gate ID");
2159         
2160      /* Gate Identifier */
2161      cops_to_disp_fmt(tvb,stt,offset,4,"Gate Identifier", NULL,FMT_HEX,&hf_cops_pc_gate_id);
2162 }
2163
2164 /* Cops - Section : Activity Count */
2165 void cops_activity_count(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2166         
2167      proto_tree *stt;
2168         
2169      /* Create a subtree */        
2170      stt = cops_to_subtree(tvb,st,n,offset,"Activity Count");
2171         
2172      /* Activity Count */
2173      cops_to_disp_fmt(tvb,stt,offset,4,"Count", NULL,FMT_DEC,&hf_cops_pc_activity_count);
2174 }
2175
2176 /* Cops - Section : Gate Specifications */
2177 void cops_gate_specs(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2178         
2179      proto_tree *stt;
2180         
2181      /* Create a subtree */        
2182      stt = cops_to_subtree(tvb,st,n,offset,"Gate Specifications");
2183         
2184      /* Direction */
2185      cops_to_disp_fmt(tvb,stt,offset,1,"Direction",table_cops_direction,FMT_DEC,&hf_cops_pc_direction);
2186      offset += 1;        
2187         
2188      /* Protocol ID */
2189      cops_to_disp_fmt(tvb,stt,offset,1,"Protocol ID",NULL,FMT_DEC,&hf_cops_pc_protocol_id);
2190      offset += 1;
2191         
2192      /* Flags */
2193      cops_to_disp_fmt(tvb,stt,offset,1,"Flags",NULL,FMT_DEC,&hf_cops_pc_gate_spec_flags);
2194      offset += 1;
2195         
2196      /* Session Class */
2197      cops_to_disp_fmt(tvb,stt,offset,1,"Session Class",table_cops_session_class,FMT_DEC,&hf_cops_pc_session_class);
2198      offset += 1;
2199         
2200      /* Source IP Address */
2201      cops_to_disp_fmt(tvb,stt,offset,4,"Source IP Address",NULL,FMT_IP,&hf_cops_pc_src_ip);
2202      offset += 4;
2203         
2204      /* Destination IP Address */
2205      cops_to_disp_fmt(tvb,stt,offset,4,"Destination IP Address",NULL,FMT_IP,&hf_cops_pc_dest_ip);
2206      offset += 4;
2207         
2208      /* Source IP Port */
2209      cops_to_disp_fmt(tvb,stt,offset,2,"Source IP Port",NULL,FMT_DEC,&hf_cops_pc_src_port);
2210      offset += 2;
2211         
2212      /* Destination IP Port */
2213      cops_to_disp_fmt(tvb,stt,offset,2,"Destination IP Port",NULL,FMT_DEC,&hf_cops_pc_dest_port);
2214      offset += 2;
2215         
2216      /* DiffServ Code Point */
2217      cops_to_disp_fmt(tvb,stt,offset,1,"DS Field (DSCP or TOS)",NULL,FMT_HEX,&hf_cops_pc_ds_field);
2218      offset += 1;
2219         
2220      /* 3 octets Not specified */
2221      offset += 3;
2222         
2223      /* Timer T1 Value */
2224      cops_to_disp_fmt(tvb,stt,offset,2,"Timer T1 Value (sec)",NULL,FMT_DEC,&hf_cops_pc_t1_value);
2225      offset += 2;
2226         
2227      /* Reserved */
2228      cops_to_disp_fmt(tvb,stt,offset,2,"Reserved",NULL,FMT_DEC,&hf_cops_pc_reserved);
2229      offset += 2;
2230
2231      /* Timer T7 Value */
2232      cops_to_disp_fmt(tvb,stt,offset,2,"Timer T7 Value (sec)",NULL,FMT_DEC,&hf_cops_pc_t7_value);
2233      offset += 2;
2234         
2235      /* Timer T8 Value */
2236      cops_to_disp_fmt(tvb,stt,offset,2,"Timer T8 Value (sec)",NULL,FMT_DEC,&hf_cops_pc_t8_value);
2237      offset += 2;
2238         
2239      /* Token Bucket Rate */
2240      cops_to_disp_fmt(tvb,stt,offset,4,"Token Bucket Rate",NULL,FMT_FLT,&hf_cops_pc_token_bucket_rate);
2241      offset += 4;
2242         
2243      /* Token Bucket Size */
2244      cops_to_disp_fmt(tvb,stt,offset,4,"Token Bucket Size",NULL,FMT_FLT,&hf_cops_pc_token_bucket_size);
2245      offset += 4;
2246         
2247      /* Peak Data Rate */
2248      cops_to_disp_fmt(tvb,stt,offset,4,"Peak Data Rate",NULL,FMT_FLT,&hf_cops_pc_peak_data_rate);
2249      offset += 4;
2250         
2251      /* Minimum Policed Unit */
2252      cops_to_disp_fmt(tvb,stt,offset,4,"Minimum Policed Unit",NULL,FMT_DEC,&hf_cops_pc_min_policed_unit);
2253      offset += 4;
2254         
2255      /* Maximum Packet Size */
2256      cops_to_disp_fmt(tvb,stt,offset,4,"Maximum Packet Size",NULL,FMT_DEC,&hf_cops_pc_max_packet_size);
2257      offset += 4;
2258         
2259      /* Rate */
2260      cops_to_disp_fmt(tvb,stt,offset,4,"Rate",NULL,FMT_FLT,&hf_cops_pc_spec_rate);
2261      offset += 4;
2262         
2263      /* Slack Term */
2264      cops_to_disp_fmt(tvb,stt,offset,4,"Slack Term",NULL,FMT_DEC,&hf_cops_pc_slack_term);
2265      offset += 4;
2266
2267 }
2268
2269 /* Cops - Section : Remote Gate */
2270 void cops_remote_gate_info(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2271         
2272      proto_tree *stt;
2273         
2274      /* Create a subtree */        
2275      stt = cops_to_subtree(tvb,st,n,offset,"Remote Gate Info");
2276         
2277      /* CMTS IP Address */
2278      cops_to_disp_fmt(tvb,stt,offset,4,"CMTS IP Address", NULL,FMT_IP,&hf_cops_pc_cmts_ip);
2279      offset += 4;
2280         
2281      /* CMTS IP Port */
2282      cops_to_disp_fmt(tvb,stt,offset,2,"CMTS IP Port",NULL,FMT_DEC,&hf_cops_pc_cmts_ip_port);
2283      offset += 2;
2284         
2285      /* Flags */
2286      cops_to_disp_fmt(tvb,stt,offset,2,"Flags",NULL,FMT_DEC,&hf_cops_pc_remote_flags);
2287      offset += 2;
2288
2289      /* Remote Gate ID */
2290      cops_to_disp_fmt(tvb,stt,offset,4,"Remote Gate ID", NULL,FMT_HEX,&hf_cops_pc_remote_gate_id);
2291      offset += 4;
2292
2293      /* Algorithm */
2294      cops_to_disp_fmt(tvb,stt,offset,2,"Algorithm", NULL,FMT_IP,&hf_cops_pc_algorithm);
2295      offset += 2;
2296         
2297      /* Reserved */
2298      cops_to_disp_fmt(tvb,stt,offset,4,"Reserved", NULL,FMT_IP,&hf_cops_pc_reserved);
2299      offset += 4;
2300         
2301      /* Security Key */
2302      cops_to_disp_fmt(tvb,stt,offset,4,"Security Key", NULL,FMT_HEX,&hf_cops_pc_key);
2303      offset += 4;
2304         
2305      /* Security Key */
2306      cops_to_disp_fmt(tvb,stt,offset,4,"Security Key (cont)", NULL,FMT_HEX,&hf_cops_pc_key);
2307      offset += 4;
2308         
2309      /* Security Key */
2310      cops_to_disp_fmt(tvb,stt,offset,4,"Security Key (cont)", NULL,FMT_HEX,&hf_cops_pc_key);
2311      offset += 4;
2312         
2313      /* Security Key */
2314      cops_to_disp_fmt(tvb,stt,offset,4,"Security Key (cont)", NULL,FMT_HEX,&hf_cops_pc_key);
2315 }
2316
2317 /* Cops - Section : PacketCable reason */
2318 void cops_packetcable_reason(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2319         
2320      proto_tree *stt;
2321      guint16  code16;
2322         
2323      /* Create a subtree */        
2324      stt = cops_to_subtree(tvb,st,n,offset,"PacketCable Reason");
2325         
2326      /* Reason Code */
2327      code16 = tvb_get_ntohs(tvb,offset);
2328      proto_tree_add_uint_format(stt, hf_cops_pc_reason_code,tvb, offset, 2, 
2329        code16, "%-28s : %s (%u)","Reason Code",
2330        val_to_str(code16, table_cops_reason_code, "Unknown (0x%04x)"),code16);        
2331      offset += 2;        
2332         
2333      if ( code16 == 0 ) {
2334         /* Reason Sub Code with Delete */
2335         cops_to_disp_fmt(tvb,stt,offset,2,"Reason Sub Code",table_cops_reason_subcode_delete,FMT_DEC,&hf_cops_pc_delete_subcode);
2336      } else {
2337         /* Reason Sub Code with Close */
2338         cops_to_disp_fmt(tvb,stt,offset,2,"Reason Sub Code",table_cops_reason_subcode_close,FMT_DEC,&hf_cops_pc_close_subcode);
2339      }
2340 }
2341
2342 /* Cops - Section : PacketCable error */
2343 void cops_packetcable_error(tvbuff_t *tvb, proto_tree *st, guint n, guint32 offset) {
2344         
2345      proto_tree *stt;
2346         
2347      /* Create a subtree */        
2348      stt = cops_to_subtree(tvb,st,n,offset,"PacketCable Error");
2349         
2350      /* Error Code */
2351      cops_to_disp_fmt(tvb,stt,offset,2,"Error Code",table_cops_packetcable_error,FMT_DEC,&hf_cops_pc_packetcable_err_code);
2352      offset += 2;
2353         
2354      /* Error Sub Code */
2355      cops_to_disp_fmt(tvb,stt,offset,2,"Error Sub Code",NULL,FMT_HEX,&hf_cops_pc_packetcable_sub_code);
2356         
2357 }
2358
2359 /* Analyze the PacketCable objects */
2360 void cops_analyze_packetcable_obj(tvbuff_t *tvb, proto_tree *tree, guint32 offset) {
2361         
2362     gint remdata;
2363     guint16 object_len;
2364     guint8 s_num, s_type;        
2365     
2366     /* Only if this option is enabled by the Gui */
2367     if ( cops_packetcable == FALSE ) {
2368        return;
2369     }
2370         
2371     /* Do the remaining client specific objects */
2372     remdata = tvb_length_remaining(tvb, offset);
2373     while (remdata > 4) {
2374           
2375        /* In case we have remaining data, then lets try to get this analyzed */
2376        object_len   = tvb_get_ntohs(tvb, offset);
2377        s_num        = tvb_get_guint8(tvb, offset + 2);
2378        s_type       = tvb_get_guint8(tvb, offset + 3);
2379           
2380        /* Tune offset */
2381        offset += 4;
2382             
2383        /* Perform the appropriate functions */            
2384        switch (s_num){
2385         case 1:
2386                if (s_type == 1) {
2387                   cops_transaction_id(tvb, tree, object_len, offset);
2388                }
2389                break;               
2390         case 2:
2391                if (s_type == 1) {
2392                   cops_subscriber_id_v4(tvb, tree, object_len, offset);
2393                }
2394                break;               
2395         case 3:
2396                if (s_type == 1) {
2397                   cops_gate_id(tvb, tree, object_len, offset);
2398                }
2399                break;               
2400         case 4:
2401                if (s_type == 1) {
2402                   cops_activity_count(tvb, tree, object_len, offset);
2403                }
2404                break;               
2405         case 5:
2406                if (s_type == 1) {
2407                   cops_gate_specs(tvb, tree, object_len, offset);
2408                }
2409                break;               
2410         case 6:
2411                if (s_type == 1) {
2412                   cops_remote_gate_info(tvb, tree, object_len, offset);
2413                }
2414                break;               
2415         case 9:
2416                if (s_type == 1) {
2417                   cops_packetcable_error(tvb, tree, object_len, offset);
2418                }
2419                break;
2420         case 13:
2421                if (s_type == 1) {
2422                   cops_packetcable_reason(tvb, tree, object_len, offset);
2423                }
2424                break;               
2425        }
2426
2427        /* Tune offset */
2428        offset += object_len-4;
2429
2430        /* See what we can still get from the buffer */
2431        remdata = tvb_length_remaining(tvb, offset);
2432     }
2433 }
2434
2435 /* End of PacketCable Addition */