Witness: enum witness_notifyResponse_type
[wireshark-wip.git] / asn1 / ros / packet-ros-template.c
blob35dfad34da4395bd3dc8972b1bd6f2f0fe1eacce
1 /* packet-ros_asn1.c
2 * Routines for ROS packet dissection
3 * Graeme Lunt 2005
5 * $Id$
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "config.h"
28 #include <glib.h>
29 #include <epan/packet.h>
30 #include <epan/conversation.h>
31 #include <epan/wmem/wmem.h>
32 #include <epan/asn1.h>
33 #include <epan/expert.h>
35 #include "packet-ber.h"
36 #include "packet-pres.h"
37 #include "packet-ros.h"
39 #define PNAME "X.880 OSI Remote Operations Service"
40 #define PSNAME "ROS"
41 #define PFNAME "ros"
43 void proto_register_ros(void);
44 void proto_reg_handoff_ros(void);
46 /* Initialize the protocol and registered fields */
47 static int proto_ros = -1;
49 static proto_tree *top_tree=NULL;
50 static guint32 opcode;
51 static guint32 invokeid;
53 static dissector_handle_t ros_handle = NULL;
55 typedef struct ros_conv_info_t {
56 struct ros_conv_info_t *next;
57 GHashTable *unmatched; /* unmatched operations */
58 GHashTable *matched; /* matched operations */
59 } ros_conv_info_t;
61 static ros_conv_info_t *ros_info_items = NULL;
63 typedef struct ros_call_response {
64 gboolean is_request;
65 guint32 req_frame;
66 nstime_t req_time;
67 guint32 rep_frame;
68 guint invokeId;
69 } ros_call_response_t;
71 static int hf_ros_response_in = -1;
72 static int hf_ros_response_to = -1;
73 static int hf_ros_time = -1;
76 #include "packet-ros-hf.c"
78 /* Initialize the subtree pointers */
79 static gint ett_ros = -1;
80 #include "packet-ros-ett.c"
82 static expert_field ei_ros_dissector_oid_not_implemented = EI_INIT;
83 static expert_field ei_ros_unknown_ros_pdu = EI_INIT;
85 static dissector_table_t ros_oid_dissector_table=NULL;
87 static GHashTable *oid_table=NULL;
88 static GHashTable *protocol_table=NULL;
89 static gint ett_ros_unknown = -1;
91 void
92 register_ros_oid_dissector_handle(const char *oid, dissector_handle_t dissector, int proto _U_, const char *name, gboolean uses_rtse)
94 dissector_add_string("ros.oid", oid, dissector);
95 g_hash_table_insert(oid_table, (gpointer)oid, (gpointer)name);
97 if(!uses_rtse)
98 /* if we are not using RTSE, then we must register ROS with BER (ACSE) */
99 register_ber_oid_dissector_handle(oid, ros_handle, proto, name);
102 void
103 register_ros_protocol_info(const char *oid, const ros_info_t *rinfo, int proto _U_, const char *name, gboolean uses_rtse)
105 g_hash_table_insert(protocol_table, (gpointer)oid, (gpointer)rinfo);
106 g_hash_table_insert(oid_table, (gpointer)oid, (gpointer)name);
108 if(!uses_rtse)
109 /* if we are not using RTSE, then we must register ROS with BER (ACSE) */
110 register_ber_oid_dissector_handle(oid, ros_handle, proto, name);
113 static new_dissector_t ros_lookup_opr_dissector(gint32 opcode_lcl, const ros_opr_t *operations, gboolean argument)
115 /* we don't know what order asn2wrs/module definition is, so ... */
116 if(operations) {
117 for(;operations->arg_pdu != (new_dissector_t)(-1); operations++)
118 if(operations->opcode == opcode_lcl)
119 return argument ? operations->arg_pdu : operations->res_pdu;
122 return NULL;
125 static new_dissector_t ros_lookup_err_dissector(gint32 errcode, const ros_err_t *errors)
127 /* we don't know what order asn2wrs/module definition is, so ... */
128 if(errors) {
129 for(;errors->err_pdu != (new_dissector_t) (-1); errors++) {
130 if(errors->errcode == errcode)
131 return errors->err_pdu;
134 return NULL;
138 static gboolean ros_try_string(const char *oid, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct SESSION_DATA_STRUCTURE* session)
140 ros_info_t *rinfo;
141 gint32 opcode_lcl = 0;
142 const gchar *opname = NULL;
143 const gchar *suffix = NULL;
144 new_dissector_t opdissector = NULL;
145 const value_string *lookup;
146 proto_item *item=NULL;
147 proto_tree *ros_tree=NULL;
149 if((session != NULL) && ((rinfo = (ros_info_t*)g_hash_table_lookup(protocol_table, oid)) != NULL)) {
151 if(tree){
152 item = proto_tree_add_item(tree, *(rinfo->proto), tvb, 0, -1, ENC_NA);
153 ros_tree = proto_item_add_subtree(item, *(rinfo->ett_proto));
156 col_set_str(pinfo->cinfo, COL_PROTOCOL, rinfo->name);
158 /* if this is a bind operation */
159 if((session->ros_op & ROS_OP_TYPE_MASK) == ROS_OP_BIND) {
160 /* use the in-built operation codes */
161 if((session->ros_op & ROS_OP_PDU_MASK) == ROS_OP_ERROR)
162 opcode_lcl = err_ros_bind;
163 else
164 opcode_lcl = op_ros_bind;
165 } else
166 /* otherwise just take the opcode */
167 opcode_lcl = session->ros_op & ROS_OP_OPCODE_MASK;
169 /* default lookup in the operations */
170 lookup = rinfo->opr_code_strings;
172 switch(session->ros_op & ROS_OP_PDU_MASK) {
173 case ROS_OP_ARGUMENT:
174 opdissector = ros_lookup_opr_dissector(opcode_lcl, rinfo->opr_code_dissectors, TRUE);
175 suffix = "_argument";
176 break;
177 case ROS_OP_RESULT:
178 opdissector = ros_lookup_opr_dissector(opcode_lcl, rinfo->opr_code_dissectors, FALSE);
179 suffix = "_result";
180 break;
181 case ROS_OP_ERROR:
182 opdissector = ros_lookup_err_dissector(opcode_lcl, rinfo->err_code_dissectors);
183 lookup = rinfo->err_code_strings;
184 break;
185 default:
186 break;
189 if(opdissector) {
191 opname = val_to_str(opcode_lcl, lookup, "Unknown opcode (%d)");
193 col_set_str(pinfo->cinfo, COL_INFO, opname);
194 if(suffix)
195 col_append_str(pinfo->cinfo, COL_INFO, suffix);
197 (*opdissector)(tvb, pinfo, ros_tree, NULL);
199 return TRUE;
203 return FALSE;
207 call_ros_oid_callback(const char *oid, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, struct SESSION_DATA_STRUCTURE* session)
209 tvbuff_t *next_tvb;
211 next_tvb = tvb_new_subset_remaining(tvb, offset);
213 if(!ros_try_string(oid, next_tvb, pinfo, tree, session) &&
214 !dissector_try_string(ros_oid_dissector_table, oid, next_tvb, pinfo, tree, session)){
215 proto_item *item=proto_tree_add_text(tree, next_tvb, 0, tvb_length_remaining(tvb, offset), "ROS: Dissector for OID:%s not implemented. Contact Wireshark developers if you want this supported", oid);
216 proto_tree *next_tree=proto_item_add_subtree(item, ett_ros_unknown);
218 expert_add_info_format(pinfo, item, &ei_ros_dissector_oid_not_implemented,
219 "ROS: Dissector for OID %s not implemented", oid);
220 dissect_unknown_ber(pinfo, next_tvb, offset, next_tree);
223 /*XXX until we change the #.REGISTER signature for _PDU()s
224 * into new_dissector_t we have to do this kludge with
225 * manually step past the content in the ANY type.
227 offset+=tvb_length_remaining(tvb, offset);
229 return offset;
233 static guint
234 ros_info_hash_matched(gconstpointer k)
236 const ros_call_response_t *key = (const ros_call_response_t *)k;
238 return key->invokeId;
241 static gint
242 ros_info_equal_matched(gconstpointer k1, gconstpointer k2)
244 const ros_call_response_t *key1 = (const ros_call_response_t *)k1;
245 const ros_call_response_t *key2 = (const ros_call_response_t *)k2;
247 if( key1->req_frame && key2->req_frame && (key1->req_frame!=key2->req_frame) ){
248 return 0;
250 /* a response may span multiple frames
251 if( key1->rep_frame && key2->rep_frame && (key1->rep_frame!=key2->rep_frame) ){
252 return 0;
256 return key1->invokeId==key2->invokeId;
259 static guint
260 ros_info_hash_unmatched(gconstpointer k)
262 const ros_call_response_t *key = (const ros_call_response_t *)k;
264 return key->invokeId;
267 static gint
268 ros_info_equal_unmatched(gconstpointer k1, gconstpointer k2)
270 const ros_call_response_t *key1 = (const ros_call_response_t *)k1;
271 const ros_call_response_t *key2 = (const ros_call_response_t *)k2;
273 return key1->invokeId==key2->invokeId;
276 static ros_call_response_t *
277 ros_match_call_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint invokeId, gboolean isInvoke)
279 ros_call_response_t rcr, *rcrp=NULL;
280 ros_conv_info_t *ros_info = ros_info_items;
282 /* first see if we have already matched this */
284 rcr.invokeId=invokeId;
285 rcr.is_request = isInvoke;
287 if(isInvoke) {
288 rcr.req_frame=pinfo->fd->num;
289 rcr.rep_frame=0;
290 } else {
291 rcr.req_frame=0;
292 rcr.rep_frame=pinfo->fd->num;
295 rcrp=(ros_call_response_t *)g_hash_table_lookup(ros_info->matched, &rcr);
297 if(rcrp) {
298 /* we have found a match */
299 rcrp->is_request=rcr.is_request;
301 } else {
303 /* we haven't found a match - try and match it up */
305 if(isInvoke) {
306 /* this a a request - add it to the unmatched list */
308 /* check that we dont already have one of those in the
309 unmatched list and if so remove it */
311 rcr.invokeId=invokeId;
313 rcrp=(ros_call_response_t *)g_hash_table_lookup(ros_info->unmatched, &rcr);
315 if(rcrp){
316 g_hash_table_remove(ros_info->unmatched, rcrp);
319 /* if we cant reuse the old one, grab a new chunk */
320 if(!rcrp){
321 rcrp=wmem_new(wmem_file_scope(), ros_call_response_t);
323 rcrp->invokeId=invokeId;
324 rcrp->req_frame=pinfo->fd->num;
325 rcrp->req_time=pinfo->fd->abs_ts;
326 rcrp->rep_frame=0;
327 rcrp->is_request=TRUE;
328 g_hash_table_insert(ros_info->unmatched, rcrp, rcrp);
329 return NULL;
331 } else {
333 /* this is a result - it should be in our unmatched list */
335 rcr.invokeId=invokeId;
336 rcrp=(ros_call_response_t *)g_hash_table_lookup(ros_info->unmatched, &rcr);
338 if(rcrp){
340 if(!rcrp->rep_frame){
341 g_hash_table_remove(ros_info->unmatched, rcrp);
342 rcrp->rep_frame=pinfo->fd->num;
343 rcrp->is_request=FALSE;
344 g_hash_table_insert(ros_info->matched, rcrp, rcrp);
350 if(rcrp){ /* we have found a match */
351 proto_item *item = NULL;
353 if(rcrp->is_request){
354 item=proto_tree_add_uint(tree, hf_ros_response_in, tvb, 0, 0, rcrp->rep_frame);
355 PROTO_ITEM_SET_GENERATED (item);
356 } else {
357 nstime_t ns;
358 item=proto_tree_add_uint(tree, hf_ros_response_to, tvb, 0, 0, rcrp->req_frame);
359 PROTO_ITEM_SET_GENERATED (item);
360 nstime_delta(&ns, &pinfo->fd->abs_ts, &rcrp->req_time);
361 item=proto_tree_add_time(tree, hf_ros_time, tvb, 0, 0, &ns);
362 PROTO_ITEM_SET_GENERATED (item);
366 return rcrp;
369 #include "packet-ros-fn.c"
372 * Dissect ROS PDUs inside a PPDU.
374 static int
375 dissect_ros(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data)
377 int offset = 0;
378 int old_offset;
379 proto_item *item;
380 proto_tree *tree;
381 proto_tree *next_tree=NULL;
382 conversation_t *conversation;
383 ros_conv_info_t *ros_info = NULL;
384 asn1_ctx_t asn1_ctx;
385 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
387 /* save parent_tree so subdissectors can create new top nodes */
388 top_tree=parent_tree;
390 /* do we have application context from the acse dissector? */
391 if( !data){
392 if(parent_tree){
393 proto_tree_add_text(parent_tree, tvb, offset, -1,
394 "Internal error:can't get application context from ACSE dissector.");
396 return 0;
399 asn1_ctx.private_data = data;
400 conversation = find_or_create_conversation(pinfo);
403 * Do we already have our info
405 ros_info = (ros_conv_info_t *)conversation_get_proto_data(conversation, proto_ros);
406 if (ros_info == NULL) {
408 /* No. Attach that information to the conversation. */
410 ros_info = (ros_conv_info_t *)g_malloc(sizeof(ros_conv_info_t));
411 ros_info->matched=g_hash_table_new(ros_info_hash_matched, ros_info_equal_matched);
412 ros_info->unmatched=g_hash_table_new(ros_info_hash_unmatched, ros_info_equal_unmatched);
414 conversation_add_proto_data(conversation, proto_ros, ros_info);
416 ros_info->next = ros_info_items;
417 ros_info_items = ros_info;
420 item = proto_tree_add_item(parent_tree, proto_ros, tvb, 0, -1, ENC_NA);
421 tree = proto_item_add_subtree(item, ett_ros);
423 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ROS");
424 col_clear(pinfo->cinfo, COL_INFO);
426 while (tvb_reported_length_remaining(tvb, offset) > 0){
427 old_offset=offset;
428 offset=dissect_ros_ROS(FALSE, tvb, offset, &asn1_ctx , tree, -1);
429 if(offset == old_offset){
430 item = proto_tree_add_text(tree, tvb, offset, -1,"Unknown ROS PDU");
432 if(item){
433 expert_add_info(pinfo, item, &ei_ros_unknown_ros_pdu);
434 next_tree=proto_item_add_subtree(item, ett_ros_unknown);
435 dissect_unknown_ber(pinfo, tvb, offset, next_tree);
438 break;
442 return tvb_length(tvb);
445 static void
446 ros_reinit(void)
448 ros_conv_info_t *ros_info;
450 /* Free up state attached to the ros_info structures */
451 for (ros_info = ros_info_items; ros_info != NULL; ) {
452 ros_conv_info_t *last;
454 g_hash_table_destroy(ros_info->matched);
455 ros_info->matched=NULL;
456 g_hash_table_destroy(ros_info->unmatched);
457 ros_info->unmatched=NULL;
459 last = ros_info;
460 ros_info = ros_info->next;
461 g_free(last);
464 ros_info_items = NULL;
468 /*--- proto_register_ros -------------------------------------------*/
469 void proto_register_ros(void) {
471 /* List of fields */
472 static hf_register_info hf[] =
474 { &hf_ros_response_in,
475 { "Response In", "ros.response_in",
476 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
477 "The response to this remote operation invocation is in this frame", HFILL }},
478 { &hf_ros_response_to,
479 { "Response To", "ros.response_to",
480 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
481 "This is a response to the remote operation invocation in this frame", HFILL }},
482 { &hf_ros_time,
483 { "Time", "ros.time",
484 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
485 "The time between the Invoke and the Response", HFILL }},
487 #include "packet-ros-hfarr.c"
490 /* List of subtrees */
491 static gint *ett[] = {
492 &ett_ros,
493 &ett_ros_unknown,
494 #include "packet-ros-ettarr.c"
497 static ei_register_info ei[] = {
498 { &ei_ros_dissector_oid_not_implemented, { "ros.dissector_oid_not_implemented", PI_UNDECODED, PI_WARN, "ROS: Dissector for OID not implemented", EXPFILL }},
499 { &ei_ros_unknown_ros_pdu, { "ros.unknown_ros_pdu", PI_UNDECODED, PI_WARN, "Unknown ROS PDU", EXPFILL }},
502 expert_module_t* expert_ros;
504 /* Register protocol */
505 proto_ros = proto_register_protocol(PNAME, PSNAME, PFNAME);
506 new_register_dissector("ros", dissect_ros, proto_ros);
507 /* Register fields and subtrees */
508 proto_register_field_array(proto_ros, hf, array_length(hf));
509 proto_register_subtree_array(ett, array_length(ett));
510 expert_ros = expert_register_protocol(proto_ros);
511 expert_register_field_array(expert_ros, ei, array_length(ei));
513 ros_oid_dissector_table = register_dissector_table("ros.oid", "ROS OID Dissectors", FT_STRING, BASE_NONE);
514 oid_table=g_hash_table_new(g_str_hash, g_str_equal);
515 protocol_table=g_hash_table_new(g_str_hash, g_str_equal);
517 ros_handle = find_dissector("ros");
519 register_init_routine(ros_reinit);
523 /*--- proto_reg_handoff_ros --- */
524 void proto_reg_handoff_ros(void) {