09feb44f46306f49aea581aa845695bffdf919fa
[obnox/wireshark/wip.git] / packet-cops.c
1 /* packet-cops.c
2  * Routines for the COPS (Common Open Policy Service) protocol dissection
3  * RFC2748
4  *
5  * Copyright 2000, Heikki Vatiainen <hessu@cs.tut.fi>
6  *
7  * $Id: packet-cops.c,v 1.4 2000/08/13 14:08:07 deniel Exp $
8  *
9  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@zing.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * 
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  * 
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 #include <string.h>
37 #include <glib.h>
38 #include "packet.h"
39
40 #define TCP_PORT_COPS 3288
41
42 #define COPS_OBJECT_HDR_SIZE 4
43
44 static const value_string cops_flags_vals[] = {
45         { 0x00,          "None" },
46         { 0x01,          "Solicited Message Flag Bit" },
47         { 0, NULL },
48 };
49
50 /* The different COPS message types */
51 enum cops_op_code {
52         COPS_NO_MSG,          /* Not a COPS Message type     */ 
53
54         COPS_MSG_REQ,         /* Request (REQ)               */
55         COPS_MSG_DEC,         /* Decision (DEC)              */
56         COPS_MSG_RPT,         /* Report State (RPT)          */
57         COPS_MSG_DRQ,         /* Delete Request State (DRQ)  */
58         COPS_MSG_SSQ,         /* Synchronize State Req (SSQ) */
59         COPS_MSG_OPN,         /* Client-Open (OPN)           */
60         COPS_MSG_CAT,         /* Client-Accept (CAT)         */
61         COPS_MSG_CC,          /* Client-Close (CC)           */
62         COPS_MSG_KA,          /* Keep-Alive (KA)             */
63         COPS_MSG_SSC,         /* Synchronize Complete (SSC)  */
64
65         COPS_LAST_OP_CODE     /* For error checking          */
66 };
67
68 static const value_string cops_op_code_vals[] = {
69         { COPS_MSG_REQ,          "Request (REQ)" },
70         { COPS_MSG_DEC,          "Decision (DEC)" },
71         { COPS_MSG_RPT,          "Report State (RPT)" },
72         { COPS_MSG_DRQ,          "Delete Request State (DRQ)" },
73         { COPS_MSG_SSQ,          "Synchronize State Req (SSQ)" },
74         { COPS_MSG_OPN,          "Client-Open (OPN)" },
75         { COPS_MSG_CAT,          "Client-Accept (CAT)" },
76         { COPS_MSG_CC,           "Client-Close (CC)" },
77         { COPS_MSG_KA,           "Keep-Alive (KA)" },
78         { COPS_MSG_SSC,          "Synchronize Complete (SSC)" },
79         { 0, NULL },
80 };
81
82
83 /* The different objects in COPS messages */
84 enum cops_c_num {
85         COPS_NO_OBJECT,        /* Not a COPS Object type               */
86
87         COPS_OBJ_HANDLE,       /* Handle Object (Handle)               */
88         COPS_OBJ_CONTEXT,      /* Context Object (Context)             */
89         COPS_OBJ_IN_INT,       /* In-Interface Object (IN-Int)         */
90         COPS_OBJ_OUT_INT,      /* Out-Interface Object (OUT-Int)       */
91         COPS_OBJ_REASON,       /* Reason Object (Reason)               */
92         COPS_OBJ_DECISION,     /* Decision Object (Decision)           */
93         COPS_OBJ_LPDPDECISION, /* LPDP Decision Object (LPDPDecision)  */
94         COPS_OBJ_ERROR,        /* Error Object (Error)                 */
95         COPS_OBJ_CLIENTSI,     /* Client Specific Information Object (ClientSI) */
96         COPS_OBJ_KATIMER,      /* Keep-Alive Timer Object (KATimer)    */
97         COPS_OBJ_PEPID,        /* PEP Identification Object (PEPID)    */
98         COPS_OBJ_REPORT_TYPE,  /* Report-Type Object (Report-Type)     */
99         COPS_OBJ_PDPREDIRADDR, /* PDP Redirect Address Object (PDPRedirAddr) */
100         COPS_OBJ_LASTPDPADDR,  /* Last PDP Address (LastPDPaddr)       */
101         COPS_OBJ_ACCTTIMER,    /* Accounting Timer Object (AcctTimer)  */
102         COPS_OBJ_INTEGRITY,    /* Message Integrity Object (Integrity) */
103
104         COPS_LAST_C_NUM        /* For error checking                   */
105 };
106
107 static const value_string cops_c_num_vals[] = {
108         { COPS_OBJ_HANDLE,       " Handle Object (Handle)" },
109         { COPS_OBJ_CONTEXT,      " Context Object (Context)" },
110         { COPS_OBJ_IN_INT,       " In-Interface Object (IN-Int)" },
111         { COPS_OBJ_OUT_INT,      " Out-Interface Object (OUT-Int)" },
112         { COPS_OBJ_REASON,       " Reason Object (Reason)" },
113         { COPS_OBJ_DECISION,     " Decision Object (Decision)" },
114         { COPS_OBJ_LPDPDECISION, " LPDP Decision Object (LPDPDecision)" },
115         { COPS_OBJ_ERROR,        " Error Object (Error)" },
116         { COPS_OBJ_CLIENTSI,     " Client Specific Information Object (ClientSI)" },
117         { COPS_OBJ_KATIMER,      " Keep-Alive Timer Object (KATimer)" },
118         { COPS_OBJ_PEPID,        " PEP Identification Object (PEPID)" },
119         { COPS_OBJ_REPORT_TYPE,  " Report-Type Object (Report-Type)" },
120         { COPS_OBJ_PDPREDIRADDR, " PDP Redirect Address Object (PDPRedirAddr)" },
121         { COPS_OBJ_LASTPDPADDR,  " Last PDP Address (LastPDPaddr)" },
122         { COPS_OBJ_ACCTTIMER,    " Accounting Timer Object (AcctTimer)" },
123         { COPS_OBJ_INTEGRITY,    " Message Integrity Object (Integrity)" },
124         { 0, NULL },
125
126 };
127
128 /* Initialize the protocol and registered fields */
129 static gint proto_cops = -1;
130 static gint hf_cops_ver_flags = -1;
131 static gint hf_cops_version = -1;
132 static gint hf_cops_flags = -1;
133
134 static gint hf_cops_op_code = -1;
135 static gint hf_cops_client_type = -1;
136 static gint hf_cops_msg_len = -1;
137
138 static gint hf_cops_obj_len = -1;
139 static gint hf_cops_obj_c_num = -1;
140 static gint hf_cops_obj_c_type = -1;
141
142 /* Initialize the subtree pointers */
143 static gint ett_cops = -1;
144 static gint ett_cops_ver_flags = -1;
145 static gint ett_cops_obj = -1;
146
147 static int dissect_cops_object(tvbuff_t *tvb, guint32 offset, proto_tree *tree);
148
149 /* Code to actually dissect the packets */
150 static void dissect_cops(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
151 {
152         guint8 op_code;
153
154         CHECK_DISPLAY_AS_DATA(proto_cops, tvb, pinfo, tree);
155
156         pinfo->current_proto = "COPS";
157         if (check_col(pinfo->fd, COL_PROTOCOL)) 
158                 col_add_str(pinfo->fd, COL_PROTOCOL, "COPS");
159     
160         op_code = tvb_get_guint8(tvb, 1);
161         if (check_col(pinfo->fd, COL_INFO))
162                 col_add_fstr(pinfo->fd, COL_INFO, "COPS %s",
163                              val_to_str(op_code, cops_op_code_vals, "Unknown Op Code"));
164
165         if (tree) {
166                 proto_item *ti, *tv;
167                 proto_tree *cops_tree, *ver_flags_tree;
168                 guint32 offset, msg_len, carbage;
169                 guint8 ver_flags;
170
171
172                 offset = 0;
173                 ti = proto_tree_add_item(tree, proto_cops, tvb, offset, tvb_length(tvb), FALSE);
174                 cops_tree = proto_item_add_subtree(ti, ett_cops);
175
176                 /* Version and flags share the same byte, put them in a subtree */
177                 ver_flags = tvb_get_guint8(tvb, offset);
178                 tv = proto_tree_add_uint_format(cops_tree, hf_cops_ver_flags, tvb, offset, 1,
179                                                   ver_flags, "Version: %u, Flags: %s",
180                                                   hi_nibble(ver_flags),
181                                                   val_to_str(lo_nibble(ver_flags), cops_flags_vals, "Unknown"));
182                 ver_flags_tree = proto_item_add_subtree(tv, ett_cops_ver_flags);
183                 proto_tree_add_uint(ver_flags_tree, hf_cops_version, tvb, offset, 1, ver_flags);
184                 proto_tree_add_uint(ver_flags_tree, hf_cops_flags, tvb, offset, 1, ver_flags);
185                 offset++;
186
187                 proto_tree_add_uint(cops_tree, hf_cops_op_code, tvb, offset, 1, tvb_get_guint8(tvb, offset));
188                 offset ++;
189                 proto_tree_add_uint(cops_tree, hf_cops_client_type, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
190                 offset += 2;
191
192                 msg_len = tvb_get_ntohl(tvb, offset);
193                 proto_tree_add_uint(cops_tree, hf_cops_msg_len, tvb, offset, 4, tvb_get_ntohl(tvb, offset));
194                 offset += 4;
195
196                 while (msg_len >= COPS_OBJECT_HDR_SIZE) {
197                         int consumed;
198
199                         consumed = dissect_cops_object(tvb, offset, cops_tree);
200                         if (consumed == 0)
201                                 break;
202                         msg_len -= consumed;
203                         offset += consumed;
204                 }
205
206                 carbage = tvb_length_remaining(tvb, offset);
207                 if (carbage != 0)
208                         proto_tree_add_text(cops_tree, tvb, offset, carbage,
209                                             "Trailing carbage: %u byte%s", carbage,
210                                             plurality(carbage, "", "s"));
211         }
212
213         return;
214 }
215
216 static int dissect_cops_object(tvbuff_t *tvb, guint32 offset, proto_tree *tree)
217 {
218         guint16 object_len, contents_len;
219         guint8 c_num, c_type;
220         proto_item *ti;
221         proto_tree *obj_tree;
222
223         if (tvb_length_remaining(tvb, offset) < COPS_OBJECT_HDR_SIZE)
224                 return 0;
225
226         object_len = tvb_get_ntohs(tvb, offset);
227         c_num = tvb_get_guint8(tvb, offset + 2);
228         c_type = tvb_get_guint8(tvb, offset + 3);
229
230         ti = proto_tree_add_uint_format(tree, hf_cops_obj_c_num, tvb, offset, object_len, c_num,
231                                           "Object Type: %s", val_to_str(c_num, cops_c_num_vals, "Unknown"));
232         obj_tree = proto_item_add_subtree(ti, ett_cops_obj);
233
234         proto_tree_add_uint(obj_tree, hf_cops_obj_len, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
235         offset += 2;
236
237         proto_tree_add_uint(obj_tree, hf_cops_obj_c_num, tvb, offset, 1, tvb_get_guint8(tvb, offset));
238         offset++;
239
240         proto_tree_add_uint(obj_tree, hf_cops_obj_c_type, tvb, offset, 1, tvb_get_guint8(tvb, offset));
241         offset++;
242
243         contents_len = object_len - COPS_OBJECT_HDR_SIZE;
244         proto_tree_add_text(obj_tree, tvb, offset, contents_len,
245                             "Object contents: %u bytes", contents_len);
246
247         /* Pad to 32bit boundary */
248         if (object_len % sizeof (guint32))
249                 object_len += (sizeof (guint32) - object_len % sizeof (guint32));
250
251         return object_len;
252         
253 }
254
255 /* Register the protocol with Ethereal */
256 void proto_register_cops(void)
257 {                 
258
259         /* Setup list of header fields */
260         static hf_register_info hf[] = {
261                 { &hf_cops_ver_flags,
262                         { "Version and Flags",           "cops.ver_flags",
263                         FT_UINT8, BASE_HEX, NULL, 0x0,
264                         "Version and Flags in COPS Common Header" }
265                 },
266                 { &hf_cops_version,
267                         { "Version",           "cops.version",
268                         FT_UINT8, BASE_DEC, NULL, 0xF0,
269                         "Version in COPS Common Header" }
270                 },
271                 { &hf_cops_flags,
272                         { "Flags",           "cops.flags",
273                         FT_UINT8, BASE_HEX, VALS(cops_flags_vals), 0x0F,
274                         "Flags in COPS Common Header" }
275                 },
276                 { &hf_cops_op_code,
277                         { "Op Code",           "cops.op_code",
278                         FT_UINT8, BASE_DEC, VALS(cops_op_code_vals), 0x0,
279                         "Op Code in COPS Common Header" }
280                 },
281                 { &hf_cops_client_type,
282                         { "Client Type",           "cops.client_type",
283                         FT_UINT16, BASE_DEC, NULL, 0x0,
284                         "Client Type in COPS Common Header" }
285                 },
286                 { &hf_cops_msg_len,
287                         { "Message Length",           "cops.msg_len",
288                         FT_UINT32, BASE_DEC, NULL, 0x0,
289                         "Message Length in COPS Common Header" }
290                 },
291                 { &hf_cops_obj_len,
292                         { "Object Length",           "cops.obj.len",
293                         FT_UINT32, BASE_DEC, NULL, 0x0,
294                         "Object Length in COPS Object Header" }
295                 },
296                 { &hf_cops_obj_c_num,
297                         { "C-Num",           "cops.obj.c_num",
298                         FT_UINT8, BASE_DEC, VALS(cops_c_num_vals), 0x0,
299                         "C-Num in COPS Object Header" }
300                 },
301                 { &hf_cops_obj_c_type,
302                         { "C-Type",           "cops.obj.c_type",
303                         FT_UINT8, BASE_DEC, NULL, 0x0,
304                         "C-Type in COPS Object Header" }
305                 },
306         };
307
308         /* Setup protocol subtree array */
309         static gint *ett[] = {
310                 &ett_cops,
311                 &ett_cops_ver_flags,
312                 &ett_cops_obj,
313         };
314
315         /* Register the protocol name and description */
316         proto_cops = proto_register_protocol("Common Open Policy Service", "cops");
317
318         /* Required function calls to register the header fields and subtrees used */
319         proto_register_field_array(proto_cops, hf, array_length(hf));
320         proto_register_subtree_array(ett, array_length(ett));
321 };
322
323 void
324 proto_reg_handoff_cops(void)
325 {
326         dissector_add("tcp.port", TCP_PORT_COPS, dissect_cops);
327 }