In a ChangeHosts request, display 4-byte Internet addresses as IPv4
[obnox/wireshark/wip.git] / packet-giop.c
1 /* packet-giop.c
2  * Routines for CORBA GIOP/IIOP packet disassembly
3  *
4  * Initial Code by,
5  * Laurent Deniel <deniel@worldnet.fr>
6  * Craig Rodrigues <rodrigc@mediaone.net>
7  * 
8  * GIOP API extensions by,
9  * Frank Singleton <frank.singleton@ericsson.com>
10  * Trevor Shepherd <eustrsd@am1.ericsson.se>
11  *
12  * $Id: packet-giop.c,v 1.57 2002/02/27 00:30:22 guy Exp $
13  *
14  * Ethereal - Network traffic analyzer
15  * By Gerald Combs <gerald@ethereal.com>
16  * Copyright 1998 Gerald Combs
17  * 
18  * This program is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public License
20  * as published by the Free Software Foundation; either version 2
21  * of the License, or (at your option) any later version.
22  * 
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  * 
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
31  */
32
33
34 /*
35  * TODO: -- FS
36  * 1. heuristic giop dissector table [started]
37  * 2. GUI options, see 20
38  * 3. Remove unneccessary reply_status in heuristic dissector calls (now 
39  *    part of MessageHeader) [done]
40  * 4. get_CDR_xxx should be passed an alignment offset value
41  *    rather than GIOP_HEADER_SIZE, as alignment can also change in a
42  *    octet stream when eg: encapsulation is used [done]
43  * 5. GIOP users should eventually get there own tvbuff, and
44  *    not rely on the GIOP tvbuff, more robust
45  * 6. get_CDR_string,wchar,wstring etc should handle different 
46  *    GIOP versions [started]
47  * 7. Fix situation where req_id is not unique in a logfile [done, use FN/MFN, needs improving.]
48  *
49  * 8. Keep request_1_2 in step with request_1_1 [started]
50  * 9. Explicit module name dissection [done]
51  * 10. Decode IOR and put in a useful struct [IOR decode started]
52  * 11. Fix encapsulation of IOR etc and boundary [done]
53  * 12. handle get_CDR_typeCode() [started]
54  * 13. Handle different IOR profiles
55  * 14. Change printable_string to RETURN a new string, not to modify the old.
56  *     or, new function, make_printable_string [done, make_printable_string]
57  *
58  * 15. Handle "TCKind", and forget about eg: enum translation to symbolic values
59  *     otherwise need knowledge of sub dissectors data - YUK [done]
60  * 16. Handle multiple RepoId representations, besides IDL:Echo:1.0 (see 13.)
61  * 17. Pass subset of RepoID to explicit dissector.
62  *     eg : If IDL:Mod1/Mod2/Int3:1.0 then pass "Mod1/Mode2/Int3" to sub dissector[done]
63  * 18. Better hashing algorithms
64  * 19. Handle hash collision properly .
65  * 20. Allow users to paste a stringified IOR into the GUI, and tie it
66  *     to a sub_dissector.
67  * 21. Add complete_request_packet_list and complete_reply_packet_hash.[done]
68  * 22. Handle case where users click in any order, AND try and match
69  *     REPLY msg to the correct REQUEST msg when we have a request_id collision.[done]
70  * 23. Clean up memory management for all those g_malloc's etc
71  * 24. register_giop_user_module could return a key for every distinct Module/Interface
72  *     the sub_dissector uses. So, instead of strcmp()'s when  handling the
73  *     namespace of an operation, we could have a lookup table instead.
74  * 25. A few typedefs in the right place.
75  * 26  Improve handling of gchar *  and use const gchar * where possible.
76  * 27. Read/write IOR etc to/from file, allows objkey hash to be built from
77  *     external data [read done, write incomplete]
78  * 28. Call sub dissector only if tvb_offset_exists(). [Done, this is checked
79  *     inside try_explicit_giop_dissector() ]
80  *     
81  * 29. Make add/delete routine for objkey hash as it may be useful when say reading 
82  *     stringified IOR's from a file to add them to our hash. ie: There are other ways
83  *     to populate our object key hash besides REPLY's to RESOLVE(request) [done]
84  *
85  * 30. Add routine to encode/decode stringified IOR's [decode done]
86  * 31. Add routine to read IOR's from file [done]
87  * 32. TypeCode -none-, needs decoding.
88  * 33. Complete dissect_data_for_typecode.
89  * 34. For complex TypeCodes need to check final offset against original offset + sequence length.
90  * 35. Update REQUEST/REPLY 1_2 according to IDL (eg; ServiceContextList etc).
91  * 36. Adding decode_ServiceContextList, incomplete. 
92  * 37. Helper functions should not ALWAYS rely on header to find  current endianess. It should
93  *     be passed from user, eg Use   stream_is_big_endian. [started]
94  * 38. Remove unwanted/unused function parameters, see decode_IOR [started]
95  * 40. Add sequence <IOP::TaggedComponent> components to IIOP IOR profile. Perhaps 
96  *     decode_IOP_TaggedComponents as a helper function. [done - NOT helper]
97  *
98  * 41. Make important field searchable from Message header. ie: Remove add_text_
99  * 42. Use sub-tree for decode_ServiceContextList, looks better.
100  * 43. dissect_reply_body, no exception dissector calls
101  *       - call subdiss directly, as we already have handle.
102  *       - add repoid to heuristic call also.
103  *
104  * 44. typedef using xxx_t in .h file.
105  * 45. Subdissectors should not be passed MessageHeader to find endianness and
106  *     version, they should be passed directly ?
107  * 46. get_CDR_wchar and wstring need wide chars decoded (just dumped in
108  *     any readable form at present, not handled well at all, suggestions welcome -- FS
109  * 47. Change ...add_text to ...add_xxx (ie use hf fields).
110  *
111  * 48. BUG - file load with a GIOP filter set, causes the FN/MFN data struct to be
112  *     not initiated properly. Hit "Reload" as a workaround, til I fix this -- FS
113  *
114  */
115
116
117
118 /*
119  * Intended Decode strategy:
120  * =========================
121  *
122  * Initial Pass
123  * ------------
124  * REQUEST: objkey -> Repo_ID -> Module/Interface -> giop_sub_handle_t
125  *          and populate complete_request_packet_hash
126  *
127  * REPLY:   FN -> MFN (via complete_reply_packet_hash) = Request FN -> giop_sub_handle_t
128  *
129  * User Clicks
130  * -----------
131  *
132  * REQUEST: FN -> giop_sub_handle_t directly (via complete_request_packet_hash)
133  *
134  * REPLY:   FN -> MFN (via complete_reply_packet_hash) = Request FN -> giop_sub_handle_t
135  *                                                                     (via complete_request_packet_hash
136  *
137  *
138  * Limitations. 
139  * ============
140  *
141  * 1. Request_ID's are unique only per connection.
142  *
143  * 2. You must be monitoring the network when the client does
144  *    a REQUEST(resolve), otherwise I have no knowledge of the
145  *    association between object_key and REPOID. I could talk to 
146  *    a Nameserver, but then I would start "generating" packets.
147  *    This is probably not a good thing for a protocol analyser.
148  *    Also, how could I decode logfiles offline.
149  *
150  *    TODO -- Read stringified IORs from an input file.[done]
151  *
152  * 3. User clicks (REQUEST) is currently handle the same as
153  *    the initial pass handling.
154  *
155  *    ie: objkey -> Repo_ID -> Module/Interface -> giop_sub_handle_t
156  */
157
158
159 /*
160  * Important Data Structures:
161  *
162  * giop_module_hash 
163  * ----------------
164  *
165  * This is a hash table that maps IDL Module/Interface Names (Key)
166  * to sub_dissector handles, giop_sub_handle_t. It is populated
167  * by subdissectors, via register_giop_user_module(). This
168  * table is used when we have a REPOID, and explicitly wish to
169  * call the subdissector that has registered responsibility for
170  * that IDL module/interface.
171  *
172  * 
173  * giop_sub_list
174  * -------------
175  *
176  * This singly linked list is used to hold entries for
177  * heuristic based subdissectors. It is populated by sub_dissectors
178  * wishing to be called via heuristic mechanisms. They do this
179  * via the register_giop_user() function.
180  *
181  * 
182  * giop_objkey_hash
183  * ----------------
184  *
185  * This hash table maps object_key's (key) onto REPOID's (val).
186  * Once a client has REQUEST(resolve) an object , it knows about
187  * an object (interface) via its object_key (see IOR). So in order to follow
188  * packets that contain an object_key only, and to be able to forward it
189  * to the correct explicit subdissector, we need this table.
190  *
191  * So, I listen in on REQUEST(resolve) messages between client and
192  * Nameserver, and store the respones (REPLY/Objkey,Repo_ID) here.
193  *
194  * Also, stringified IOR's can be read from a file "IOR.txt" and used
195  * to populate  this hash also.
196  *
197  *
198  * Other Data structures 
199  * =======================
200  *
201  * These structures have  been added to minimise the possibility
202  * of incorrectly interpreted packets when people click all
203  * over the place, in no particular order, when the request_id's are
204  * not unique as captured. If all request_is'd are unique, as captured, then
205  * we would not have to deal with this problem.
206  *
207  *
208  * When the logfile or packets are initially being processed, I will
209  * build 2 structures. The intent is to be able to map a REPLY message
210  * back to the most recent REQUEST message with the same Request_ID
211  * (TODO and matching port and IP address ??)
212  * 
213  * Abbrevs:
214  * --------
215  *
216  * FN  - Frame Number
217  * MFN - Matching Frame Number
218  *
219  *
220  * complete_request_packet_list
221  * ----------------------------
222  *
223  * This is a list that contains ALL the FN's that are REQUEST's, along with 
224  * operation,request_id and giop_sub_handle_t
225  *
226  * complete_reply_packet_hash
227  * --------------------------
228  *
229  * This is a hash table. It is populated with FN (key) and MFN (val).
230  * This allows me to handle the case, where if you click on any REPLY
231  * message, I can lookup the matching request. This can improve
232  * the match rate between REQUEST and REPLY when people click in
233  * any old fashion, but is NOT foolproof. 
234  *
235  * The algorithm I use to populate this hash during initial pass,
236  * is as follows. 
237  *
238  * If packet is a REPLY, note the reqid, and then traverse backwards
239  * through the complete_request_packet_list from its tail, looking
240  * for a FN that has the same Request_id. Once found, take the found FN
241  * from complete_reply_packet_hash, and insert it into the MFN field
242  * of the complete_reply_packet_hash.
243  *
244  *
245  * See TODO for improvements to above algorithm.
246  *
247  * So now when people click on a REQUEST packet, I can call lookup the
248  * giop_sub_handle_t directly from complete_request_packet_list.
249  *
250  * And, when they click on a REPLY, I grab the MFN of this FN from
251  * complete_reply_packet_hash, then look that up in the complete_request_packet_list
252  * and call the sub_dissector directly.
253  *
254  * So, how do I differentiate between the initial processing of incoming
255  * packets, and a user clickin on one ? Good question.
256  *
257  * I leverage the pinfo_fd->flags.visited  on a per frame
258  * basis. 
259  *
260  * To quote from the ever helpful development list
261  *
262  * " When a capture file is initially loaded, all "visited" flags
263  * are 0. Ethereal then makes the first pass through file,
264  * sequentially dissecting each packet. After the packet is
265  * dissected the first time, "visited" is 1. (See the end of
266  * dissect_packet() in epan/packet.c; that's the code that
267  * sets "visited" to 1).
268
269  * By the time a user clicks on a packet, "visited" will already
270  * be 1 because Ethereal will have already done its first pass
271  * through the packets.
272
273  * Reload acts just like a normal Close/Open, except that it
274  * doesn't need to ask for a filename. So yes, the reload button
275  * clears the flags and re-dissects the file, just as if the file
276  * had been "opened".  "
277  *
278  */
279
280
281 #ifdef HAVE_CONFIG_H
282 # include "config.h"
283 #endif
284
285 #ifdef HAVE_SYS_TYPES_H
286 # include <sys/types.h>
287 #endif
288
289 #include <string.h>
290 #include <stdio.h>
291 #include <errno.h>
292 #include <ctype.h>
293 #include <glib.h>
294 #include <math.h>
295 #ifdef NEED_STRERROR_H
296 #include "strerror.h"
297 #endif
298
299 #include <epan/packet.h>
300 #include "packet-giop.h"
301
302 /*
303  * This affects how we handle context_data inside ServiceContext structs.
304  * According to CORBA 2.4.2,  Context data is encapsulated in octet sequences,
305  * but so far I haven't seen the that on the wire. But, maybe its me -- FS 
306  *
307  */
308
309 #define CONTEXT_DATA_IS_ENCAPSULATED  0
310
311
312 /*
313  * Set to 1 for DEBUG output - TODO make this a runtime option
314  */
315
316 #define DEBUG   0
317
318
319
320 /*
321  * ------------------------------------------------------------------------------------------+ 
322  *                                 Private Helper function Declarations
323  * ------------------------------------------------------------------------------------------+
324  */
325
326
327 static void decode_IIOP_IOR_profile(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
328                                     guint32 boundary, gboolean new_endianess, gchar *repobuf,
329                                     gboolean store_flag);
330
331 static void decode_ServiceContextList(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
332                                       gboolean stream_is_be, guint32 boundary);
333
334 static void decode_TaggedProfile(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
335                                  guint32 boundary, gboolean stream_is_big_endian, gchar *repobuf);
336
337 static void decode_IOR(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
338                        guint32 boundary, gboolean stream_is_big_endian );
339
340 static void decode_SystemExceptionReplyBody (tvbuff_t *tvb, proto_tree *tree, gint *offset,
341                                              gboolean stream_is_big_endian,
342                                              guint32 boundary);
343
344 static void dissect_tk_objref_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
345                                      gboolean stream_is_big_endian, guint32 boundary,
346                                      MessageHeader * header);
347
348 static void dissect_tk_struct_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
349                                      gboolean stream_is_big_endian, guint32 boundary,
350                                      MessageHeader * header);
351
352 static void dissect_tk_union_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
353                                     gboolean stream_is_big_endian, guint32 boundary,
354                                     MessageHeader * header );
355  
356 static void dissect_tk_enum_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
357                                    gboolean stream_is_big_endian, guint32 boundary,
358                                    MessageHeader * header);
359
360 static void dissect_tk_sequence_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
361                                        gboolean stream_is_big_endian, guint32 boundary,
362                                        MessageHeader * header);
363
364 static void dissect_tk_array_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
365                                     gboolean stream_is_big_endian, guint32 boundary,
366                                     MessageHeader * header);
367
368 static void dissect_tk_alias_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
369                                     gboolean stream_is_big_endian, guint32 boundary,
370                                     MessageHeader * header);
371
372 static void dissect_tk_except_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
373                                      gboolean stream_is_big_endian, guint32 boundary,
374                                      MessageHeader * header);
375
376 static void dissect_tk_value_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
377                                     gboolean stream_is_big_endian, guint32 boundary,
378                                     MessageHeader * header);
379
380 static void dissect_tk_value_box_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
381                                         gboolean stream_is_big_endian, guint32 boundary,
382                                         MessageHeader * header);
383
384 static void dissect_tk_native_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
385                                      gboolean stream_is_big_endian, guint32 boundary,
386                                      MessageHeader * header);
387
388 static void dissect_tk_abstract_interface_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
389                                                  gboolean stream_is_big_endian, guint32 boundary,
390                                                  MessageHeader * header);
391
392
393 static void dissect_typecode_string_param(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
394                                           gboolean new_stream_is_big_endian, guint32 new_boundary, int hf_id );
395
396 static void dissect_data_for_typecode(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
397                                       gboolean stream_is_big_endian, guint32 boundary,
398                                       MessageHeader * header, guint32 data_type );
399
400
401
402
403 /*
404  * ------------------------------------------------------------------------------------------+ 
405  *                                 Data/Variables/Structs
406  * ------------------------------------------------------------------------------------------+
407  */
408
409
410 static int proto_giop = -1;
411 static int hf_giop_message_type = -1;
412 static int hf_giop_message_size = -1;
413 static int hf_giop_repoid = -1;
414 static int hf_giop_string_length = -1;
415 static int hf_giop_sequence_length = -1;
416 static int hf_giop_profile_id = -1;
417 static int hf_giop_type_id = -1;
418 static int hf_giop_iiop_v_maj = -1;
419 static int hf_giop_iiop_v_min = -1;
420 static int hf_giop_endianess = -1; /* esp encapsulations */
421 static int hf_giop_IOR_tag = -1; 
422 static int hf_giop_IIOP_tag = -1;
423
424 static int hf_giop_TCKind = -1;
425 static int hf_giop_typecode_count = -1;
426 static int hf_giop_typecode_default_used = -1;
427 static int hf_giop_typecode_digits = -1;
428 static int hf_giop_typecode_length = -1;
429 static int hf_giop_typecode_max_length = -1;
430 static int hf_giop_typecode_member_name = -1;
431 static int hf_giop_typecode_name = -1;
432 static int hf_giop_typecode_scale = -1;
433 static int hf_giop_typecode_ValueModifier = -1;
434 static int hf_giop_typecode_Visibility = -1;
435
436 static int hf_giop_type_boolean = -1;
437 static int hf_giop_type_char = -1;
438 static int hf_giop_type_double = -1;
439 static int hf_giop_type_enum = -1;
440 static int hf_giop_type_float = -1;
441 static int hf_giop_type_long = -1;
442 static int hf_giop_type_octet = -1;
443 static int hf_giop_type_short = -1;
444 static int hf_giop_type_string = -1;
445 static int hf_giop_type_ulong = -1;
446 static int hf_giop_type_ushort = -1;
447
448 static int hf_giop_iiop_host = -1; 
449 static int hf_giop_iiop_port = -1; 
450 static int hf_giop_iop_vscid = -1;
451 static int hf_giop_iop_scid = -1;
452
453 /*
454  * (sub)Tree declares
455  */
456
457 static gint ett_giop = -1;
458 static gint ett_giop_reply = -1;
459 static gint ett_giop_request = -1;
460 static gint ett_giop_cancel_request = -1;
461 static gint ett_giop_locate_request = -1;
462 static gint ett_giop_locate_reply = -1;
463 static gint ett_giop_fragment = -1;
464
465 static gint ett_giop_scl = -1;  /* ServiceContextList */
466 static gint ett_giop_ior = -1;  /* IOR  */
467
468 static dissector_handle_t data_handle;
469 /* GIOP endianess */
470
471 static const value_string giop_endianess_vals[] = {
472   { 0x0, "Big Endian" },
473   { 0x1, "Little Endian" },
474   { 0, NULL}
475 };
476
477 static const value_string sync_scope[] = {
478         { 0x0, "SYNC_NONE" },
479         { 0x1, "SYNC_WITH_TRANSPORT"},
480         { 0x2, "SYNC_WITH_SERVER"},
481         { 0x3, "SYNC_WITH_TARGET"},
482         { 0, NULL}
483 };
484
485 /* Profile ID's */
486
487 static const value_string profile_id_vals[] = {
488         { 0x0, "TAG_INTERNET_IOP" },
489         { 0x1, "TAG_MULTIPLE_COMPONENTS"},
490         { 0x2, "TAG_SCCP_IOP"},
491         { 0, NULL}
492 };
493
494 static const value_string giop_message_types[] = {
495         { 0x0, "Request" },
496         { 0x1, "Reply"},
497         { 0x2, "CancelRequest"},
498         { 0x3, "LocateRequest"},
499         { 0x4, "LocateReply"},
500         { 0x5, "CloseConnection"},
501         { 0x6, "MessageError"},
502         { 0x7, "Fragment"},
503         { 0, NULL}
504 };
505
506 static const value_string giop_locate_status_types[] = {
507         { 0x0, "Unknown Object" },
508         { 0x1, "Object Here"},
509         { 0x2, "Object Forward"},
510         { 0x3, "Object Forward Perm"},
511         { 0x4, "Loc System Exception"},
512         { 0x5, "Loc Needs Addressing Mode"},
513         { 0, NULL }     
514 };
515
516 static const value_string tckind_vals[] = {
517   { 0, "tk_null"},
518   { 1, "tk_void"},
519   { 2, "tk_short"},
520   { 3, "tk_long"},
521   { 4, "tk_ushort"},
522   { 5, "tk_ulong"},
523   { 6, "tk_float"},
524   { 7, "tk_double"},
525   { 8, "tk_boolean"},
526   { 9, "tk_char"},
527   { 10, "tk_octet"},
528   { 11, "tk_any"},
529   { 12, "tk_TypeCode"},
530   { 13, "tk_Principal"},
531   { 14, "tk_objref"},
532   { 15, "tk_struct"},
533   { 16, "tk_union"},
534   { 17, "tk_enum"},
535   { 18, "tk_string"},
536   { 19, "tk_sequence"},
537   { 20, "tk_array"},
538   { 21, "tk_alias"},
539   { 22, "tk_except"},
540   { 23, "tk_longlong"},
541   { 24, "tk_ulonglong"},
542   { 25, "tk_longdouble"},
543   { 26, "tk_wchar"},
544   { 27, "tk_wstring"},
545   { 28, "tk_fixed"},
546   { 29, "tk_value"},
547   { 30, "tk_value_box"},
548   { 31, "tk_native"},
549   { 32, "tk_abstract_interface"},
550   { 0, NULL }   
551 };
552
553
554
555 #define GIOP_MAGIC       "GIOP"
556
557 /*
558  * TAGS for IOR Profiles
559  *
560  * Chapter 13 Corba 2.4.2
561  *
562  */
563
564 #define IOP_TAG_INTERNET_IOP          0
565 #define IOP_TAG_MULTIPLE_COMPONENTS   1
566
567
568 /* Max Supported versions */
569
570 static const guint GIOP_MAJOR =  1;
571 static const guint GIOP_MINOR =  2;
572
573
574 static const int KeyAddr       = 0;
575 static const int ProfileAddr   = 1;
576 static const int ReferenceAddr = 2;
577
578
579
580 static const value_string reply_status_types[] = { 
581    { NO_EXCEPTION, "No Exception" } ,
582    { USER_EXCEPTION, "User Exception" } ,
583    { SYSTEM_EXCEPTION, "System Exception" } ,
584    { LOCATION_FORWARD, "Location Forward" } ,
585    { LOCATION_FORWARD_PERM, "Location Forward Perm" } ,
586    { NEEDS_ADDRESSING_MODE, "Needs Addressing Mode" } ,
587    { 0, NULL }
588 };
589
590
591
592 typedef enum LocateStatusType
593 {
594   UNKNOWN_OBJECT,
595   OBJECT_HERE,
596   OBJECT_FORWARD,
597   OBJECT_FORWARD_PERM,      /* new value for GIOP 1.2 */
598   LOC_SYSTEM_EXCEPTION,     /* new value for GIOP 1.2 */
599   LOC_NEEDS_ADDRESSING_MODE /* new value for GIOP 1.2 */
600 }
601 LocateStatusType_t;
602
603 typedef struct LocateReplyHeader
604 {
605   guint32 request_id;
606   guint32 locate_status;
607 }
608 LocateReplyHeader_t;
609
610
611 /*
612  * DATA - complete_request_list 
613  */
614
615 static GList *giop_complete_request_list;
616
617 struct comp_req_list_entry {
618   guint32 fn;                   /* frame number */
619   gchar * operation;            /* echo echoString */
620   giop_sub_handle_t *subh;      /* handle to sub dissector */
621   guint32 reqid;                /* request id */  
622   gchar * repoid;               /* repository ID */
623 };
624
625 typedef struct comp_req_list_entry comp_req_list_entry_t;
626
627
628 /*
629  * DATA - complete_reply_hash
630  *
631  * Maps reply FN to request MFN
632  */
633
634 static int complete_reply_hash_count = 1000; /* storage size for our permanent data */
635                                              /* ie: 1000 entries -- needs tweaking -- FS */
636
637 struct complete_reply_hash_key {
638   guint32 fn;                   /* reply frame number  */
639 };
640
641 struct complete_reply_hash_val {
642   guint32 mfn;                  /* matching frame number (request)  */
643 };
644
645 GHashTable *giop_complete_reply_hash = NULL; /* hash */
646 GMemChunk  *giop_complete_reply_keys = NULL; /* key storage */
647 GMemChunk  *giop_complete_reply_vals = NULL; /* val storage */
648
649
650 /*
651  * DATA - Module Hash stuff to store data from register_giop_user_module
652  *
653  * ie: module (or interface ?) name, and ptr to sub_dissector handle
654  *
655  * With this knowledge, we can call a sub dissector directly, 
656  * by :
657  * 
658  * objkey -> repoid -> sub_dissector via registered module/interface
659  *
660  */
661
662
663 static int giop_module_init_count = 100; /* storage size for our permanent data */
664                                          /* ie: 100 entries -- needs tweaking -- FS */
665
666 struct giop_module_key {
667   gchar *module;                /* module (interface?) name  */
668 };
669
670 struct giop_module_val {
671   giop_sub_handle_t *subh;      /* handle to sub dissector */
672 };
673
674 GHashTable *giop_module_hash = NULL; /* hash */
675 GMemChunk  *giop_module_keys = NULL; /* key storage */
676 GMemChunk  *giop_module_vals = NULL; /* val storage */
677
678
679 /*
680  * DATA - GSList to store list of function (dissector) pointers.
681  * for heuristic dissection.
682  *
683  */
684
685 static GSList *giop_sub_list = NULL;
686
687 /*
688  * DATA - Hash stuff to follow request/reply. This is so if we get a REPLY
689  * to a REQUEST (resolve), we can dump/store the RepoId and Object Key.
690  *
691  * With this knowledge, we can call a sub dissector directly later
692  * by :
693  * 
694  * objkey -> repoid -> sub_dissector via registered module/interface
695  *
696  * rather than heuristic calls that do not provide operation context.
697  * (unless we pass the RepoID for a given objkey -- hmmm)
698  *
699  */
700
701 /*
702  * Interesting operation list, add more if you want to save
703  * interesting data.
704  */
705
706 static const char  giop_op_resolve[]           = "resolve";
707 static const char  giop_op_bind_new_context[]  = "bind_new_context";
708 static const char  giop_op_bind[]              = "bind";
709
710 /*
711  * Enums  for interesting local operations, that we may need to monitor
712  * with their subsequent replies
713  * 
714  */
715
716 enum giop_op_val {
717   request_resolve_op_val,            /* REQUEST (resolve) to get RepoID etc*/
718   request_bind_new_context_op_val,   /* bind_new_context */
719   request_bind_op_val,               /* bind */
720   request_get_INIT_op_val,           /* finding Nameserver */
721
722 };
723
724
725 /*
726  * hash for mapping object keys onto object namespaces, so
727  * I can call the correct dissector.
728  *
729  *
730  */
731
732 /*
733  * Where did I get the IOR from.
734  */
735
736 enum ior_src {
737   req_res = 0,                  /* REQUEST (resolve) */
738   file,                         /* stringified IOR' in a file */
739
740 };
741
742 typedef enum ior_src ior_src_t;
743
744
745
746 /*
747  * Enums for my lists and hash's 
748  */
749
750 enum collection_data {
751   cd_heuristic_users = 0,
752   cd_module_hash,
753   cd_objkey_hash,
754   cd_complete_request_list,
755   cd_complete_reply_hash
756 };
757
758 typedef enum collection_data collection_data_t;
759
760
761
762 static int giop_objkey_init_count = 100; /* storage size for our permanent data */
763                                          /* ie: 100 entries -- needs tweaking -- FS */
764
765 struct giop_object_key {
766   guint8 *objkey;               /* ptr to object key */
767   guint32 objkey_len;           /* length */
768 };
769
770 struct giop_object_val { 
771   guint8 *repo_id;              /* ptr to Repository ID string */
772   ior_src_t src;                /* where did Iget this IOR from */
773 };
774
775 GHashTable *giop_objkey_hash = NULL; /* hash */
776 GMemChunk  *giop_objkey_keys = NULL; /* key storage */
777 GMemChunk  *giop_objkey_vals = NULL; /* val storage */
778
779
780
781 /*
782  * ------------------------------------------------------------------------------------------+ 
783  *                                 Private helper functions
784  * ------------------------------------------------------------------------------------------+
785  */
786
787
788
789 /*
790  * Insert FN,reqid,operation and sub handle in list. DOES not check for duplicates yet.
791  */
792
793 static GList *insert_in_comp_req_list(GList *list, guint32 fn, guint32 reqid, gchar * op, giop_sub_handle_t *sh ) {
794   GList * newlist_start;
795   comp_req_list_entry_t * entry = NULL;
796   gchar * opn;
797
798   entry =  g_malloc(sizeof(comp_req_list_entry_t));
799   opn =  g_strdup(op); /* duplicate operation for storage */
800     
801   entry->fn = fn;
802   entry->reqid = reqid;
803   entry->subh = sh;             
804   entry->operation = opn;       
805   entry->repoid = NULL;         /* dont have yet */
806
807   newlist_start = g_list_append (list, entry); /* append */
808
809   return newlist_start;
810 }
811
812
813 /*
814  * Used to find an entry with matching Frame Number FN
815  * in the complete_request_list list.
816  */
817
818 static comp_req_list_entry_t * find_fn_in_list(guint32 fn) {
819
820   GList * element;              /*  entry in list */
821   comp_req_list_entry_t * entry_ptr = NULL;
822   
823   element = g_list_last(giop_complete_request_list); /* start from  last  */
824   
825   while(element) {                      /* valid list entry */
826     entry_ptr = element->data;  /* grab data pointer */
827     if (entry_ptr->fn == fn) {  /* similar FN  */
828       return entry_ptr;
829     }    
830     element = g_list_previous(element); /* try next previous */
831   }
832   
833   return NULL;                  /* no match so return NULL */
834 }
835
836
837 /*
838  * Add/update a sub_dissector handle and repoid to a FN entry in the complete_request_list
839  *
840  * Call this when you know a FN and matching giop_sub_handle_t and repoid
841  *
842  * This is done in say, try_explicit_dissector for example.
843  *
844  */
845
846 static void add_sub_handle_repoid_to_comp_req_list(guint32 fn, giop_sub_handle_t *sh, gchar *repoid ) {
847
848   comp_req_list_entry_t * entry = NULL;
849   entry = find_fn_in_list(fn);  /* grab FN data entry */
850
851   if (entry) {
852     entry->subh = sh;           
853     entry->repoid = g_strdup(repoid); /* copy and store */
854
855   }
856 }
857
858
859
860
861 /* giop_complete_reply_hash  "EQUAL" Functions */
862
863 static gint complete_reply_equal_fn(gconstpointer v, gconstpointer w) {
864   struct complete_reply_hash_key *mk1 = (struct complete_reply_hash_key *)v;
865   struct complete_reply_hash_key *mk2 = (struct complete_reply_hash_key *)w;
866
867   if (mk1->fn == mk2->fn) {    
868     return 1;
869   }
870
871   return 0;                     /* found  differences */
872 }
873
874 /* giop_complete_reply_hash "HASH" Functions */
875
876 static guint32 complete_reply_hash_fn(gconstpointer v) {
877   guint32 val;          /* init hash value */
878   struct complete_reply_hash_key *key = (struct complete_reply_hash_key *)v;
879
880   val = key->fn;                /* simple and unique */
881
882   return val;
883 }
884
885
886 /*
887  * Insert the FN and MFN together in our complete_reply_hash.
888  */
889
890 static void insert_in_complete_reply_hash(guint32 fn, guint32 mfn) {
891
892   struct complete_reply_hash_key key, *new_key;
893   struct complete_reply_hash_val *val = NULL;
894
895   key.fn = fn;
896
897   val = (struct complete_reply_hash_val *)g_hash_table_lookup(giop_complete_reply_hash, &key);
898
899   if (val) {
900     return;                     /* FN collision */
901   }
902
903   new_key = g_mem_chunk_alloc(giop_complete_reply_keys);
904   new_key->fn = fn;             /* save FN */
905
906   val = g_mem_chunk_alloc(giop_complete_reply_vals);
907   val->mfn = mfn;               /* and MFN */
908   
909   g_hash_table_insert(giop_complete_reply_hash, new_key, val);
910
911 }
912
913 /*
914  * Find the MFN values from a given FN key.
915  * Assumes the complete_reply_hash is already populated.
916  */
917
918 static guint32 get_mfn_from_fn(guint32 fn) {
919
920   struct complete_reply_hash_key key;
921   struct complete_reply_hash_val *val = NULL;
922   guint32 mfn = fn;             /* save */
923
924   key.fn = fn;
925   val = (struct complete_reply_hash_val *)g_hash_table_lookup(giop_complete_reply_hash, &key);
926
927   if (val) {
928     mfn = val->mfn;             /* grab it */
929   }
930   
931   return mfn;                   /* mfn or fn if not found */
932
933 }
934
935 /*
936  * Attempt to find the MFN for this FN, and return it.
937  * Return MFN if found, or just FN if not. This is
938  * only used when we are building
939  */
940
941 static guint32 get_mfn_from_fn_and_reqid(guint32 fn, guint32 reqid) {
942
943   GList * element;              /* last entry in list */
944   comp_req_list_entry_t * entry_ptr = NULL;
945
946   /* Need Some pretty snappy code */
947   
948   /* Loop back from current end of complete_request_list looking for */
949   /* a FN with the same reqid -- TODO enhance with port/address checks -- FS */
950
951   /*
952    * As this routine is only called during initial pass of data,
953    * and NOT when a user clicks, it is ok to start from Current
954    * end of complete_request_list when searching for a match.
955    * As that list is bing populated in the same order as FN's
956    * are being read.
957    *
958    * Also, can make check for same reqid more detailed, but I start
959    * with reqid. Could add say port or address checks etc later ??
960    */
961
962
963   element = g_list_last(giop_complete_request_list); /* get last  */
964   
965   while(element) {                      /* valid list entry */
966     entry_ptr = element->data;  /* grab data pointer */
967     if (entry_ptr->reqid == reqid) {    /* similar reqid  */
968       return entry_ptr->fn;     /* return MFN */
969     }    
970     element = g_list_previous(element); /* try next previous */
971   }
972   
973   return fn;                    /* no match so return FN */
974 }
975
976
977 /* Module Hash "EQUAL" Functions */
978
979 static gint giop_hash_module_equal(gconstpointer v, gconstpointer w) {
980   struct giop_module_key *mk1 = (struct giop_module_key *)v;
981   struct giop_module_key *mk2 = (struct giop_module_key *)w;
982   
983   if (!strcmp(mk1->module, mk2->module)) {    
984     return 1;
985   }
986
987   return 0;                     /* found  differences */
988 }
989
990 /* Module Hash "HASH" Functions */
991
992 static guint32 giop_hash_module_hash(gconstpointer v) {
993   
994   int i,len;
995   guint32 val = 0;              /* init hash value */
996
997   struct giop_module_key *key = (struct giop_module_key *)v;
998   
999   /*
1000    * Hmm, try this simple hashing scheme for now.
1001    * ie: Simple summation, FIX later -- FS
1002    *
1003    *
1004    */
1005
1006   len = strlen(key->module);
1007
1008   for (i=0; i<len; i++) {
1009     val += (guint8) key->module[i];
1010   }
1011
1012   return val;
1013
1014 }
1015
1016
1017 /*
1018  * ------------------------------------------------------------------------------------------+ 
1019  *                                 Public Utility functions
1020  * ------------------------------------------------------------------------------------------+
1021  */
1022
1023
1024
1025
1026 /*
1027  * Routine to  allow giop users to register their sub dissector function, name, and
1028  * IDL module/interface name. Store in giop_module_hash. Also pass along their proto_XXX
1029  * value returned from their proto_register_protocol(), so we can enable/disbale it
1030  * through the GUI (edit protocols).
1031  *
1032  * This is used by try_explicit_giop_dissector() to find the
1033  * correct sub-dissector.
1034  *
1035  */
1036
1037 void register_giop_user_module(giop_sub_dissector_t *sub, gchar *name, gchar *module, int sub_proto) {
1038
1039   struct giop_module_key module_key, *new_module_key;
1040   struct giop_module_val *module_val = NULL;
1041
1042   module_key.module = module; /*  module name */
1043   
1044   module_val = (struct giop_module_val *)g_hash_table_lookup(giop_module_hash, &module_key);
1045
1046   if (module_val) {
1047     return;                     /* module name collision */
1048   }
1049   
1050   /* So, passed module name should NOT exist in hash at this point.*/
1051
1052 #if DEBUG    
1053   printf("giop:register_module: Adding Module %s to module hash \n", module);
1054   printf("giop:register_module: Module sub dissector name is %s \n", name);
1055 #endif
1056
1057   new_module_key = g_mem_chunk_alloc(giop_module_keys);
1058   new_module_key->module = module; /* save Module or interface name from IDL */
1059   
1060   module_val = g_mem_chunk_alloc(giop_module_vals);
1061
1062   module_val->subh = g_malloc(sizeof (giop_sub_handle_t)); /* init subh  */
1063
1064   module_val->subh->sub_name = name;    /* save dissector name */
1065   module_val->subh->sub_fn = sub;       /* save subdissector*/
1066   module_val->subh->sub_proto = sub_proto;      /* save subdissector's proto_XXX value */
1067   
1068   g_hash_table_insert(giop_module_hash, new_module_key, module_val);
1069
1070 }
1071
1072
1073
1074
1075 /* Object Key Hash "EQUAL" Functions */
1076
1077 static gint giop_hash_objkey_equal(gconstpointer v, gconstpointer w) {
1078   struct giop_object_key *v1 = (struct giop_object_key *)v;
1079   struct giop_object_key *v2 = (struct giop_object_key *)w;
1080
1081   if (v1->objkey_len != v2->objkey_len)
1082     return 0;                   /* no match because different length */
1083
1084   /* Now do a byte comaprison */
1085
1086   if (!memcmp(v1->objkey,v2->objkey, v1->objkey_len)) {
1087     return 1;           /* compares ok */
1088   }
1089
1090 #if DEBUG
1091   printf("giop:giop_hash_objkey_equal: Objkey's DO NOT match");
1092 #endif
1093
1094   return 0;                     /* found  differences */
1095 }
1096
1097 /* Object Key Hash "HASH" Functions */
1098
1099 static guint32 giop_hash_objkey_hash(gconstpointer v) {
1100   struct giop_object_key *key = (struct giop_object_key *)v;
1101
1102   guint32 i;
1103   guint32 val = 0;              /* init hash value */
1104
1105
1106   /*
1107    * Hmm, try this simple hashing scheme for now.
1108    * ie: Simple summation
1109    *
1110    *
1111    */
1112
1113 #if DEBUG
1114   printf("giop:hash_objkey: Key length = %u \n", key->objkey_len );
1115 #endif
1116
1117   for (i=0; i< key->objkey_len; i++) {
1118     val += (guint8) key->objkey[i];
1119   }
1120
1121   return val;
1122
1123 }
1124
1125 /*
1126  * Routine to take an object key octet sequence, and length, and ptr to
1127  * a (null terminated )repository ID string, and store them in the obect key hash.
1128  *
1129  * Blindly Inserts even if it does exist, See TODO at top for reason.
1130  */
1131
1132 static void insert_in_objkey_hash(GHashTable *hash, gchar *obj, guint32 len, gchar *repoid, ior_src_t src) {
1133
1134   struct giop_object_key objkey_key, *new_objkey_key;
1135   struct giop_object_val *objkey_val = NULL;
1136
1137   objkey_key.objkey_len  = len; /*  length  */
1138   objkey_key.objkey  = obj;     /*  object key octet sequence  */
1139
1140   /* Look it up to see if it exists */
1141
1142   objkey_val = (struct giop_object_val *)g_hash_table_lookup(hash, &objkey_key);
1143
1144   /* CHANGED -- Same reqid, so abandon old entry */
1145
1146   if (objkey_val) {
1147     g_hash_table_remove(hash, &objkey_key);
1148   }
1149   
1150   /* So, passed key should NOT exist in hash at this point.*/
1151     
1152   new_objkey_key = g_mem_chunk_alloc(giop_objkey_keys);
1153   new_objkey_key->objkey_len = len; /* save it */
1154   new_objkey_key->objkey = (guint8 *) g_memdup(obj,len);        /* copy from object and allocate ptr */
1155     
1156   objkey_val = g_mem_chunk_alloc(giop_objkey_vals);
1157   objkey_val->repo_id = g_strdup(repoid); /* duplicate and store Respository ID string */
1158   objkey_val->src = src; /* where IOR came from */
1159
1160
1161 #if DEBUG  
1162   printf("giop: ******* Inserting Objkey with RepoID = %s and key length = %u into hash  \n",
1163          objkey_val->repo_id, new_objkey_key->objkey_len);
1164 #endif
1165
1166   g_hash_table_insert(hash, new_objkey_key, objkey_val);
1167
1168 }
1169
1170
1171
1172 /*
1173  * convert an ascii char representing a hex value,
1174  * to a numeric value.
1175  *
1176  * returns value, or -1 if problem.
1177  *
1178  */
1179
1180 static gint8 hex_char_to_val(guchar c){
1181   gint8 retval ;
1182
1183   if (!isxdigit(c)) {
1184     return -1;
1185   }
1186   if (isdigit(c)) {
1187     retval = c - 48;            /* convert digit */
1188     return retval;
1189   }
1190
1191   c = toupper(c);               /* convert to uppercase */
1192   if (c >= 'A' && c <= 'F') {
1193     retval = c - 55;
1194     return retval;
1195   } 
1196   else {
1197     return -1;
1198   }
1199
1200 }
1201
1202 /*
1203  * Convert from  stringified IOR of the kind IOR:af4f7e459f....
1204  * to an IOR octet sequence.
1205  *
1206  * User must free buffer.
1207  *
1208  * Creates a new tvbuff and call decode_IOR with a NULL tree, just to
1209  * grab repoid etc for our objkey hash. 
1210  *
1211  */
1212
1213 static guint32 string_to_IOR(guchar *in, guint32 in_len, guint8 **out){
1214   gint8 tmpval_lsb;
1215   gint8 tmpval_msb;
1216   gint8 tmpval;         /* complete value */
1217   guint32 i;
1218
1219   *out = g_new0(guint8, in_len); /* allocate buffer */
1220
1221   if (*out == NULL) {
1222     return 0;
1223   }
1224
1225   /* skip past IOR:  and convert character pairs to guint8 */
1226
1227   for (i=4; i<in_len-1; i+=2) {
1228     if ( isxdigit(in[i]) && isxdigit(in[i+1]) ) { /* hex ? */
1229       
1230       if ( (tmpval_msb = hex_char_to_val(in[i])) < 0 ) {
1231         g_warning("giop: Invalid value in IOR %i \n", tmpval_msb);
1232
1233       }
1234       
1235       if ( (tmpval_lsb = hex_char_to_val(in[i+1])) < 0 ) {
1236         g_warning("giop: Invalid value in IOR %i \n", tmpval_lsb);
1237       }
1238       
1239       tmpval = tmpval_msb << 4;
1240       tmpval += tmpval_lsb;
1241       (*out)[(i-4)/2] = (guint8) tmpval;
1242
1243     }
1244     else {
1245       /* hmm  */
1246       break;
1247     }
1248     
1249   }
1250
1251   return (i-4)/2;               /* length  */
1252
1253 }
1254
1255
1256
1257 /*
1258  * Simple getline, copied from somewhere :)
1259  *
1260  */
1261
1262 static int getline(FILE *fp, gchar *line, int maxlen) {
1263
1264   if (fgets(line,maxlen,fp) == NULL)
1265     return 0;
1266   else
1267     return strlen(line);
1268
1269 }
1270
1271
1272 /* 
1273  * Read a list of stringified IOR's from a named file, convert to IOR's
1274  * and store in object key hash
1275  */
1276
1277 static void read_IOR_strings_from_file(gchar *name, int max_iorlen) {
1278   guchar *buf;                  /* NOTE reused for every line */
1279   int len;
1280   int ior_val_len;              /* length after unstringifying. */
1281   FILE *fp;             
1282   guint8 *out;                  /* ptr to unstringified IOR */
1283   tvbuff_t *tvb;                /* temp tvbuff for dissectin IORs */
1284   guint32 my_offset = 0;
1285   gboolean stream_is_big_endian;
1286
1287
1288   fp = fopen(name,"r"); /* open read only */
1289
1290   if (fp == NULL) {
1291     if (errno == EACCES)
1292       fprintf(stderr, "Error opening file IOR.txt for reading: %s\n",strerror(errno));
1293     return;
1294   }
1295
1296   buf = g_malloc0(max_iorlen+1);        /* input buf */
1297
1298   while ((len = getline(fp,buf,max_iorlen+1)) > 0) {
1299     my_offset = 0;              /* reset for every IOR read */
1300
1301     ior_val_len = string_to_IOR(buf,len,&out);  /* convert */
1302
1303     if(ior_val_len>0) {
1304     
1305       /* Combination of tvb_new() and tvb_set_real_data().
1306          Can throw ReportedBoundsError.
1307
1308          XXX - can it throw an exception in this case?  If so, we
1309          need to catch it and clean up, but we really shouldn't allow
1310          it - or "get_CDR_octet()", or "decode_IOR()" - to throw an
1311          exception. */
1312
1313       tvb =  tvb_new_real_data(out, ior_val_len, ior_val_len);
1314
1315       stream_is_big_endian = !get_CDR_octet(tvb,&my_offset);
1316       decode_IOR(tvb, NULL, NULL, &my_offset, 0, stream_is_big_endian);
1317
1318       tvb_free(tvb);
1319
1320     }
1321
1322     g_free(out);
1323
1324   }
1325
1326   fclose(fp);                   /* be nice */
1327
1328   g_free(buf);
1329 }
1330
1331
1332
1333 /*
1334  * Init routine, setup our request hash stuff, or delete old ref's
1335  *
1336  * Cannot setup the module hash here as my init() may not be called before
1337  * users start registering. So I will move the module_hash stuff to
1338  * proto_register_giop, as is done with packet-rpc
1339  *
1340  *
1341  *
1342  * Also, setup our objectkey/repoid hash here.
1343  *
1344  */
1345
1346 static void giop_init(void) {
1347
1348
1349   /*
1350    * Create objkey/repoid  hash, use my "equal" and "hash" functions.
1351    * 
1352    */
1353
1354   if (giop_objkey_hash)
1355     g_hash_table_destroy(giop_objkey_hash);
1356   if (giop_objkey_keys)
1357     g_mem_chunk_destroy(giop_objkey_keys);
1358   if (giop_objkey_vals)
1359     g_mem_chunk_destroy(giop_objkey_vals);
1360
1361
1362   /*
1363    * Create hash, use my "equal" and "hash" functions.
1364    * 
1365    */
1366
1367   giop_objkey_hash = g_hash_table_new(giop_hash_objkey_hash, giop_hash_objkey_equal);
1368
1369   giop_objkey_keys = g_mem_chunk_new("giop_objkey_keys",
1370                                          sizeof(struct giop_object_key),
1371                                          giop_objkey_init_count * sizeof(struct giop_object_key), 
1372                                          G_ALLOC_AND_FREE);
1373
1374   giop_objkey_vals = g_mem_chunk_new("giop_objkey_vals", 
1375                                          sizeof(struct giop_object_val),
1376                                          giop_objkey_init_count * sizeof(struct giop_object_val), 
1377                                          G_ALLOC_AND_FREE);
1378
1379
1380   /*
1381    * Create complete_reply_hash, use my "equal" and "hash" functions.
1382    * 
1383    */
1384
1385   if (giop_complete_reply_hash)
1386     g_hash_table_destroy(giop_complete_reply_hash);
1387   if (giop_complete_reply_keys)
1388     g_mem_chunk_destroy(giop_complete_reply_keys);
1389   if (giop_complete_reply_vals)
1390     g_mem_chunk_destroy(giop_complete_reply_vals);
1391
1392
1393   /*
1394    * Create hash, use my "equal" and "hash" functions.
1395    * 
1396    */
1397
1398   giop_complete_reply_hash = g_hash_table_new(complete_reply_hash_fn, complete_reply_equal_fn);
1399
1400   giop_complete_reply_keys = g_mem_chunk_new("giop_complete_reply_keys",
1401                                          sizeof(struct complete_reply_hash_key),
1402                                          complete_reply_hash_count * sizeof(struct complete_reply_hash_key), 
1403                                          G_ALLOC_AND_FREE);
1404
1405   giop_complete_reply_vals = g_mem_chunk_new("giop_complete_reply_vals", 
1406                                          sizeof(struct complete_reply_hash_val),
1407                                          complete_reply_hash_count * sizeof(struct complete_reply_hash_val), 
1408                                          G_ALLOC_AND_FREE);
1409
1410
1411   
1412   read_IOR_strings_from_file("IOR.txt", 600); /* testing */
1413
1414
1415 }
1416
1417
1418 /* 
1419  * Insert an entry in the GIOP Heuristic User table.
1420  * Uses a GList.
1421  * Uses giop_sub_handle_t to wrap giop user info.
1422  *
1423  */
1424     
1425 void register_giop_user(giop_sub_dissector_t *sub, gchar *name, int sub_proto) {
1426
1427   giop_sub_handle_t *subh;
1428   
1429   subh = g_malloc(sizeof (giop_sub_handle_t));
1430
1431   subh->sub_name = name;
1432   subh->sub_fn = sub;
1433   subh->sub_proto = sub_proto;  /* proto_XXX from sub dissectors's proto_register_protocol() */
1434
1435   giop_sub_list = g_slist_append (giop_sub_list, subh);
1436  
1437 }
1438
1439
1440 /*
1441  * Lookup an object key in our object key hash, and return the corresponding
1442  * Repo Id.
1443  *
1444  */
1445
1446 static gchar * get_repoid_from_objkey(GHashTable *hash, guint8 *obj, guint32 len) {
1447
1448   struct giop_object_key objkey_key;
1449   struct giop_object_val *objkey_val = NULL;
1450
1451   objkey_key.objkey_len  = len; /*  length  */
1452   objkey_key.objkey  = obj;     /*  object key octet sequence  */
1453
1454   /* Look it up to see if it exists */
1455
1456   objkey_val = (struct giop_object_val *)g_hash_table_lookup(hash, &objkey_key);
1457
1458   if (objkey_val) {
1459 #if DEBUG
1460     printf("Lookup of object key returns  RepoId = %s \n",objkey_val->repo_id );
1461 #endif
1462     return objkey_val->repo_id; /* found  */
1463   }
1464
1465 #if DEBUG    
1466   printf("FAILED Lookup of object key \n" );
1467 #endif
1468   
1469   return NULL;                  /* not  found */
1470 }
1471
1472
1473
1474 /*
1475  * Extract top level module/interface from repoid 
1476  *
1477  * eg from -  "IDL:Echo/interface1:1.0"
1478  * get "Echo"
1479  *
1480  * Or, from "IDL:linux.org/Penguin/Teeth:1.0" get
1481  * get linux.org/Penguin/Teeth
1482  * 
1483  *
1484  * User must free returned ptr after use.
1485  *
1486  * TODO -- generalize for other Repoid encodings
1487  */
1488
1489 static gchar * get_modname_from_repoid(gchar *repoid) {
1490
1491   gchar *modname = NULL;
1492   gchar *saved_repoid = NULL;
1493   gchar c = 'a';
1494   guint8 stop_mod;              /* Index of last character of modname in Repoid  */
1495   guint8 start_mod = 4;         /* Index where Module name starts in repoid */
1496   int i;
1497
1498   saved_repoid = g_strdup(repoid); /* make a copy */
1499
1500   /* Must start with IDL: , otherwise I get confused */
1501
1502   if (g_strncasecmp("IDL:",repoid,4))
1503     return NULL;
1504
1505   /* Looks like a RepoID to me, so get Module or interface name */
1506
1507   /* TODO -- put some code here to get Module name */
1508
1509   for(i=4; c != '\0'; i++) {
1510     c = repoid[i];
1511     stop_mod = i;               /* save */
1512     if (c == ':' )              /* delimiters */
1513       break;
1514     
1515   }
1516
1517   /* Now create a new string based on start and stop and \0 */
1518   
1519   modname = g_strndup(repoid+4, stop_mod - start_mod);
1520     
1521   return modname;
1522   
1523 }
1524
1525 /*
1526  * DEBUG CODE
1527  *
1528  */
1529
1530
1531 #if DEBUG
1532
1533 /*
1534  * Display a "module" hash entry
1535  */
1536
1537 static void display_module_hash(gpointer key, gpointer val, gpointer user_data) {
1538
1539   struct giop_module_val *mv = (struct giop_module_val *) val;
1540   struct giop_module_key *mk = (struct giop_module_key *) key;
1541
1542   printf("giop:module: Key = (%s) , Val = (%s) \n", mk->module, mv->subh->sub_name);
1543   
1544   return;
1545
1546 }
1547
1548 /*
1549  * Display a "complete_reply " hash entry
1550  */
1551
1552 static void display_complete_reply_hash(gpointer key, gpointer val, gpointer user_data) {
1553
1554   struct complete_reply_hash_val *mv = (struct complete_reply_hash_val *) val;
1555   struct complete_reply_hash_key *mk = (struct complete_reply_hash_key *) key;
1556
1557   printf("giop:complete_reply: FN (key) = %8u , MFN (val) = %8u \n", mk->fn, mv->mfn);
1558   
1559   return;
1560
1561 }
1562
1563
1564 /*
1565  * Display an "objkey" hash entry
1566  */
1567
1568 static void display_objkey_hash(gpointer key, gpointer val, gpointer user_data) {
1569   guint32 i;
1570   struct giop_object_val *mv = (struct giop_object_val *) val;
1571   struct giop_object_key *mk = (struct giop_object_key *) key;
1572
1573
1574   printf("giop:objkey: Key->objkey_len = %u,  Key->objkey ",  mk->objkey_len);
1575
1576   for (i=0; i<mk->objkey_len; i++) {
1577     printf("%.2x ", mk->objkey[i]);
1578   }
1579
1580   /*
1581    * If read from file, mark it as such..
1582    */
1583
1584   if(mv->src == 0) {
1585     printf(", Repo ID = %s \n", mv->repo_id);
1586   }
1587   else {
1588     printf(", Repo ID = %s , (file) \n", mv->repo_id);    
1589   }
1590   
1591   return;
1592
1593 }
1594
1595 /*
1596  * Display all giop_sub_list (GSList) entries
1597  */
1598
1599 static void display_heuristic_user_list() {
1600   int i;
1601   int len;
1602   giop_sub_handle_t *subh;      /* handle */
1603   
1604   /* Get length of list */
1605   len = g_slist_length(giop_sub_list); /* find length */
1606
1607   if (len == 0)
1608     return;
1609
1610   for (i=0; i<len; i++) {
1611     subh = ( giop_sub_handle_t *) g_slist_nth_data(giop_sub_list,i); /* grab entry */
1612     printf("giop:heuristic_user: Element = %i, Val (user) = %s \n", i, subh->sub_name);
1613   }
1614   
1615 }
1616
1617 /*
1618  * Display all complete_request_list (GList) entries
1619  */
1620
1621 static void display_complete_request_list() {
1622   int i;
1623   int len;
1624   comp_req_list_entry_t *entry;
1625   
1626   /* Get length of list */
1627   len = g_list_length(giop_complete_request_list); /* find length */
1628
1629   if (len == 0)
1630     return;
1631
1632   for (i=0; i<len; i++) {
1633     entry = (comp_req_list_entry_t *) g_list_nth_data(giop_complete_request_list,i); /* grab entry */
1634     printf("giop:Index = %8i , FN = %8i, reqid = %8u , operation = %20s , repoid = %30s \n", i, entry->fn, 
1635            entry->reqid,entry->operation, entry->repoid);
1636   }
1637   
1638 }
1639
1640
1641
1642
1643 /* Dump Hash/List contents 
1644  *
1645  * collection_type specifies the list or hash to dump
1646  *
1647  */
1648
1649 static void giop_dump_collection(collection_data_t collection_type) {
1650
1651   switch(collection_type) {
1652   case cd_heuristic_users:
1653     printf("+----------------------------------------------+ \n");
1654     printf("+-------------- Heuristic User (Begin) --------+ \n");
1655     printf("+----------------------------------------------+ \n");
1656
1657     display_heuristic_user_list();
1658
1659     printf("+----------------------------------------------+ \n");
1660     printf("+-------------- Heuristic User (End) ----------+ \n");
1661     printf("+----------------------------------------------+ \n");
1662
1663     break;
1664
1665   case cd_complete_request_list:
1666     printf("+----------------------------------------------+ \n");
1667     printf("+------------- Complete Request List (Begin) --+ \n");
1668     printf("+----------------------------------------------+ \n");
1669
1670     display_complete_request_list();
1671
1672     printf("+----------------------------------------------+ \n");
1673     printf("+------------ Complete Request List (End) -----+ \n");
1674     printf("+----------------------------------------------+ \n");
1675
1676     break;
1677
1678   case cd_module_hash:
1679     printf("+----------------------------------------------+ \n");
1680     printf("+-------------- Module (Begin) ----------------+ \n");
1681     printf("+----------------------------------------------+ \n");
1682
1683     g_hash_table_foreach(giop_module_hash, display_module_hash, NULL);
1684
1685     printf("+----------------------------------------------+ \n");
1686     printf("+-------------- Module ( End) -----------------+ \n");
1687     printf("+----------------------------------------------+ \n\n");
1688
1689     break;
1690
1691   case cd_objkey_hash:
1692     printf("+----------------------------------------------+ \n");
1693     printf("+-------------- Objkey (Begin) ----------------+ \n");
1694     printf("+----------------------------------------------+ \n");
1695
1696     g_hash_table_foreach(giop_objkey_hash, display_objkey_hash,NULL);
1697
1698     printf("+----------------------------------------------+ \n");
1699     printf("+-------------- Objkey (End) ------------------+ \n");
1700     printf("+----------------------------------------------+ \n\n");
1701   
1702     break;
1703
1704   case cd_complete_reply_hash:
1705     printf("+----------------------------------------------+ \n");
1706     printf("+-------------- Complete_Reply_Hash (Begin) ---+ \n");
1707     printf("+----------------------------------------------+ \n");
1708
1709     g_hash_table_foreach(giop_complete_reply_hash, display_complete_reply_hash, NULL);
1710
1711     printf("+----------------------------------------------+ \n");
1712     printf("+------------- Complete_Reply_Hash (End) ------+ \n");
1713     printf("+----------------------------------------------+ \n");
1714
1715     break;
1716     
1717   default:
1718
1719     printf("giop: giop_dump_collection: Unknown type   \n");
1720
1721   }
1722
1723
1724 }
1725
1726
1727 #endif /* DEBUG */
1728
1729 /*
1730  * Loop through all  subdissectors, and call them until someone
1731  * answers (returns TRUE). This function then returns TRUE, otherwise
1732  * it return FALSE
1733  *
1734  * But skip a subdissector if it has been disabled in GUI "edit protocols".
1735  */
1736
1737 static gboolean try_heuristic_giop_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
1738                 MessageHeader *header, gchar *operation  ) {
1739
1740   int i,len;
1741   gboolean res = FALSE;         /* result of calling a heuristic sub dissector */
1742   giop_sub_handle_t *subh = NULL; 
1743   const char *saved_proto;
1744
1745   len = g_slist_length(giop_sub_list); /* find length */
1746
1747   if (len == 0)
1748     return FALSE;
1749
1750   saved_proto = pinfo->current_proto;
1751   for (i=0; i<len; i++) {
1752     subh = (giop_sub_handle_t *) g_slist_nth_data(giop_sub_list,i); /* grab dissector handle */
1753
1754     if (proto_is_protocol_enabled(subh->sub_proto)) {
1755       pinfo->current_proto =
1756         proto_get_protocol_short_name(subh->sub_proto);
1757       res = (subh->sub_fn)(tvb,pinfo,tree,offset,header,operation,NULL); /* callit TODO - replace NULL */
1758       if (res) {
1759         pinfo->current_proto = saved_proto;
1760         return TRUE;            /* found one, lets return */
1761       }  
1762     } /* protocol_is_enabled */
1763   } /* loop */
1764
1765   if (check_col (pinfo->cinfo, COL_PROTOCOL))
1766       col_set_str (pinfo->cinfo, COL_PROTOCOL, "GIOP");
1767
1768   pinfo->current_proto = saved_proto;
1769   return res;                   /* result */
1770
1771 }
1772
1773
1774 /*
1775  * Find the matching repoid in the module hash and call
1776  * the dissector function if offset exists.
1777  * 
1778  *
1779  * Repoid is eg IDL:tux.antarctic/Penguin/Teeth:1.0 but subdissectors 
1780  * will register possibly "tux.antarctic/Penguin" and "tux.antarctic/Penguin/Teeth". 
1781  *
1782  *
1783  *
1784  */
1785
1786 static gboolean try_explicit_giop_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
1787                                             MessageHeader *header, gchar *operation, gchar *repoid ) {
1788
1789   giop_sub_handle_t *subdiss = NULL; /* handle */
1790   gboolean res = FALSE;
1791   gchar *modname = NULL;
1792   struct giop_module_key module_key;
1793   struct giop_module_val *module_val = NULL;
1794   const char *saved_proto;
1795
1796
1797   /*
1798    * Get top level module/interface from complete repoid 
1799    */
1800
1801   modname = get_modname_from_repoid(repoid); 
1802   if (modname == NULL) {
1803     return res;                 /* unknown module name */
1804   }
1805
1806
1807   /* Search for Module or interface name */
1808
1809   module_key.module = modname; /*  module name */
1810   module_val = (struct giop_module_val *)g_hash_table_lookup(giop_module_hash, &module_key);
1811
1812   if (module_val == NULL) {
1813     return res;                 /* module not registered */
1814   }
1815   
1816   subdiss = (giop_sub_handle_t *) module_val->subh; /* grab dissector handle */
1817
1818   if (subdiss) {
1819     /* Add giop_sub_handle_t and repoid into complete_request_list, so REPLY can */
1820     /* look it up directly, later ie: FN -> MFN -> giop_sub_handle_t and repoid */
1821     /* but only if user not clicking */
1822
1823     if (!pinfo->fd->flags.visited)
1824       add_sub_handle_repoid_to_comp_req_list(pinfo->fd->num,subdiss,repoid);
1825
1826
1827     /* Call subdissector if current offset exists , and dissector is enabled in GUI "edit protocols" */
1828
1829     if (tvb_offset_exists(tvb, *offset)) {   
1830 #if DEBUG  
1831       printf("giop:try_explicit_dissector calling sub = %s with module = (%s) \n", subdiss->sub_name  , modname);
1832 #endif
1833
1834       if (proto_is_protocol_enabled(subdiss->sub_proto)) {
1835
1836         saved_proto = pinfo->current_proto;
1837         pinfo->current_proto =
1838           proto_get_protocol_short_name(subdiss->sub_proto);
1839         res = (subdiss->sub_fn)(tvb,pinfo,tree,offset,header,operation, modname); /* callit, TODO replace NULL with idlname */
1840         pinfo->current_proto = saved_proto;
1841
1842       } /* protocol_is_enabled */
1843     } /* offset exists */
1844   } /* subdiss */
1845   
1846   return res;                   /* return result */
1847 }
1848
1849
1850
1851 /* Take in an array of char and create a new string.
1852  * Replace non-printable characters with periods.
1853  *
1854  * The array may contain \0's so dont use strdup
1855  * The string is \0 terminated, and thus longer than
1856  * the initial sequence. 
1857  * Caller must free the new string.
1858  */
1859
1860 static gchar * make_printable_string (gchar *in, guint32 len) {
1861   guint32 i = 0;
1862   gchar *print_string = NULL;
1863
1864   print_string = (gchar * )g_malloc0(len + 1); /* make some space and zero it */
1865   memcpy(print_string, in, len);        /* and make a copy of input data */
1866   
1867   for(i=0; i < len; i++) {
1868     if( !isprint( (unsigned char)print_string[i] ) ) 
1869       print_string[i] = '.';
1870   }
1871
1872   return print_string;          /* return ptr */
1873 }
1874
1875 /* Determine the byte order from the GIOP MessageHeader */
1876
1877 gboolean is_big_endian (MessageHeader * header) {
1878   gboolean big_endian = FALSE;
1879
1880   switch (header->GIOP_version.minor) {
1881   case 2:
1882   case 1:
1883     if (header->flags & 0x01)
1884       big_endian = FALSE;
1885     else
1886       big_endian = TRUE;
1887     break;
1888   case 0:
1889     if (header->flags)
1890       big_endian = FALSE;
1891     else
1892       big_endian = TRUE;
1893     break;
1894   default:
1895     break;
1896   }
1897   return big_endian;
1898 }
1899
1900
1901
1902 /* 
1903  * Calculate new offset, based on the current offset, and user supplied 
1904  * "offset delta" value, and the alignment requirement.
1905  *
1906  *
1907  *
1908  * eg: Used for GIOP 1.2 where Request and Reply bodies are 
1909  *     aligned on 8 byte boundaries.
1910  */
1911
1912 static void set_new_alignment(int *offset, int delta, int  alignment) {
1913
1914   while( ( (*offset + delta) % alignment) != 0)
1915           ++(*offset);
1916
1917
1918 }
1919
1920
1921
1922 /*
1923  * ------------------------------------------------------------------------------------------+ 
1924  *                                 Public get_CDR_xxx functions.
1925  * ------------------------------------------------------------------------------------------+
1926  */
1927
1928
1929
1930 /*
1931  * Gets data of type any. This is encoded as a TypeCode
1932  * followed by the encoded value.
1933  */
1934
1935 void get_CDR_any(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
1936                  gboolean stream_is_big_endian, int boundary,
1937                  MessageHeader * header ) {
1938   
1939   guint32  TCKind;    /* TypeCode */
1940
1941   /* get TypeCode of any */
1942   TCKind = get_CDR_typeCode(tvb, tree, offset, stream_is_big_endian, boundary, header );
1943
1944   /* dissect data of type TCKind */
1945   dissect_data_for_typecode(tvb, tree, offset, stream_is_big_endian, boundary, header, TCKind );
1946 }
1947
1948
1949 /* Copy a 1 octet sequence from the tvbuff 
1950  * which represents a boolean value, and convert
1951  * it to a boolean value.
1952  * Offset is then incremented by 1, to indicate the 1 octet which
1953  * has been processed.
1954  */
1955
1956 gboolean get_CDR_boolean(tvbuff_t *tvb, int *offset) {
1957   guint8 val;
1958
1959   val = tvb_get_guint8(tvb, *offset); /* easy */
1960   (*offset)++;
1961   return val;
1962 }
1963
1964 /* Copy a 1 octet sequence from the tvbuff 
1965  * which represents a char, and convert
1966  * it to an char value.
1967  * offset is then incremented by 1, to indicate the 1 octet which
1968  * has been processed.
1969  */
1970
1971 guint8 get_CDR_char(tvbuff_t *tvb, int *offset) {
1972   guint8 val;
1973
1974   val = tvb_get_guint8(tvb, *offset); /* easy */
1975   (*offset)++;
1976   return val;
1977 }
1978
1979
1980
1981 /* 
1982  * Floating Point Data Type double IEEE 754-1985 
1983  *
1984  * Copy an 8 octet sequence from the tvbuff 
1985  * which represents a double value, and convert
1986  * it to a double value, taking into account byte order.
1987  * offset is first incremented so that it falls on a proper alignment
1988  * boundary for double values.
1989  * offset is then incremented by 8, to indicate the 8 octets which
1990  * have been processed.
1991  */
1992
1993 gdouble get_CDR_double(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
1994
1995   guint8 sign;
1996   guint8 e1,e2,f1,f2,f3,f4,f5,f6,f7;
1997   gdouble val;
1998   guint16 exp;
1999   guint32 fract0, fract1;
2000   gdouble d_fract;              
2001   
2002
2003   /* double values must be aligned on a 8 byte boundary */
2004
2005   while( ( (*offset + boundary) % 8) != 0)
2006           ++(*offset);
2007
2008
2009   if(stream_is_big_endian) {    
2010     e1  = get_CDR_octet(tvb,offset);
2011     sign = e1 >> 7;                     /* sign value */
2012     e1 &= 0x7f;         /* bottom 7 bits */
2013     f1  = get_CDR_octet(tvb,offset);
2014     e2 = f1 >> 4;
2015     f1 &= 0x0f;         /* bottom 4 bits */
2016     f2  = get_CDR_octet(tvb,offset);
2017     f3  = get_CDR_octet(tvb,offset);
2018     f4  = get_CDR_octet(tvb,offset);
2019     f5  = get_CDR_octet(tvb,offset);
2020     f6  = get_CDR_octet(tvb,offset);
2021     f7  = get_CDR_octet(tvb,offset);
2022
2023   } else {
2024
2025     f7  = get_CDR_octet(tvb,offset);
2026     f6  = get_CDR_octet(tvb,offset);
2027     f5  = get_CDR_octet(tvb,offset);
2028     f4  = get_CDR_octet(tvb,offset);
2029     f3  = get_CDR_octet(tvb,offset);
2030     f2  = get_CDR_octet(tvb,offset);
2031     f1  = get_CDR_octet(tvb,offset);
2032     e2 = f1 >> 4;
2033     f1 &= 0x0f;         /* bottom 4 bits */
2034     e1  = get_CDR_octet(tvb,offset);
2035     sign = e1 >> 7;                     /* sign value */
2036     e1 &= 0x7f;         /* bottom 7 bits */
2037
2038   }
2039
2040   exp = (e1 << 4) + e2;
2041
2042   /* Now lets do some 52 bit math with 32 bit constraint */
2043
2044   fract0 = f7 + (f6 << 8) + (f5 << 16) + (f4 << 24); /* lower 32 bits of fractional part */
2045   fract1 = f3 + (f2 << 8) + (f1 << 16);              /* top 20 bits of fractional part   */
2046
2047   d_fract = (fract1 / (pow(2,20))) + (fract0 / (pow(2,52))); /* 52 bits represent a fraction */
2048
2049   val = pow(-1,sign) * pow(2,(exp - 1023)) * (1 + d_fract);
2050
2051   return val;           /* FIX rounding ?? */
2052
2053 }
2054
2055
2056 /* Copy a 4 octet sequence from the tvbuff 
2057  * which represents an enum value, and convert
2058  * it to an enum value, taking into account byte order.
2059  * offset is first incremented so that it falls on a proper alignment
2060  * boundary for an enum (4)
2061  * offset is then incremented by 4, to indicate the 4 octets which
2062  * have been processed.
2063  *
2064  * Enum values are encoded as unsigned long.
2065  */
2066
2067
2068 guint32 get_CDR_enum(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2069
2070   return get_CDR_ulong(tvb, offset, stream_is_big_endian, boundary );
2071
2072 }
2073
2074
2075 /*
2076  * Copy an octet sequence from the tvbuff
2077  * which represents a Fixed point decimal type, and create a string representing
2078  * a Fixed point decimal type. There are no alignment restrictions.
2079  * Size and scale of fixed decimal type is determined by IDL.
2080  * 
2081  * digits - IDL specified number of "digits" for this fixed type
2082  * scale  - IDL specified "scale" for this fixed type
2083  *
2084  *
2085  * eg: typedef fixed <5,2> fixed_t;
2086  *     could represent numbers like 123.45, 789.12, 
2087  *
2088  *
2089  * As the fixed type could be any size, I will not try to fit it into our
2090  * simple types like gdouble or glong etc. I will just create a string buffer holding
2091  * a  representation (after scale is applied), and with a decimal point or zero padding
2092  * inserted at the right place if necessary. The string is null terminated
2093  *
2094  * so string may look like 
2095  *
2096  *
2097  *  "+1.234" or "-3456.78" or "1234567309475760377365465897891" or "-2789000000" etc
2098  *
2099  * According to spec, digits <= 31
2100  * and scale is positive (except for constants eg: 1000 has digit=1 and implied scale = -3)
2101  * or <4,0> ?
2102  *
2103  * User must remember to free the buffer
2104  *
2105  */
2106
2107
2108 void get_CDR_fixed(tvbuff_t *tvb, gchar **seq, gint *offset, guint32 digits, gint32 scale) {
2109
2110   guint8 sign;                  /* 0x0c is positive, 0x0d is negative */
2111   guint32 i ;                   /* loop */
2112   guint32 slen;                 /* number of bytes to hold digits + extra 0's if scale <0 */
2113                                 /* this does not include sign, decimal point and \0 */
2114   guint32 sindex = 0;           /* string index */
2115   gchar *tmpbuf;                /* temp buff, holds string without scaling */
2116   guint8 tval;                  /* temp val storage */
2117
2118   /*
2119    * how many bytes to hold digits and scale (if scale <0) 
2120    *
2121    * eg: fixed <5,2> = 5 digits
2122    *     fixed <5,-2> = 7 digits (5 + 2 added 0's)
2123    */
2124
2125 #if DEBUG
2126     printf("giop:get_CDR_fixed() called , digits = %u, scale = %u \n", digits, scale);
2127 #endif
2128
2129   if (scale <0) {
2130     slen = digits - scale;      /* allow for digits + padding 0's for negative scal */
2131   } else {
2132     slen = digits;              /*  digits */
2133   }
2134
2135 #if DEBUG
2136     printf("giop:get_CDR_fixed(): slen =  %.2x \n", slen);
2137 #endif
2138   
2139   tmpbuf = g_new0(gchar, slen); /* allocate temp buffer */ 
2140
2141   /*
2142    * Register a cleanup function in case on of our tvbuff accesses
2143    * throws an exception. We need to clean up tmpbuf.
2144    */
2145   CLEANUP_PUSH(g_free, tmpbuf);
2146
2147   /* If even , grab 1st dig */
2148
2149   if (!(digits & 0x01)) {
2150     tval = get_CDR_octet(tvb,offset);
2151 #if DEBUG
2152     printf("giop:get_CDR_fixed():even: octet = %.2x \n", tval);
2153 #endif
2154     tmpbuf[sindex] = (tval & 0x0f) + 0x30; /* convert top nibble to ascii */
2155     sindex++;
2156   }
2157
2158   /*
2159    * Loop, but stop BEFORE we hit last digit and sign 
2160    * if digits = 1 or 2, then this part is skipped 
2161    */
2162
2163   if (digits>2) {
2164     for(i=0; i< ((digits-1)/2 ); i++) {
2165       tval = get_CDR_octet(tvb,offset);
2166 #if DEBUG
2167       printf("giop:get_CDR_fixed():odd: octet = %.2x \n", tval);
2168 #endif
2169       
2170       tmpbuf[sindex] = ((tval & 0xf0) >> 4) + 0x30; /* convert top nibble to ascii */
2171       sindex++;
2172       tmpbuf[sindex] = (tval & 0x0f)  + 0x30; /* convert bot nibble to ascii */
2173       sindex++;
2174       
2175     }
2176   } /* digits > 3 */
2177
2178 #if DEBUG
2179     printf("giop:get_CDR_fixed(): before last digit \n");
2180 #endif
2181   
2182
2183   /* Last digit and sign if digits >1, or 1st dig and sign if digits = 1 */
2184
2185     tval = get_CDR_octet(tvb,offset);
2186 #if DEBUG
2187     printf("giop:get_CDR_fixed(): octet = %.2x \n", tval);
2188 #endif
2189     tmpbuf[sindex] = (( tval & 0xf0)>> 4) + 0x30; /* convert top nibble to ascii */
2190     sindex++;
2191
2192     sign = tval & 0x0f; /* get sign */
2193
2194     /* So now, we have all digits in an array, and the sign byte 
2195      * so lets generate a printable string, taking into account the scale
2196      * and sign values.
2197      */
2198  
2199     sindex = 0;                         /* reset */
2200     *seq = g_new0(gchar, slen + 3);     /* allocate temp buffer , including space for sign, decimal point and 
2201                                          * \0 -- TODO check slen is reasonable first */
2202 #if DEBUG
2203     printf("giop:get_CDR_fixed(): sign =  %.2x \n", sign);
2204 #endif                                  
2205     
2206     switch(sign) {
2207     case 0x0c:
2208       (*seq)[sindex] = '+';     /* put sign in first string position */
2209       break;                    
2210     case 0x0d:
2211       (*seq)[sindex] = '-';
2212       break;
2213     default:
2214       g_warning("giop: Unknown sign value in fixed type %u \n", sign);
2215       (*seq)[sindex] = '*';     /* flag as sign unkown */
2216       break;
2217     }
2218
2219     sindex++;
2220
2221     /* Add decimal point or padding 0's, depending if scale is positive or
2222      * negative, respectively
2223      */
2224
2225     if (scale>0) {
2226       for (i=0; i<digits-scale; i++) {
2227         (*seq)[sindex] = tmpbuf[i]; /* digits to the left of the decimal point */       
2228         sindex++;
2229       }
2230       
2231       (*seq)[sindex] = '.'; /* decimal point */ 
2232       sindex++;
2233       
2234       for (i=digits-scale; i<digits; i++) {
2235         (*seq)[sindex] = tmpbuf[i]; /* remaining digits to the right of the decimal point */    
2236         sindex++;
2237       }
2238
2239       (*seq)[sindex] = '\0'; /* string terminator */    
2240
2241     } else {
2242
2243       /* negative scale, dump digits and  pad out with 0's */
2244
2245       for (i=0; i<digits-scale; i++) {
2246         if (i<digits) {
2247           (*seq)[sindex] = tmpbuf[i]; /* save digits */ 
2248         } else {
2249           (*seq)[sindex] = '0'; /* all digits used up, so pad with 0's */       
2250         }
2251         sindex++;
2252       }
2253
2254       (*seq)[sindex] = '\0'; /* string terminator */    
2255       
2256     }
2257
2258     /*
2259      * We're done with tmpbuf, so we can call the cleanup handler to free
2260      * it, and then pop the cleanup handler.
2261      */
2262     CLEANUP_CALL_AND_POP;
2263     
2264 #if DEBUG
2265     printf("giop:get_CDR_fixed(): value = %s \n", *seq);
2266 #endif
2267
2268     return; 
2269
2270 }
2271
2272
2273
2274 /*
2275  * Floating Point Data Type float IEEE 754-1985 
2276  * 
2277  * Copy an 4 octet sequence from the tvbuff 
2278  * which represents a float value, and convert
2279  * it to a float value, taking into account byte order.
2280  * offset is first incremented so that it falls on a proper alignment
2281  * boundary for float values.
2282  * offset is then incremented by 4, to indicate the 4 octets which
2283  * have been processed.
2284  */
2285
2286 gfloat get_CDR_float(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2287   
2288   guint8 sign;
2289   guint8 e1,e2,f1,f2,f3;
2290   gfloat val;
2291   guint8 exp;
2292   guint32 fract;
2293   gdouble d_fract;              
2294   
2295   /* float values must be aligned on a 4 byte boundary */
2296
2297   while( ( (*offset + boundary) % 4) != 0)
2298     ++(*offset);
2299
2300   if(stream_is_big_endian) {    
2301     e1  = get_CDR_octet(tvb,offset);
2302     sign = e1 >> 7;                     /* sign value */
2303     e1 &= 0x7f;         /* bottom 7 bits */
2304     f1  = get_CDR_octet(tvb,offset);
2305     e2 = f1 >> 7;
2306     f1 &= 0x7f;         /* bottom 7 bits */
2307     f2  = get_CDR_octet(tvb,offset);
2308     f3  = get_CDR_octet(tvb,offset);
2309
2310   } else {
2311
2312     f3  = get_CDR_octet(tvb,offset);
2313     f2  = get_CDR_octet(tvb,offset);
2314     f1  = get_CDR_octet(tvb,offset);
2315     e2 = f1 >> 7;
2316     f1 &= 0x7f;         /* bottom 7 bits */
2317     e1  = get_CDR_octet(tvb,offset);
2318     sign = e1 >> 7;                     /* sign value */
2319     e1 &= 0x7f;         /* bottom 7 bits */
2320
2321   }
2322
2323
2324   exp = (e1 << 1) + e2;
2325   fract = f3 + (f2 << 8) + (f1 << 16);
2326
2327   d_fract = fract / (pow(2,23)); /* 23 bits represent a fraction */
2328
2329   val = pow(-1,sign) * pow(2,(exp - 127)) * (1 + d_fract);
2330
2331   return val;           /* FIX rounding ?? */
2332
2333 }
2334
2335
2336 /*
2337  * Decode an Interface type, and display it on the tree.
2338  */
2339
2340 void get_CDR_interface(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, 
2341                        gboolean stream_is_big_endian, int boundary) {
2342
2343
2344   decode_IOR(tvb, pinfo, tree, offset, boundary, stream_is_big_endian);
2345   
2346   return;
2347 }
2348
2349
2350 /* Copy a 4 octet sequence from the tvbuff 
2351  * which represents a signed long value, and convert
2352  * it to an signed long vaule, taking into account byte order.
2353  * offset is first incremented so that it falls on a proper alignment
2354  * boundary for long values.
2355  * offset is then incremented by 4, to indicate the 4 octets which
2356  * have been processed.
2357  */
2358
2359 gint32 get_CDR_long(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2360
2361   gint32 val;
2362
2363   /* unsigned long values must be aligned on a 4 byte boundary */
2364   while( ( (*offset + boundary) % 4) != 0)
2365           ++(*offset);
2366
2367   val = (stream_is_big_endian) ? tvb_get_ntohl (tvb, *offset) :
2368                                  tvb_get_letohl (tvb, *offset);
2369
2370   *offset += 4; 
2371   return val; 
2372 }
2373
2374 /*
2375  * Decode an Object type, and display it on the tree.
2376  */
2377
2378 void get_CDR_object(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, 
2379                     gboolean stream_is_big_endian, int boundary) {
2380   
2381   decode_IOR(tvb, pinfo, tree, offset, boundary, stream_is_big_endian);
2382   
2383   return;
2384 }
2385
2386
2387 /* Copy a 1 octet sequence from the tvbuff 
2388  * which represents a octet, and convert
2389  * it to an octet value.
2390  * offset is then incremented by 1, to indicate the 1 octet which
2391  * has been processed.
2392  */
2393
2394 guint8 get_CDR_octet(tvbuff_t *tvb, int *offset) {
2395   guint8 val;
2396
2397   val = tvb_get_guint8(tvb, *offset); /* easy */
2398   (*offset)++;
2399   return val;
2400 }
2401
2402
2403 /* Copy a sequence of octets from the tvbuff.
2404  * Caller of this function must remember to free the 
2405  * array pointed to by seq.
2406  * This function also increments offset by len. 
2407  */
2408
2409 void get_CDR_octet_seq(tvbuff_t *tvb, gchar **seq, int *offset, int len) {
2410
2411   if (! tvb_bytes_exist(tvb, *offset,len)) {
2412     /*
2413      * Generate an exception, and stop processing.
2414      * We do that now, rather than after allocating the buffer, so we
2415      * don't have to worry about freeing the buffer.
2416      * XXX - would we be better off using a cleanup routine?
2417      */
2418     tvb_get_guint8(tvb, *offset + len);
2419   }
2420
2421   /*
2422    * XXX - should we just allocate "len" bytes, and have "get_CDR_string()"
2423    * do what we do now, and null-terminate the string (which also means
2424    * we don't need to zero out the entire allocation, just the last byte)?
2425    */
2426   *seq = g_new0(gchar, len + 1);
2427   tvb_memcpy( tvb, *seq, *offset, len);
2428   *offset += len;
2429 }
2430
2431
2432 /* Copy a 2 octet sequence from the tvbuff 
2433  * which represents a signed short value, and convert
2434  * it to a signed short value, taking into account byte order.
2435  * offset is first incremented so that it falls on a proper alignment
2436  * boundary for short values.
2437  * offset is then incremented by 2, to indicate the 2 octets which
2438  * have been processed.
2439  */
2440
2441 gint16 get_CDR_short(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2442
2443   gint16 val;
2444
2445   /* short values must be aligned on a 2 byte boundary */
2446   while( ( (*offset + boundary) % 2) != 0)
2447           ++(*offset);
2448
2449   val = (stream_is_big_endian) ? tvb_get_ntohs (tvb, *offset) :
2450                                  tvb_get_letohs (tvb, *offset);
2451
2452   *offset += 2; 
2453   return val; 
2454 }
2455
2456
2457
2458 /* Copy an octet sequence from the tvbuff 
2459  * which represents a string, and convert
2460  * it to an string value, taking into account byte order.
2461  * offset is first incremented so that it falls on a proper alignment
2462  * boundary for string values. (begins with an unsigned long LI)
2463  *
2464  * String sequence is copied to a  buffer "seq". This must
2465  * be freed by the calling program.
2466  * offset is then incremented, to indicate the  octets which
2467  * have been processed.
2468  *
2469  * returns number of octets in the sequence
2470  *
2471  * Note: This function only supports single byte encoding at the
2472  *       moment until I get a handle on multibyte encoding etc.
2473  *
2474  */
2475
2476
2477 guint32 get_CDR_string(tvbuff_t *tvb, gchar **seq, int *offset, gboolean stream_is_big_endian, 
2478                        int boundary ) {
2479   
2480   guint32 slength;
2481
2482   slength = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get length first */
2483
2484 #if 0
2485   (*offset)++;                  /* must step past \0 delimiter */
2486 #endif
2487   
2488   if (slength > 0) {
2489     get_CDR_octet_seq(tvb, seq, offset, slength);
2490   } else {
2491     *seq = g_strdup("");        /* zero-length string */
2492   }
2493
2494   return slength;               /* return length */
2495
2496 }
2497
2498 /* Process a sequence of octets that represent the 
2499  * Pseudo Object Type "TypeCode". Typecodes are used for example,
2500  * by "Any values". 
2501  * This function also increments offset to the correct position.
2502  *
2503  * It will parse the TypeCode and output data to the "tree" provided
2504  * by the user
2505  *
2506  * It returns a guint32 representing a TCKind value. 
2507  */
2508
2509 guint32 get_CDR_typeCode(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
2510                          gboolean stream_is_big_endian, int boundary,
2511                          MessageHeader * header ) {
2512   guint32 val;
2513
2514   gint16  s_octet2; /* signed int16 */
2515   guint16 u_octet2; /* unsigned int16 */
2516   guint32 u_octet4; /* unsigned int32 */
2517
2518   val = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get TCKind enum */
2519   if (tree) {
2520     proto_tree_add_uint(tree,hf_giop_TCKind,tvb,
2521                         *offset-sizeof(val),4,val);
2522   }
2523
2524   /* Grab the data according to Typecode Table - Corba Chapter 15 */
2525
2526   switch (val) {
2527   case tk_null: /* empty parameter list */
2528     break;
2529   case tk_void: /* empty parameter list */
2530     break;
2531   case tk_short: /* empty parameter list */
2532     break;
2533   case tk_long: /* empty parameter list */
2534     break;
2535   case tk_ushort: /* empty parameter list */
2536     break;
2537   case tk_ulong: /* empty parameter list */
2538     break;
2539   case tk_float: /* empty parameter list */
2540     break;
2541   case tk_double: /* empty parameter list */
2542     break;
2543   case tk_boolean: /* empty parameter list */
2544     break;
2545   case tk_char: /* empty parameter list */
2546     break;
2547   case tk_octet: /* empty parameter list */
2548     break;
2549   case tk_any: /* empty parameter list */
2550     break;
2551   case tk_TypeCode: /* empty parameter list */
2552     break;
2553   case tk_Principal: /* empty parameter list */
2554     break;
2555   case tk_objref: /* complex parameter list */
2556     dissect_tk_objref_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2557     break;
2558   case tk_struct: /* complex parameter list */
2559     dissect_tk_struct_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2560     break;
2561   case tk_union: /* complex parameter list */
2562     dissect_tk_union_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2563     break;
2564   case tk_enum: /* complex parameter list */
2565     dissect_tk_enum_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2566     break;
2567
2568   case tk_string: /* simple parameter list */
2569     u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get maximum length */
2570     if (tree) {
2571       proto_tree_add_uint(tree,hf_giop_typecode_max_length,tvb,
2572                           *offset-sizeof(u_octet4),4,u_octet4);
2573     }
2574     break;
2575
2576   case tk_sequence: /* complex parameter list */
2577     dissect_tk_sequence_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2578     break;
2579   case tk_array: /* complex parameter list */
2580     dissect_tk_array_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2581     break;
2582   case tk_alias: /* complex parameter list */
2583     dissect_tk_alias_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2584     break;
2585   case tk_except: /* complex parameter list */
2586     dissect_tk_except_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2587     break;
2588   case tk_longlong: /* empty parameter list */
2589     break;
2590   case tk_ulonglong: /* empty parameter list */
2591     break;
2592   case tk_longdouble: /* empty parameter list */
2593     break;
2594   case tk_wchar: /* empty parameter list */
2595     break;
2596   case tk_wstring: /* simple parameter list */
2597     u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get maximum length */
2598     if (tree) {
2599       proto_tree_add_uint(tree,hf_giop_typecode_max_length,tvb,
2600                           *offset-sizeof(u_octet4),4,u_octet4);
2601     }
2602     break;
2603
2604   case tk_fixed: /* simple parameter list */
2605     u_octet2 = get_CDR_ushort(tvb,offset,stream_is_big_endian,boundary); /* get digits */
2606     if (tree) {
2607       proto_tree_add_uint(tree,hf_giop_typecode_digits,tvb,
2608                           *offset-sizeof(u_octet2),2,u_octet2);
2609     }
2610
2611     s_octet2 = get_CDR_short(tvb,offset,stream_is_big_endian,boundary); /* get scale */
2612     if (tree) {
2613       proto_tree_add_int(tree,hf_giop_typecode_scale,tvb,
2614                           *offset-sizeof(s_octet2),2,s_octet2);
2615     }
2616     break;
2617
2618   case tk_value: /* complex parameter list */
2619     dissect_tk_value_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2620     break;
2621   case tk_value_box: /* complex parameter list */
2622     dissect_tk_value_box_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2623     break;
2624   case tk_native: /* complex parameter list */
2625     dissect_tk_native_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2626     break;
2627   case tk_abstract_interface: /* complex parameter list */
2628     dissect_tk_abstract_interface_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2629     break;
2630   default:
2631     g_warning("giop: Unknown TCKind %u \n", val);
2632     break;
2633   } /* val */
2634
2635   return val;
2636 }
2637
2638
2639
2640 /* Copy a 4 octet sequence from the tvbuff 
2641  * which represents an unsigned long value, and convert
2642  * it to an unsigned long vaule, taking into account byte order.
2643  * offset is first incremented so that it falls on a proper alignment
2644  * boundary for unsigned long values.
2645  * offset is then incremented by 4, to indicate the 4 octets which
2646  * have been processed.
2647  */
2648
2649 guint32 get_CDR_ulong(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2650
2651   guint32 val;
2652
2653   /* unsigned long values must be aligned on a 4 byte boundary */
2654   while( ( (*offset + boundary) % 4) != 0)
2655           ++(*offset);
2656
2657   val = (stream_is_big_endian) ? tvb_get_ntohl (tvb, *offset) :
2658                                  tvb_get_letohl (tvb, *offset);
2659
2660   *offset += 4; 
2661   return val; 
2662 }
2663
2664
2665 /* Copy a 2 octet sequence from the tvbuff 
2666  * which represents an unsigned short value, and convert
2667  * it to an unsigned short value, taking into account byte order.
2668  * offset is first incremented so that it falls on a proper alignment
2669  * boundary for unsigned short values.
2670  * offset is then incremented by 2, to indicate the 2 octets which
2671  * have been processed.
2672  */
2673
2674 guint16 get_CDR_ushort(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2675
2676   guint16 val;
2677
2678   /* unsigned short values must be aligned on a 2 byte boundary */
2679   while( ( (*offset + boundary) % 2) != 0)
2680           ++(*offset);
2681
2682   val = (stream_is_big_endian) ? tvb_get_ntohs (tvb, *offset) :
2683                                  tvb_get_letohs (tvb, *offset);
2684
2685   *offset += 2; 
2686   return val; 
2687 }
2688
2689
2690
2691 /* Copy a wchar from the tvbuff.
2692  * Caller of this function must remember to free the 
2693  * array pointed to by seq.
2694  * This function also increments offset according to
2695  * the wchar size.
2696  *
2697  * For GIOP 1.1 read 2 octets and return size -2. The
2698  * negation means there is no size element in the packet
2699  * and therefore no size to add to the tree.
2700  *
2701  * For GIOP 1.2 read size of wchar and the size
2702  * octets. size is returned as a gint8.
2703  *
2704  * For both GIOP versions the wchar is returned
2705  * as a printable string.
2706  *
2707  */
2708
2709 /* NOTE: This is very primitive in that it just reads
2710  * the wchar as a series of octets and returns them
2711  * to the user. No translation is attempted based on
2712  * byte orientation, nor on code set. I.e it only 
2713  * really reads past the wchar and sets the offset
2714  * correctly.
2715  */
2716
2717 /* The "decoding" is done according to CORBA chapter 15.
2718  * Wchar is not supported for GIOP 1.0.
2719  */
2720
2721 gint8 get_CDR_wchar(tvbuff_t *tvb, gchar **seq, int *offset, MessageHeader * header) {
2722   
2723   gint8 slength;
2724   gchar *raw_wstring;
2725
2726   /* CORBA chapter 15:
2727    *   - prior to GIOP 1.2 wchar limited to two octet fixed length.
2728    *   - GIOP 1.2 wchar is encoded as an unsigned binary octet
2729    *     followed by the elements of the octet sequence representing
2730    *     the encoded value of the wchar.
2731    */
2732
2733   *seq = NULL; /* set in case GIOP 1.2 length is 0 */
2734   slength = 2; /* set for GIOP 1.1 length in octets */
2735
2736   if (header->GIOP_version.minor > 1) /* if GIOP 1.2 get length of wchar */
2737     slength = get_CDR_octet(tvb,offset);
2738
2739   if (slength > 0) {
2740     /* ??? assume alignment is ok for GIOP 1.1 ??? */
2741     get_CDR_octet_seq(tvb, &raw_wstring, offset, slength);
2742
2743     /* now turn octets (wchar) into something that can be printed by the user */
2744     *seq = make_printable_string(raw_wstring, slength);
2745
2746     g_free(raw_wstring);
2747   }
2748
2749   /* if GIOP 1.1 negate length to indicate not an item to add to tree */
2750   if (header->GIOP_version.minor < 2)
2751     slength = -slength;
2752
2753   return slength;               /* return length */
2754
2755 }
2756
2757
2758 /* Copy a wstring from the tvbuff.
2759  * Caller of this function must remember to free the 
2760  * array pointed to by seq.
2761  * This function also increments offset, according to
2762  * wstring length. length is returned as guint32
2763  */
2764
2765 /* NOTE: This is very primitive in that it just reads
2766  * the wstring as a series of octets and returns them
2767  * to the user. No translation is attempted based on
2768  * byte orientation, nor on code set. I.e it only 
2769  * really reads past the wstring and sets the offset
2770  * correctly.
2771  */
2772
2773 /* The "decoding" is done according to CORBA chapter 15.
2774  * Wstring is not supported for GIOP 1.0.
2775  */
2776
2777
2778 guint32 get_CDR_wstring(tvbuff_t *tvb, gchar **seq, int *offset, gboolean stream_is_big_endian, 
2779                        int boundary, MessageHeader * header) {
2780   
2781   guint32 slength;
2782   gchar *raw_wstring;
2783
2784   /* CORBA chapter 15:
2785    *   - prior to GIOP 1.2 wstring limited to two octet fixed length.
2786    *     length and string are NUL terminated (length???).
2787    *   - GIOP 1.2 length is total number of octets. wstring is NOT NUL
2788    *     terminated.
2789    */
2790
2791   *seq = NULL; /* set in case GIOP 1.2 length is 0 */
2792
2793   /* get length, same for all GIOP versions,
2794    * although for 1.2 CORBA doesnt say, so assume. 
2795    */
2796   slength = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
2797
2798 #ifdef DEBUG
2799   if (slength>200) {
2800         fprintf(stderr, "giop:get_CDR_wstring, length %u > 200, truncating to 5 \n", slength);
2801         slength = 5;            /* better than core dumping during debug */
2802   }
2803 #endif
2804   
2805   if (header->GIOP_version.minor < 2) {
2806 #if 0
2807     (*offset)++;  /* must step past \0 delimiter */
2808 #endif
2809     /* assume length is number of characters and not octets, spec not clear */
2810     slength = slength * 2; /* length in octets is 2 * wstring length */
2811   }
2812
2813   if (slength > 0) {
2814     get_CDR_octet_seq(tvb, &raw_wstring, offset, slength);
2815
2816     /* now turn octets (wstring) into something that can be printed by the user */
2817     *seq = make_printable_string(raw_wstring, slength);
2818
2819     g_free(raw_wstring);
2820   }
2821
2822   return slength;               /* return length */
2823
2824 }
2825
2826
2827
2828 /**
2829  *  Dissects a TargetAddress which is defined in (CORBA 2.4, section 15.4.2)
2830  *  GIOP 1.2
2831  *  typedef short AddressingDisposition;
2832  *  const short KeyAddr = 0;
2833  *  const short ProfileAddr = 1;
2834  *  const short ReferenceAddr = 2;
2835  *  struct IORAddressingInfo {
2836  *    unsigned long selected_profile_index;
2837  *    IOP::IOR ior;
2838  *  };
2839  *
2840  *  union TargetAddress switch (AddressingDisposition) {
2841  *      case KeyAddr: sequence <octet> object_key;
2842  *      case ProfileAddr: IOP::TaggedProfile profile;
2843  *      case ReferenceAddr: IORAddressingInfo ior;
2844  *  };
2845  */
2846
2847 static void
2848 dissect_target_address(tvbuff_t * tvb, packet_info *pinfo, int *offset, proto_tree * tree, 
2849                        MessageHeader * header, gboolean stream_is_big_endian)
2850 {
2851    guint16 discriminant;
2852    gchar *object_key;
2853    gchar *p_object_key;
2854    guint32 len = 0;
2855    guint32 u_octet4;
2856
2857    discriminant = get_CDR_ushort(tvb, offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2858    if(tree)
2859    {
2860      proto_tree_add_text (tree, tvb, *offset -2, 2,
2861                  "TargetAddress Discriminant: %u", discriminant);
2862    }
2863   
2864    switch (discriminant)
2865    {
2866            case 0:  /* KeyAddr */
2867                    len = get_CDR_ulong(tvb, offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2868                    if(tree)
2869                    {
2870                       proto_tree_add_text (tree, tvb, *offset -4, 4,
2871                                            "KeyAddr (object key length): %u", len);
2872                    }
2873
2874                    if (len > 0) {
2875
2876                      get_CDR_octet_seq(tvb, &object_key, offset, len);
2877                      p_object_key = make_printable_string( object_key, len );
2878                    
2879                      if(tree)
2880                        {
2881                          proto_tree_add_text (tree, tvb, *offset -len, len,
2882                                                "KeyAddr (object key): %s", p_object_key);
2883                        }
2884                      g_free( p_object_key );
2885                      g_free( object_key );
2886                    }
2887                    break;
2888            case 1: /* ProfileAddr */
2889                    decode_TaggedProfile(tvb, pinfo, tree, offset, GIOP_HEADER_SIZE,
2890                                         stream_is_big_endian, NULL);
2891                    break;
2892            case 2: /* ReferenceAddr */
2893                    u_octet4 = get_CDR_ulong(tvb, offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2894
2895                    if(tree)
2896                    {
2897                       proto_tree_add_text (tree, tvb, *offset -len -4, 4,
2898                                            "ReferenceAddr (selected_profile_index): %u", u_octet4);
2899                    }
2900
2901                    decode_IOR(tvb, pinfo, tree, offset, GIOP_HEADER_SIZE, stream_is_big_endian);
2902                    break;
2903            default:
2904                    break;
2905    }
2906 }
2907
2908 static void
2909 dissect_reply_body (tvbuff_t *tvb, u_int offset, packet_info *pinfo,
2910                     proto_tree *tree, gboolean stream_is_big_endian,
2911                     guint32 reply_status, MessageHeader *header, proto_tree *clnp_tree) {
2912
2913   u_int sequence_length;
2914   gboolean exres = FALSE;               /* result of trying explicit dissectors */
2915   gchar * repoid = NULL;        /* Repositor ID looked up from  objkey */
2916   
2917   /*
2918    * comp_req_list stuff
2919    */
2920
2921   comp_req_list_entry_t * entry = NULL; /* data element in our list */
2922   
2923   guint32 mfn;
2924
2925   switch (reply_status)
2926     {
2927     case SYSTEM_EXCEPTION:
2928
2929       decode_SystemExceptionReplyBody (tvb, tree, &offset, stream_is_big_endian, GIOP_HEADER_SIZE);
2930       break;
2931
2932     case USER_EXCEPTION:
2933
2934       sequence_length = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2935
2936       if (tree)
2937       {
2938           proto_tree_add_text(tree, tvb, offset-4, 4,
2939                            "Exception length: %u", sequence_length);
2940       }
2941       if (sequence_length != 0)
2942         {
2943           if (tree)
2944           {
2945               proto_tree_add_text(tree, tvb, offset, sequence_length,
2946                            "Exception id: %s",
2947                            tvb_format_text(tvb, offset, sequence_length));
2948           }
2949 #if 1
2950
2951           header->exception_id = g_new0(gchar,sequence_length ); /* allocate buffer */
2952
2953           /* read exception id from buffer and store in*/
2954
2955           tvb_get_nstringz0(tvb,offset,sequence_length, header->exception_id );
2956           
2957
2958 #endif          
2959           
2960
2961           offset += sequence_length;
2962         }
2963
2964
2965
2966       /*
2967        * Now just fall through to the NO_EXCEPTION part
2968        * as this is common .
2969        */
2970       
2971
2972
2973     case NO_EXCEPTION:
2974
2975
2976       /* lookup MFN in hash directly */
2977  
2978       mfn = get_mfn_from_fn(pinfo->fd->num); 
2979       
2980       if (mfn == pinfo->fd->num)
2981         return;                 /* no matching frame number, what am I */
2982
2983       /* get entry for this MFN */
2984       entry = find_fn_in_list(mfn); /* get data entry in complete_request_list */
2985
2986       if (!entry)
2987         return;                 /* no matching entry */
2988         
2989
2990       /*
2991        * If this packet is a REPLY to a RESOLVE(request) 
2992        * then decode IOR.
2993        * TODO - make this lookup faster -- FS
2994        */
2995       
2996       if (!strcmp(giop_op_resolve,entry->operation)) {
2997         decode_IOR(tvb, pinfo, tree, &offset, GIOP_HEADER_SIZE,stream_is_big_endian);
2998         return;         /* done */
2999       }
3000       
3001       /* TODO -- Put stuff here for other "interesting operations" */
3002
3003       /*
3004        *
3005        * Call sub dissector.
3006        * First try an find a explicit sub_dissector, then if that
3007        * fails, try the heuristic method.
3008        */
3009
3010
3011       if(entry->repoid) {    
3012         exres = try_explicit_giop_dissector(tvb,pinfo,clnp_tree, &offset, header, entry->operation, entry->repoid );
3013       }
3014
3015       /* Only call heuristic if no explicit dixxector was found */
3016
3017       if(! exres) {
3018         try_heuristic_giop_dissector(tvb,pinfo,clnp_tree,&offset,header,entry->operation);
3019       } 
3020
3021
3022       break;
3023       
3024     case LOCATION_FORWARD:
3025       decode_IOR(tvb, pinfo, tree, &offset, GIOP_HEADER_SIZE, stream_is_big_endian);
3026
3027       break;
3028
3029     case LOCATION_FORWARD_PERM:
3030       decode_IOR(tvb, pinfo, tree, &offset, GIOP_HEADER_SIZE, stream_is_big_endian);
3031
3032       break;
3033
3034     case NEEDS_ADDRESSING_MODE: {
3035       guint16 addr_disp;
3036       addr_disp = get_CDR_ushort(tvb, &offset, stream_is_big_endian, GIOP_HEADER_SIZE);
3037       if(tree) {
3038         proto_tree_add_text (tree, tvb, offset -2, 2,
3039                              "AddressingDisposition: %u", addr_disp);
3040       }
3041
3042       break;
3043     }
3044
3045     default:
3046       
3047       g_warning("giop: Unknown reply status %i request_id = %u\n",reply_status, header->req_id);
3048       
3049       break;
3050       
3051     } /* switch */
3052   
3053   g_free(repoid);               /* free resource */
3054   
3055   return;                       /* done */
3056   
3057 }
3058
3059
3060
3061
3062
3063 /* The format of the Reply Header for GIOP 1.0 and 1.1
3064  * is documented in Section 15.4.3.1 of the CORBA 2.4 standard.
3065
3066     struct ReplyHeader_1_0 {
3067           IOP::ServiceContextList service_context;
3068           unsigned long request_id;
3069           ReplyStatusType_1_0 reply_status;
3070     };
3071  */
3072
3073 static void dissect_giop_reply (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
3074                                 proto_tree * clnp_tree, MessageHeader * header,
3075                                 gboolean stream_is_big_endian) {
3076
3077   guint32 offset = 0;
3078   guint32 request_id;
3079   guint32 reply_status;
3080   proto_tree *reply_tree = NULL;
3081   proto_item *tf;
3082   guint32 mfn;                  /* matching frame number */
3083
3084   if (tree) {
3085     tf = proto_tree_add_text (tree, tvb, offset, -1,
3086                               "General Inter-ORB Protocol Reply");
3087     if (reply_tree == NULL)
3088       {
3089         reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
3090         
3091       }
3092   }
3093   
3094   /*
3095    * Decode IOP::ServiceContextList
3096    */
3097   
3098   decode_ServiceContextList(tvb, pinfo, reply_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3099
3100   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3101
3102   if (check_col(pinfo->cinfo, COL_INFO)) {
3103     col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3104   }
3105
3106   if (tree) {
3107     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3108                          "Request id: %u", request_id);
3109   }
3110
3111   reply_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3112
3113   if (check_col(pinfo->cinfo, COL_INFO)) {
3114     col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
3115                     val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3116
3117   }
3118
3119   if (tree) {
3120     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3121                          "Reply status: %s",
3122                          val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3123     
3124   }
3125
3126   /*
3127    * Save FN and MFN in complete_reply_hash, only if user is NOT clicking
3128    */
3129
3130   if (! pinfo->fd->flags.visited) {
3131     mfn = get_mfn_from_fn_and_reqid(pinfo->fd->num,request_id); /* find MFN for this FN */
3132     if (mfn != pinfo->fd->num) { /* if mfn is not fn, good */
3133       insert_in_complete_reply_hash(pinfo->fd->num, mfn);
3134     }
3135   }
3136
3137   header->req_id = request_id;          /* save for sub dissector */
3138   header->rep_status = reply_status;   /* save for sub dissector */
3139
3140   dissect_reply_body(tvb, offset, pinfo, reply_tree, stream_is_big_endian,
3141     reply_status, header,tree);
3142
3143
3144 }
3145
3146 /** The format of the GIOP 1.2 Reply header is very similar to the 1.0
3147  *  and 1.1 header, only the fields have been rearranged.  From Section
3148  *  15.4.3.1 of the CORBA 2.4 specification:
3149  *
3150  *   struct ReplyHeader_1_2 {
3151  *         unsigned long request_id;
3152  *         ReplyStatusType_1_2 reply_status;
3153  *         IOP:ServiceContextList service_context; 
3154  *    };
3155  */
3156
3157 static void dissect_giop_reply_1_2 (tvbuff_t * tvb, packet_info * pinfo,
3158                                     proto_tree * tree, proto_tree * clnp_tree,
3159                                     MessageHeader * header,
3160                                     gboolean stream_is_big_endian) {
3161
3162   u_int offset = 0;
3163   guint32 request_id;
3164   guint32 reply_status;
3165   proto_tree *reply_tree = NULL;
3166   proto_item *tf;
3167   guint32 mfn;                  /* matching frame number */
3168   
3169   if (tree) {
3170     tf = proto_tree_add_text (tree, tvb, offset, -1,
3171                               "General Inter-ORB Protocol Reply");
3172     reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
3173   }
3174   
3175   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3176   
3177   if (check_col(pinfo->cinfo, COL_INFO)) {
3178     col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3179   }
3180
3181   if (tree) {
3182     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3183                          "Request id: %u", request_id);
3184   }
3185
3186   reply_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3187   
3188   if (check_col(pinfo->cinfo, COL_INFO)) {
3189     col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
3190                     val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3191
3192   }
3193
3194   if (tree) {
3195     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3196                          "Reply status: %s",
3197                          val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3198
3199   }
3200
3201   /*
3202    * Decode IOP::ServiceContextList
3203    */
3204
3205   decode_ServiceContextList(tvb, pinfo, reply_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3206
3207   /*
3208    * GIOP 1.2 Reply body must fall on an 8 octet alignment.
3209    */
3210
3211   set_new_alignment(&offset, GIOP_HEADER_SIZE, 8);
3212
3213   /*
3214    * Save FN and MFN in complete_reply_hash, only if user is NOT clicking
3215    */
3216   
3217   if (! pinfo->fd->flags.visited) {
3218     mfn = get_mfn_from_fn_and_reqid(pinfo->fd->num,request_id); /* find MFN for this FN */
3219     if (mfn != pinfo->fd->num) { /* if mfn is not fn, good */
3220       insert_in_complete_reply_hash(pinfo->fd->num, mfn);
3221     }
3222   }
3223
3224   /*
3225    * Add header to argument list so sub dissector can get header info.
3226    */
3227
3228   header->req_id = request_id;          /* save for sub dissector */
3229   header->rep_status = reply_status;   /* save for sub dissector */
3230
3231   dissect_reply_body(tvb, offset, pinfo, reply_tree, stream_is_big_endian,
3232                      reply_status,header,tree);
3233
3234 }
3235
3236
3237
3238 static void dissect_giop_cancel_request (tvbuff_t * tvb, packet_info * pinfo,
3239                         proto_tree * tree, proto_tree * clnp_tree,
3240                         MessageHeader * header, gboolean stream_is_big_endian) {
3241
3242   u_int offset = 0;
3243   guint32 request_id;
3244   proto_tree *cancel_request_tree = NULL;
3245   proto_item *tf;
3246
3247   if (tree) {
3248     tf = proto_tree_add_text (tree, tvb, offset, -1,
3249                               "General Inter-ORB Protocol CancelRequest");
3250     cancel_request_tree = proto_item_add_subtree (tf, ett_giop_cancel_request);
3251   }
3252
3253   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3254   
3255   if (check_col(pinfo->cinfo, COL_INFO)) {
3256     col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3257   }
3258
3259   if (tree) {
3260     proto_tree_add_text (cancel_request_tree, tvb, offset-4, 4,
3261                          "Request id: %u", request_id);
3262   }
3263
3264   
3265 }
3266
3267 /**  The formats for GIOP 1.0 and 1.1 Request messages are defined
3268  *   in section 15.4.2.1 of the CORBA 2.4 specification.
3269  *
3270  *   struct RequestHeader{
3271  *          IOP::ServiceContextList   service_context;
3272  *          unsigned long             request_id;
3273  *          boolean                   response_expected;
3274  *          octet                     reserved[3];  // Only in GIOP 1.1
3275  *          sequence<octet>           object_key;
3276  *          string                    operation;
3277  *          CORBA::OctetSeq           requesting_principal;
3278  *   }
3279  */
3280 static void
3281 dissect_giop_request_1_1 (tvbuff_t * tvb, packet_info * pinfo,
3282                         proto_tree * tree, proto_tree * clnp_tree,
3283                         MessageHeader * header, gboolean stream_is_big_endian)
3284 {
3285   guint32 offset = 0;
3286   guint32 request_id;
3287   guint32 len = 0;
3288
3289   guint32 objkey_len = 0;       /* object key length */
3290   gchar *objkey = NULL;         /* object key sequence */
3291   gchar *print_objkey;          /* printable object key sequence */
3292   gboolean exres = FALSE;       /* result of trying explicit dissectors */
3293
3294   gchar *operation;
3295   gchar *requesting_principal;
3296   gchar *print_requesting_principal;
3297   guint8 response_expected;
3298   gchar *reserved;
3299   proto_tree *request_tree = NULL;
3300   proto_item *tf;
3301
3302   gchar *repoid = NULL;         /* from object key lookup in objkey hash */
3303
3304
3305   if (tree)
3306     {
3307       tf = proto_tree_add_text (tree, tvb, offset, -1,
3308                                 "General Inter-ORB Protocol Request");
3309       if (request_tree == NULL)
3310         {
3311           request_tree = proto_item_add_subtree (tf, ett_giop_request);
3312
3313         }
3314     }
3315
3316
3317
3318
3319   /*
3320    * Decode IOP::ServiceContextList
3321    */
3322   
3323   decode_ServiceContextList(tvb, pinfo, request_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3324
3325
3326   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3327   if (check_col(pinfo->cinfo, COL_INFO))
3328     {
3329       col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3330     }
3331   if (tree)
3332     {
3333       proto_tree_add_text (request_tree, tvb, offset-4, 4,
3334                            "Request id: %u", request_id);
3335     }
3336
3337   response_expected = tvb_get_guint8( tvb, offset );
3338   offset += 1;
3339   if (check_col(pinfo->cinfo, COL_INFO))
3340     {
3341       col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)",
3342                 response_expected ? "two-way" : "one-way");
3343     }
3344   if (tree)
3345     {
3346       proto_tree_add_text (request_tree, tvb, offset-1, 1,
3347                            "Response expected: %u", response_expected);
3348     }
3349
3350   if( header->GIOP_version.minor > 0)
3351   {
3352      get_CDR_octet_seq( tvb, &reserved, &offset, 3);
3353      if (tree)
3354        {
3355          proto_tree_add_text (request_tree, tvb, offset-3, 3,
3356                            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
3357        }
3358      g_free(reserved);
3359   }
3360
3361
3362
3363   /* Length of object_key sequence */
3364   objkey_len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3365
3366
3367   if(tree)
3368   {
3369          proto_tree_add_text (request_tree, tvb, offset-4, 4,
3370          /**/                 "Object Key length: %u", objkey_len);
3371   } 
3372
3373   if (objkey_len > 0)
3374   {
3375        get_CDR_octet_seq(tvb, &objkey, &offset, objkey_len);
3376
3377        print_objkey = make_printable_string(objkey, objkey_len);
3378
3379        if(tree)
3380        {
3381          proto_tree_add_text (request_tree, tvb, offset - objkey_len, objkey_len,
3382          /**/                 "Object Key: %s", print_objkey);
3383
3384        }
3385
3386        g_free( print_objkey );  
3387   } 
3388
3389   /*
3390    * Register a cleanup function in case on of our tvbuff accesses
3391    * throws an exception. We need to clean up objkey.
3392    */
3393   CLEANUP_PUSH(g_free, objkey);
3394
3395   /* length of operation string and string */ 
3396   len = get_CDR_string(tvb, &operation, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3397   if(tree)
3398   {
3399          proto_tree_add_text (request_tree, tvb, offset - 4 - len, 4,
3400          /**/                 "Operation length: %u", len);
3401   } 
3402
3403   if( len > 0)
3404   {
3405        if (check_col(pinfo->cinfo, COL_INFO))
3406        {
3407          col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", operation);
3408        }
3409        if(tree)
3410        {
3411          proto_tree_add_text (request_tree, tvb, offset - len, len,
3412          /**/                 "Operation: %s", operation);
3413
3414        }
3415   }
3416
3417   /*
3418    * Register a cleanup function in case on of our tvbuff accesses
3419    * throws an exception. We need to clean up operation.
3420    */
3421   CLEANUP_PUSH(g_free, operation);
3422
3423   /* length of requesting_principal string */ 
3424   len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3425   if(tree)
3426   {
3427          proto_tree_add_text (request_tree, tvb, offset-4, 4,
3428          /**/                 "Requesting Principal Length: %u", len);
3429   } 
3430
3431   if( len > 0)
3432   {
3433        get_CDR_octet_seq(tvb, &requesting_principal, &offset, len);
3434
3435        print_requesting_principal = make_printable_string(requesting_principal, len);
3436
3437        if(tree)
3438        {
3439          proto_tree_add_text (request_tree, tvb, offset - len, len, 
3440          /**/                 "Requesting Principal: %s", print_requesting_principal);
3441
3442        }
3443
3444        g_free( print_requesting_principal );
3445        g_free( requesting_principal );
3446   }
3447
3448
3449   /*
3450    * Save FN,reqid,and operation for later. Add sub_handle later.
3451    * But only if user is NOT clicking.
3452    */
3453
3454   if (! pinfo->fd->flags.visited)
3455     giop_complete_request_list = insert_in_comp_req_list(giop_complete_request_list,pinfo->fd->num,
3456                                                          request_id,operation,NULL);
3457
3458   
3459   /*
3460    * Call subdissector here before freeing "operation" and "key"
3461    * pass request_id also. 
3462    * First try an find an explicit sub_dissector, then if that
3463    * fails, try the heuristic method.
3464    *
3465    */
3466
3467
3468   header->req_id = request_id;          /* save for sub dissector */
3469   repoid = get_repoid_from_objkey(giop_objkey_hash,objkey,objkey_len);
3470
3471
3472   if(repoid) {    
3473     exres = try_explicit_giop_dissector(tvb,pinfo,tree,&offset,header,operation,repoid);
3474   }
3475
3476   /* Only call heuristic if no explicit dissector was found */
3477
3478   if (! exres) {
3479     try_heuristic_giop_dissector(tvb,pinfo,tree,&offset,header,operation);
3480   }
3481   
3482
3483   /*
3484    * We're done with operation, so we can call the cleanup handler to free
3485    * it, and then pop the cleanup handler.
3486    */
3487   CLEANUP_CALL_AND_POP;
3488
3489   /*
3490    * We're done with objkey, so we can call the cleanup handler to free
3491    * it, and then pop the cleanup handler.
3492    */
3493   CLEANUP_CALL_AND_POP;
3494
3495 }
3496
3497 /**  The format of a GIOP 1.2 RequestHeader message is 
3498  *   (CORBA 2.4, sec. 15.4.2):
3499  *
3500  *   struct RequestHeader_1_2 {
3501  *       unsigned long request_id;
3502  *       octet response_flags;
3503  *       octet reserved[3];
3504  *       TargetAddress target;
3505  *       string operation;
3506  *       IOP::ServiceContextList service_context;
3507  *       // requesting_principal not in GIOP 1.2
3508  *   };
3509  */
3510 static void
3511 dissect_giop_request_1_2 (tvbuff_t * tvb, packet_info * pinfo,
3512                         proto_tree * tree, proto_tree * clnp_tree,
3513                         MessageHeader * header, gboolean stream_is_big_endian)
3514 {
3515   guint32 offset = 0;
3516   guint32 request_id;
3517   guint32 len = 0;
3518   guint8 response_flags;
3519   gchar *reserved;
3520   gchar *operation = NULL;
3521   proto_tree *request_tree = NULL;
3522   proto_item *tf;
3523   gboolean exres = FALSE;               /* result of trying explicit dissectors */
3524
3525   gchar *repoid = NULL;
3526
3527
3528   if (tree)
3529     {
3530       tf = proto_tree_add_text (tree, tvb, offset, -1,
3531                                 "General Inter-ORB Protocol Request");
3532       request_tree = proto_item_add_subtree (tf, ett_giop_reply);
3533     }
3534
3535   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3536   if (check_col(pinfo->cinfo, COL_INFO))
3537     {
3538       col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3539     }
3540   if (request_tree)
3541     {
3542       proto_tree_add_text (request_tree, tvb, offset-4, 4,
3543                            "Request id: %u", request_id);
3544     }
3545
3546   response_flags = tvb_get_guint8( tvb, offset );
3547   offset += 1;
3548   if (request_tree)
3549     {
3550       proto_tree_add_text (request_tree, tvb, offset-1, 1,
3551                            "Response flags: %s (%u)",
3552                                 match_strval(response_flags, sync_scope),  
3553                                 response_flags);
3554     }
3555
3556   get_CDR_octet_seq( tvb, &reserved, &offset, 3);
3557   if (request_tree)
3558    {
3559      proto_tree_add_text (request_tree, tvb, offset-3, 3,
3560            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
3561    }
3562   g_free(reserved);
3563
3564   dissect_target_address(tvb, pinfo, &offset, request_tree, header, stream_is_big_endian);
3565
3566   /* length of operation string */ 
3567   len = get_CDR_string(tvb, &operation, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3568   if(tree)
3569   {
3570          proto_tree_add_text (request_tree, tvb, offset - len - 4, 4,
3571          /**/                 "Operation length: %u", len);
3572   } 
3573
3574   if( len > 0)
3575   {
3576        if (check_col(pinfo->cinfo, COL_INFO))
3577        {
3578          col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", operation);
3579        }
3580        if(request_tree)
3581        {
3582          proto_tree_add_text (request_tree, tvb, offset - len, len,
3583          /**/                 "Operation: %s", operation);
3584
3585        }
3586
3587   }
3588
3589   /*
3590    * Register a cleanup function in case on of our tvbuff accesses
3591    * throws an exception. We need to clean up operation.
3592    */
3593   CLEANUP_PUSH(g_free, operation);
3594
3595   /*
3596    * Decode IOP::ServiceContextList
3597    */
3598
3599   decode_ServiceContextList(tvb, pinfo, request_tree, &offset,  stream_is_big_endian, GIOP_HEADER_SIZE);
3600
3601   /*
3602    * GIOP 1.2 Request body must fall on an 8 octet alignment, taking into
3603    * account we are in a new tvbuff, GIOP_HEADER_SIZE octets from the
3604    * GIOP octet stream start.
3605    */
3606
3607   set_new_alignment(&offset, GIOP_HEADER_SIZE, 8);
3608
3609   /*
3610    * Save FN,reqid,and operation for later. Add sub_handle later.
3611    * But only if user is NOT clicking.
3612    */
3613   
3614   if (! pinfo->fd->flags.visited)
3615     giop_complete_request_list = insert_in_comp_req_list(giop_complete_request_list,pinfo->fd->num,
3616                                                          request_id,operation,NULL);
3617
3618   /*
3619    *
3620    * Call sub dissector.
3621    * First try an find a explicit sub_dissector, then if that
3622    * fails, try the heuristic method.
3623    */
3624   
3625
3626   if(repoid) {    
3627     exres = try_explicit_giop_dissector(tvb,pinfo,tree,&offset,header,operation,repoid);
3628   }
3629
3630   /* Only call heuristic if no explicit dissector was found */
3631
3632   if (! exres) {
3633     try_heuristic_giop_dissector(tvb,pinfo,tree,&offset,header,operation);
3634   }
3635   
3636
3637   /*
3638    * We're done with operation, so we can call the cleanup handler to free
3639    * it, and then pop the cleanup handler.
3640    */
3641   CLEANUP_CALL_AND_POP;
3642 }
3643
3644 static void
3645 dissect_giop_locate_request( tvbuff_t * tvb, packet_info * pinfo,
3646                         proto_tree * tree, MessageHeader * header,
3647                         gboolean stream_is_big_endian)
3648 {
3649   guint32 offset = 0;
3650   guint32 request_id;
3651   guint32 len = 0;
3652   gchar *object_key;
3653   gchar *p_object_key;
3654   proto_tree *locate_request_tree = NULL;
3655   proto_item *tf;
3656
3657   if (tree)
3658     {
3659       tf = proto_tree_add_text (tree, tvb, offset, -1,
3660                                 "General Inter-ORB Locate Request");
3661       if (locate_request_tree == NULL)
3662         {
3663           locate_request_tree = proto_item_add_subtree (tf, ett_giop_locate_request);
3664
3665         }
3666     }
3667
3668   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3669   if (check_col(pinfo->cinfo, COL_INFO))
3670     {
3671       col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3672     }
3673   if (locate_request_tree)
3674     {
3675       proto_tree_add_text (locate_request_tree, tvb, offset-4, 4,
3676                            "Request id: %u", request_id);
3677     }
3678
3679   if(header->GIOP_version.minor < 2)
3680   {
3681         len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3682         if (locate_request_tree)
3683           {
3684             proto_tree_add_text (locate_request_tree, tvb, offset-4, 4,
3685                                  "Object Key length: %u", len);
3686           }
3687
3688         if (len > 0) {
3689           get_CDR_octet_seq(tvb, &object_key, &offset, len);
3690
3691           p_object_key = make_printable_string(object_key, len);
3692   
3693           if(locate_request_tree)
3694             {
3695
3696               proto_tree_add_text (locate_request_tree, tvb, offset-len, len,
3697                                    "Object Key: %s", p_object_key);
3698             }
3699
3700           g_free(p_object_key);
3701           g_free(object_key);
3702         }
3703   }
3704   else     /* GIOP 1.2 and higher */
3705   {
3706       dissect_target_address(tvb, pinfo, &offset, locate_request_tree, header,
3707                              stream_is_big_endian);
3708
3709   }
3710 }
3711
3712 static void
3713 dissect_giop_locate_reply( tvbuff_t * tvb, packet_info * pinfo,
3714                         proto_tree * tree, MessageHeader * header,
3715                         gboolean stream_is_big_endian)
3716 {
3717   guint32 offset = 0;
3718   guint32 request_id;
3719   guint32 locate_status;
3720   guint16 addr_disp;
3721
3722   proto_tree *locate_reply_tree = NULL;
3723   proto_item *tf;
3724
3725   if (tree)
3726     {
3727       tf = proto_tree_add_text (tree, tvb, offset, -1,
3728                                 "General Inter-ORB Locate Reply");
3729       if (locate_reply_tree == NULL)
3730         {
3731           locate_reply_tree = proto_item_add_subtree (tf, ett_giop_locate_reply);
3732
3733         }
3734     }
3735
3736   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3737   if (check_col(pinfo->cinfo, COL_INFO))
3738     {
3739       col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3740     }
3741   if (locate_reply_tree)
3742     {
3743       proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
3744                            "Request id: %u", request_id);
3745     }
3746
3747   locate_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3748   if (locate_reply_tree)
3749     {
3750       proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
3751                            "Locate status: %s", 
3752                            match_strval(locate_status, giop_locate_status_types)
3753                            );
3754     }
3755
3756   /* Decode the LocateReply body.
3757    *
3758    * For GIOP 1.0 and 1.1 body immediately follows header.
3759    * For GIOP 1.2 it is aligned on 8 octet boundary so need to
3760    * spin up.
3761    */
3762
3763   if (header->GIOP_version.minor > 1) {
3764     while( ( (offset + GIOP_HEADER_SIZE) % 8) != 0)
3765       ++(offset);
3766   }
3767
3768   switch(locate_status) {
3769   case OBJECT_FORWARD: /* fall through to OBJECT_FORWARD_PERM */
3770   case OBJECT_FORWARD_PERM:
3771     decode_IOR(tvb, pinfo, locate_reply_tree, &offset, GIOP_HEADER_SIZE, stream_is_big_endian);
3772     break;
3773   case LOC_SYSTEM_EXCEPTION:
3774     decode_SystemExceptionReplyBody (tvb, tree, &offset, stream_is_big_endian, GIOP_HEADER_SIZE);
3775     break;
3776   case LOC_NEEDS_ADDRESSING_MODE:
3777     addr_disp = get_CDR_ushort(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3778     if(locate_reply_tree) {
3779       proto_tree_add_text (tree, tvb, offset -2, 2,
3780                            "AddressingDisposition: %u", addr_disp);
3781     }
3782     break;
3783   default: /* others have no reply body */
3784     break;
3785   }
3786
3787 }
3788
3789 static void
3790 dissect_giop_fragment( tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
3791                         MessageHeader * header, gboolean stream_is_big_endian)
3792 {
3793   guint32 offset = 0;
3794   guint32 request_id;
3795   proto_tree *fragment_tree = NULL;
3796   proto_item *tf;
3797
3798   if (tree)
3799     {
3800       tf = proto_tree_add_text (tree, tvb, offset, -1,
3801                                 "General Inter-ORB Fragment");
3802       if (fragment_tree == NULL)
3803         {
3804           fragment_tree = proto_item_add_subtree (tf, ett_giop_fragment);
3805
3806         }
3807     }
3808
3809   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3810   if (check_col(pinfo->cinfo, COL_INFO))
3811     {
3812       col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3813     }
3814   if (fragment_tree )
3815     {
3816       proto_tree_add_text (fragment_tree, tvb, offset-4, 4,
3817                            "Request id: %u", request_id);
3818     }
3819                                    
3820 }
3821
3822
3823 /* Main entry point */
3824
3825 gboolean dissect_giop (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) {
3826   u_int offset = 0;
3827   MessageHeader header;
3828   tvbuff_t *giop_header_tvb;
3829   tvbuff_t *payload_tvb;
3830
3831   proto_tree *clnp_tree = NULL;
3832   proto_item *ti;
3833   u_int message_size;
3834   u_int minor_version;
3835   gboolean stream_is_big_endian;
3836
3837
3838   /* DEBUG */
3839   
3840 #if DEBUG
3841   giop_dump_collection(cd_module_hash);
3842   giop_dump_collection(cd_objkey_hash);
3843   giop_dump_collection(cd_heuristic_users);
3844   giop_dump_collection(cd_complete_reply_hash);
3845   giop_dump_collection(cd_complete_request_list);
3846 #endif
3847
3848   header.exception_id = NULL;
3849
3850   /* check magic number and version */
3851
3852
3853   /*define END_OF_GIOP_MESSAGE (offset - first_offset - GIOP_HEADER_SIZE) */
3854
3855   if (tvb_length_remaining(tvb, 0) < GIOP_HEADER_SIZE)
3856     {
3857       /* Not enough data captured to hold the GIOP header; don't try
3858          to interpret it as GIOP. */
3859       return FALSE;
3860     }
3861
3862   giop_header_tvb = tvb_new_subset (tvb, 0, GIOP_HEADER_SIZE, -1);
3863   payload_tvb = tvb_new_subset (tvb, GIOP_HEADER_SIZE, -1, -1);
3864   
3865   /*
3866    * because I have added extra elements in MessageHeader struct
3867    * for sub dissectors. -- FS
3868    */
3869
3870   tvb_memcpy (giop_header_tvb, (guint8 *)&header, 0, GIOP_HEADER_SIZE );
3871
3872   if (memcmp (header.magic, GIOP_MAGIC, sizeof (header.magic)) != 0)
3873     {
3874       /* Not a GIOP message. */
3875
3876       return FALSE;
3877     }
3878
3879   if (check_col (pinfo->cinfo, COL_PROTOCOL))
3880     {
3881       col_set_str (pinfo->cinfo, COL_PROTOCOL, "GIOP");
3882     }
3883
3884   if (header.GIOP_version.major != GIOP_MAJOR ||
3885       ((minor_version = header.GIOP_version.minor) > GIOP_MINOR))
3886     {
3887       /* Bad version number; should we note that and dissect the rest
3888          as data, or should we return FALSE on the theory that it
3889          might have been some other packet that happened to begin with
3890          "GIOP"?  We shouldn't do *both*, so we return TRUE, for now.
3891          If we should return FALSE, we should do so *without* setting
3892          the "Info" column, *without* setting the "Protocol" column,
3893          and *without* adding anything to the protocol tree. */
3894
3895       if (check_col (pinfo->cinfo, COL_INFO))
3896         {
3897           col_add_fstr (pinfo->cinfo, COL_INFO, "Version %u.%u",
3898                         header.GIOP_version.major, header.GIOP_version.minor);
3899         }
3900       if (tree)
3901         {
3902           ti = proto_tree_add_item (tree, proto_giop, tvb, 0, -1, FALSE);
3903           clnp_tree = proto_item_add_subtree (ti, ett_giop);
3904           proto_tree_add_text (clnp_tree, giop_header_tvb, 0, -1,
3905                                "Version %u.%u not supported",
3906                                header.GIOP_version.major,
3907                                header.GIOP_version.minor);
3908         }
3909       call_dissector(data_handle,payload_tvb, pinfo, tree);
3910       return TRUE;
3911     }
3912
3913   if (check_col (pinfo->cinfo, COL_INFO)) 
3914   { 
3915       col_add_fstr (pinfo->cinfo, COL_INFO, "GIOP %u.%u %s",
3916                     header.GIOP_version.major, header.GIOP_version.minor,
3917                     val_to_str(header.message_type, giop_message_types,
3918                                "Unknown message type (0x%02x)"));
3919   }
3920
3921   stream_is_big_endian = is_big_endian (&header);
3922
3923   if (stream_is_big_endian)
3924     message_size = pntohl (&header.message_size);
3925   else
3926     message_size = pletohl (&header.message_size);
3927
3928   if (tree)
3929     {
3930       ti = proto_tree_add_item (tree, proto_giop, tvb, 0, 12, FALSE);
3931       clnp_tree = proto_item_add_subtree (ti, ett_giop);
3932       proto_tree_add_text (clnp_tree, giop_header_tvb, offset, 4,
3933                            "Magic number: %s", GIOP_MAGIC);
3934       proto_tree_add_text (clnp_tree, giop_header_tvb, 4, 2,
3935                            "Version: %u.%u",
3936                            header.GIOP_version.major,
3937                            header.GIOP_version.minor);
3938       switch (minor_version)
3939         {
3940         case 2:
3941         case 1:
3942           proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
3943                                "Flags: 0x%02x (%s %s)",
3944                                header.flags,
3945                                (stream_is_big_endian) ? "big-endian" : "little-endian",
3946                                (header.flags & 0x02) ? " fragment" : "");
3947           break;
3948         case 0:
3949           proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
3950                                "Byte ordering: %s-endian",
3951                                (stream_is_big_endian) ? "big" : "little");
3952           break;
3953         default:
3954           break;
3955         }                       /* minor_version */
3956
3957       proto_tree_add_uint_format (clnp_tree,
3958                                   hf_giop_message_type,
3959                                   giop_header_tvb, 7, 1,
3960                                   header.message_type,
3961                                   "Message type: %s", match_strval(header.message_type, giop_message_types));
3962
3963       proto_tree_add_uint (clnp_tree,
3964                            hf_giop_message_size,
3965                            giop_header_tvb, 8, 4, message_size);
3966
3967     }                           /* tree */
3968
3969 #if 0
3970   if (check_col (pinfo->cinfo, COL_INFO)) 
3971   { 
3972       col_add_fstr (pinfo->cinfo, COL_INFO, "GIOP %u.%u %s",
3973                     header.GIOP_version.major, header.GIOP_version.minor,
3974                     match_strval(header.message_type, giop_message_types));
3975   }
3976 #endif
3977
3978   switch (header.message_type)
3979     {
3980
3981     case Request:
3982       if(header.GIOP_version.minor < 2)
3983       {
3984            dissect_giop_request_1_1 (payload_tvb, pinfo, tree, clnp_tree,
3985                                      &header, stream_is_big_endian);
3986       }
3987       else
3988       {    
3989            dissect_giop_request_1_2 (payload_tvb, pinfo, tree, clnp_tree,
3990                                      &header, stream_is_big_endian);
3991       }
3992       
3993       break;
3994
3995
3996     case Reply:
3997       if(header.GIOP_version.minor < 2)
3998         {
3999            dissect_giop_reply (payload_tvb, pinfo, tree, clnp_tree, &header,
4000                                stream_is_big_endian);
4001         }
4002       else
4003         {
4004            dissect_giop_reply_1_2 (payload_tvb, pinfo, tree, clnp_tree,
4005                                    &header, stream_is_big_endian);
4006         }
4007       break;
4008     case CancelRequest:
4009         dissect_giop_cancel_request(payload_tvb, pinfo, tree, clnp_tree,
4010                                     &header, stream_is_big_endian);
4011         break;
4012     case LocateRequest:
4013         dissect_giop_locate_request(payload_tvb, pinfo, tree, &header,
4014                                     stream_is_big_endian);
4015         break;
4016     case LocateReply:
4017         dissect_giop_locate_reply(payload_tvb, pinfo, tree, &header,
4018                                   stream_is_big_endian);
4019         break;
4020     case Fragment:
4021         dissect_giop_fragment(payload_tvb, pinfo, tree, &header,
4022                               stream_is_big_endian);
4023         break;  
4024     default:
4025       break;
4026
4027     }                           /* switch message_type */
4028
4029
4030   /*
4031    * XXX - we should catch exceptions here, so that we can free
4032    * this if an exception is thrown.
4033    * We'd then have to forward the exception.
4034    */
4035   if (header.exception_id != NULL)
4036     g_free(header.exception_id);
4037
4038   return TRUE;
4039 }
4040
4041 void
4042 proto_register_giop (void)
4043 {
4044   static hf_register_info hf[] = {
4045     { &hf_giop_message_type,
4046      { "Message type", "giop.type",
4047        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4048     },
4049     
4050     { &hf_giop_message_size,
4051       { "Message size", "giop.len",
4052         FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4053     },
4054
4055     { &hf_giop_repoid,
4056      { "Repository ID", "giop.repoid",
4057        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4058     },
4059
4060     { &hf_giop_string_length,
4061      { "String Length", "giop.strlen",
4062        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4063     },
4064
4065     { &hf_giop_sequence_length,
4066      { "Sequence Length", "giop.seqlen",
4067        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4068     },
4069
4070     { &hf_giop_profile_id,
4071      { "Profile ID", "giop.profid",
4072        FT_UINT32, BASE_DEC, VALS(profile_id_vals), 0x0, "", HFILL }
4073     },
4074
4075
4076     { &hf_giop_type_id,
4077      { "IOR::type_id", "giop.typeid",
4078        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4079     },
4080
4081     { &hf_giop_iiop_v_maj,
4082      { "IIOP Major Version", "giop.iiop_vmaj",
4083        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4084     }
4085     ,
4086     { &hf_giop_iiop_v_min,
4087      { "IIOP Minor Version", "giop.iiop_vmin",
4088        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4089     },
4090
4091     { &hf_giop_endianess,
4092      { "Endianess", "giop.endianess",
4093        FT_UINT8, BASE_DEC, VALS(giop_endianess_vals), 0x0, "", HFILL }
4094     },
4095
4096     { &hf_giop_IIOP_tag,
4097      { "IIOP Component TAG", "giop.iioptag",
4098        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4099     },
4100
4101     { &hf_giop_IOR_tag,
4102      { "IOR Profile TAG", "giop.iortag",
4103        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4104     },
4105
4106     { &hf_giop_TCKind,
4107      { "TypeCode enum", "giop.TCKind",
4108        FT_UINT32, BASE_DEC, VALS(tckind_vals), 0x0, "", HFILL }
4109     },
4110
4111     { &hf_giop_typecode_count,
4112      { "TypeCode count", "giop.tccount",
4113        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4114     },
4115
4116     { &hf_giop_typecode_default_used,
4117      { "default_used", "giop.tcdefault_used",
4118        FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL }
4119     },
4120
4121     { &hf_giop_typecode_digits,
4122      { "Digits", "giop.tcdigits",
4123        FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
4124     },
4125
4126
4127     { &hf_giop_typecode_length,
4128      { "Length", "giop.tclength",
4129        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4130     },
4131
4132     { &hf_giop_typecode_max_length,
4133      { "Maximum length", "giop.tcmaxlen",
4134        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4135     },
4136
4137     { &hf_giop_typecode_member_name,
4138      { "TypeCode member name", "giop.tcmemname",
4139        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4140     },
4141
4142     { &hf_giop_typecode_name,
4143      { "TypeCode name", "giop.tcname",
4144        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4145     },
4146
4147     { &hf_giop_typecode_scale,
4148      { "Scale", "giop.tcscale",
4149        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4150     },
4151
4152     { &hf_giop_typecode_ValueModifier,
4153      { "ValueModifier", "giop.tcValueModifier",
4154        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4155     },
4156
4157     { &hf_giop_typecode_Visibility,
4158      { "Visibility", "giop.tcVisibility",
4159        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4160     },
4161
4162
4163
4164     { &hf_giop_type_boolean,
4165       { "TypeCode boolean data", "giop.tcboolean",
4166         FT_BOOLEAN, BASE_DEC,  NULL, 0x0, "", HFILL }
4167     },
4168
4169     { &hf_giop_type_char,
4170       { "TypeCode char data", "giop.tcchar",
4171         FT_UINT8, BASE_DEC,  NULL, 0x0, "", HFILL }
4172     },
4173
4174     { &hf_giop_type_double,
4175       { "TypeCode double data", "giop.tcdouble",
4176         FT_DOUBLE, BASE_DEC,  NULL, 0x0, "", HFILL }
4177     },
4178
4179     { &hf_giop_type_enum,
4180      { "TypeCode enum data", "giop.tcenumdata",
4181        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4182     },
4183
4184     /*
4185      * float as double ?? -- FIX
4186      */
4187
4188     { &hf_giop_type_float,
4189       { "TypeCode float data", "giop.tcfloat",
4190         FT_DOUBLE, BASE_DEC,  NULL, 0x0, "", HFILL }
4191     },
4192
4193     { &hf_giop_type_long,
4194      { "TypeCode long data", "giop.tclongdata",
4195        FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL }
4196     },
4197
4198     { &hf_giop_type_octet,
4199       { "TypeCode octet data", "giop.tcoctet",
4200         FT_UINT8, BASE_DEC,  NULL, 0x0, "", HFILL }
4201     },
4202
4203     { &hf_giop_type_short,
4204      { "TypeCode short data", "giop.tcshortdata",
4205        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4206     },
4207
4208     { &hf_giop_type_string,
4209       { "TypeCode string data", "giop.tcstring",
4210         FT_STRING, BASE_DEC,  NULL, 0x0, "", HFILL }
4211     },
4212
4213     { &hf_giop_type_ulong,
4214      { "TypeCode ulong data", "giop.tculongdata",
4215        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4216     },
4217
4218     { &hf_giop_type_ushort,
4219      { "TypeCode ushort data", "giop.tcushortdata",
4220        FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
4221     },
4222
4223     /*
4224      * IIOP Module - Chapter 15.10.2
4225      */
4226
4227     { &hf_giop_iiop_host,
4228      { "IIOP::Profile_host", "giop.iiop.host",
4229        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4230     }
4231     ,
4232
4233     { &hf_giop_iiop_port,
4234      { "IIOP::Profile_port", "giop.iiop.port",
4235        FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
4236     }
4237     ,
4238
4239     /*
4240      * IIOP ServiceContext
4241      */
4242
4243     { &hf_giop_iop_vscid,
4244      { "VSCID", "giop.iiop.vscid",
4245        FT_UINT32, BASE_HEX, NULL, 0xfffff000, "", HFILL }
4246     }
4247     ,
4248
4249     { &hf_giop_iop_scid,
4250      { "SCID", "giop.iiop.scid",
4251        FT_UINT32, BASE_HEX, NULL, 0x00000fff, "", HFILL }
4252     }
4253     ,
4254
4255
4256   };
4257
4258   static gint *ett[] = {
4259     &ett_giop,
4260     &ett_giop_reply,
4261     &ett_giop_request,
4262     &ett_giop_cancel_request,
4263     &ett_giop_locate_request,
4264     &ett_giop_locate_reply,
4265     &ett_giop_fragment,
4266     &ett_giop_scl,
4267     &ett_giop_ior
4268
4269   };
4270   proto_giop = proto_register_protocol("General Inter-ORB Protocol", "GIOP",
4271                                        "giop");
4272   proto_register_field_array (proto_giop, hf, array_length (hf));
4273   proto_register_subtree_array (ett, array_length (ett));
4274
4275
4276   /* register init routine */
4277
4278   register_init_routine( &giop_init); /* any init stuff */
4279
4280   /*
4281    * Init the giop user module hash tables here, as giop users
4282    * will populate it via register_giop_user_module BEFORE my
4283    * own giop_init() is called.
4284    */
4285
4286   giop_module_hash = g_hash_table_new(giop_hash_module_hash, giop_hash_module_equal);
4287   
4288   giop_module_keys = g_mem_chunk_new("giop_module_keys",
4289                                      sizeof(struct giop_module_key),
4290                                      giop_module_init_count * sizeof(struct giop_module_key), 
4291                                      G_ALLOC_AND_FREE);
4292   
4293   giop_module_vals = g_mem_chunk_new("giop_module_vals", 
4294                                      sizeof(struct giop_module_val),
4295                                      giop_module_init_count * sizeof(struct giop_module_val), 
4296                                      G_ALLOC_AND_FREE);
4297   
4298 }
4299
4300
4301
4302 void proto_reg_handoff_giop (void) {
4303   data_handle = find_dissector("data");
4304   heur_dissector_add("tcp", dissect_giop, proto_giop);
4305   /* Support DIOP (GIOP/UDP) */
4306   heur_dissector_add("udp", dissect_giop, proto_giop);
4307 }
4308
4309
4310
4311
4312 /*
4313  * Decode IOR
4314  *
4315  * Ref Corba v2.4.2 Chapter 13
4316  *
4317  */
4318
4319 /*
4320
4321 module IOP{ 
4322
4323     typedef unsigned long ProfileId;
4324
4325     const ProfileId TAG_INTERNET_IOP = 0;
4326     const ProfileId TAG_MULTIPLE_COMPONENTS = 1;
4327
4328     struct TaggedProfile {
4329       ProfileId tag;
4330       sequence <octet> profile_data;
4331     };
4332
4333     struct IOR {
4334       string type_id;
4335       sequence <TaggedProfile> profiles;
4336     };
4337
4338     typedef unsigned long ComponentId;
4339
4340     struct TaggedComponent {
4341       ComponentId tag;
4342       sequence <octet> component_data;
4343     };
4344
4345     typedef sequence <TaggedComponent> MultipleComponentProfile;
4346
4347 };
4348
4349 */
4350
4351 void decode_IOR(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ptree, int *offset,
4352                 guint32 boundary, gboolean stream_is_big_endian) {
4353
4354
4355   guint32 seqlen_p;             /* sequence length of profiles */
4356   guint32 u_octet4;
4357
4358   proto_tree *tree = NULL;      /* IOR tree */
4359   proto_item *tf;
4360
4361   gchar *repobuf;               /* for repository ID */
4362
4363   guint32 i;
4364
4365   /* create a subtree */
4366
4367   if (ptree) {
4368     tf = proto_tree_add_text (ptree, tvb, *offset, -1, "IOR");
4369     tree = proto_item_add_subtree (tf, ett_giop_ior);
4370   }
4371
4372
4373   /* Get type_id  == Repository ID */
4374
4375   u_octet4 = get_CDR_string(tvb,&repobuf,offset,stream_is_big_endian,boundary);
4376
4377   if (tree) {    
4378     proto_tree_add_uint(tree,hf_giop_string_length,tvb,
4379                         *offset-u_octet4-sizeof(u_octet4),4,u_octet4);
4380     if (u_octet4 > 0) {
4381       proto_tree_add_string(tree,hf_giop_type_id,tvb,
4382                             *offset-u_octet4,u_octet4,repobuf);
4383     }
4384   }
4385
4386   /*
4387    * Register a cleanup function in case on of our tvbuff accesses
4388    * throws an exception. We need to clean up repobuf.
4389    * We can't free it yet, as we must wait until we have the object
4390    * key, as we have to add both to the hash table.
4391    */
4392   CLEANUP_PUSH(g_free, repobuf);
4393
4394   /* Now get a sequence of profiles */
4395   /* Get sequence length (number of elements) */
4396   
4397   seqlen_p = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
4398   if (tree) {
4399     proto_tree_add_uint(tree,hf_giop_sequence_length,tvb,
4400                         *offset-sizeof(seqlen_p),4,seqlen_p);
4401   }
4402   
4403
4404   /* fetch all TaggedProfiles in this sequence */
4405   
4406   for (i=0; i< seqlen_p; i++) { /* for every TaggedProfile */
4407     decode_TaggedProfile(tvb, pinfo, tree, offset, boundary, stream_is_big_endian, repobuf);
4408   }
4409
4410   /*
4411    * We're done with repobuf, so we can call the cleanup handler to free
4412    * it, and then pop the cleanup handler.
4413    */
4414   CLEANUP_CALL_AND_POP;
4415
4416 }
4417
4418 static void decode_TaggedProfile(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
4419                                  guint32 boundary, gboolean stream_is_big_endian, gchar *repobuf) {
4420
4421   guint32 seqlen_pd;            /* sequence length of profile data */
4422
4423   guint32 pidtag;               /* profile ID TAG */
4424
4425   gchar *profile_data;          /* profile_data pointer */
4426   gchar *p_profile_data;        /* printable profile_data pointer */
4427
4428   guint32 new_boundary;         /* for encapsulations encountered */
4429   gboolean new_big_endianess;   /* for encapsulations encountered */
4430
4431   /* Get ProfileId tag */
4432
4433   pidtag = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
4434
4435   if (tree) {
4436     proto_tree_add_uint(tree,hf_giop_profile_id,tvb,
4437                         *offset-sizeof(pidtag),4,pidtag);
4438   }
4439
4440   /* get sequence length, new endianness and boundary for encapsulation */
4441   
4442   seqlen_pd = get_CDR_encap_info(tvb, tree, offset, 
4443                                  stream_is_big_endian, boundary,
4444                                  &new_big_endianess, &new_boundary);
4445
4446   /* return if zero length sequence */
4447
4448   if(seqlen_pd == 0)
4449     return;
4450
4451     
4452   /*
4453    * Lets see what kind of TAG it is. If TAG_INTERNET_IOP then 
4454    * decode it, otherwise just dump the octet sequence 
4455    *
4456    * also, store IOR in our objectkey hash
4457    *
4458    * TODO - handle other TAGS
4459    */
4460
4461   switch(pidtag) {
4462   case IOP_TAG_INTERNET_IOP:
4463     
4464     decode_IIOP_IOR_profile(tvb, pinfo, tree, offset, new_boundary, new_big_endianess, repobuf, TRUE);
4465     break;
4466
4467   default:
4468     
4469     /* fetch all octets in this sequence , but skip endianess */
4470       
4471     get_CDR_octet_seq(tvb, &profile_data, offset, seqlen_pd -1);
4472       
4473     /* Make a printable string */
4474       
4475     p_profile_data = make_printable_string( profile_data, seqlen_pd -1);
4476       
4477     if(tree) {
4478       proto_tree_add_text (tree, tvb, *offset -seqlen_pd + 1, seqlen_pd - 1,
4479                            "Profile Data: %s", p_profile_data);
4480     }
4481       
4482     g_free(p_profile_data);
4483
4484     g_free(profile_data);
4485
4486     break;
4487       
4488   }
4489
4490 }
4491
4492
4493
4494 /*
4495  * Decode IIOP IOR Profile
4496  * Ref Chap 15.7.2 in Corba Spec
4497  */
4498
4499
4500 static void decode_IIOP_IOR_profile(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
4501                                     guint32 boundary, gboolean stream_is_big_endian, gchar *repo_id_buf,
4502                                     gboolean store_flag) {
4503
4504   guint32 i;                    /* loop index */
4505
4506   guint8 v_major,v_minor;       /* IIOP sersion */
4507   gchar *buf;
4508   guint32 u_octet4;             /* u long */
4509   guint16 u_octet2;             /* u short */
4510   guint32 seqlen;               /* generic sequence length */
4511   guint32 seqlen1;              /* generic sequence length */
4512   gchar *objkey;                /* object key pointer */
4513   gchar *p_chars;               /* printable characters pointer */
4514
4515   
4516   /* Get major/minor version */
4517
4518   v_major = get_CDR_octet(tvb,offset);
4519   v_minor = get_CDR_octet(tvb,offset);
4520
4521
4522   if (tree) {    
4523     proto_tree_add_uint(tree,hf_giop_iiop_v_maj,tvb,
4524                         *offset-sizeof(v_minor)-sizeof(v_major),1,v_major  );
4525     proto_tree_add_uint(tree,hf_giop_iiop_v_min,tvb,
4526                         *offset-sizeof(v_minor),1,v_minor  );
4527   }
4528
4529
4530   /* host */
4531   
4532   u_octet4 = get_CDR_string(tvb,&buf,offset,stream_is_big_endian,boundary);
4533    
4534   if (tree) {    
4535     proto_tree_add_uint(tree,hf_giop_string_length,tvb,
4536                         *offset-u_octet4-sizeof(u_octet4),4,u_octet4);
4537     if (u_octet4 > 0) {
4538       proto_tree_add_string(tree,hf_giop_iiop_host,tvb,
4539                             *offset-u_octet4,u_octet4,buf);
4540     }
4541   }
4542   
4543   g_free(buf);          /* dont forget */
4544     
4545   /* Port */
4546
4547   u_octet2 = get_CDR_ushort(tvb,offset,stream_is_big_endian,boundary);
4548
4549   if (tree) {    
4550     proto_tree_add_uint(tree,hf_giop_iiop_port,tvb,
4551                         *offset-sizeof(u_octet2),2,u_octet2);
4552   }
4553
4554
4555   /* Object Key - sequence<octet> object_key */
4556
4557   seqlen = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
4558
4559   if (tree) {
4560     proto_tree_add_uint(tree,hf_giop_sequence_length,tvb,
4561                         *offset-sizeof(seqlen),4,seqlen);
4562   }
4563
4564   if (seqlen > 0) {
4565     /* fetch all octets in this sequence */  
4566     get_CDR_octet_seq(tvb, &objkey, offset, seqlen);
4567
4568     /*
4569      * Now we may have the Repository ID from earlier, as well
4570      * as the object key sequence and lengh. So lets store them in
4571      * our objectkey hash and free buffers.
4572      *
4573      * But only insert if user is not clicking and repo id not NULL.
4574      *
4575      */
4576
4577     if (repo_id_buf) {
4578       if (pinfo) {
4579         if(!pinfo->fd->flags.visited)
4580           insert_in_objkey_hash(giop_objkey_hash,objkey,seqlen,repo_id_buf,req_res); 
4581       }
4582       else {
4583  
4584         /*
4585          * No pinfo, but store anyway if flag set. eg: IOR read from file
4586          */
4587
4588         if (store_flag)
4589           insert_in_objkey_hash(giop_objkey_hash,objkey,seqlen,repo_id_buf,file); 
4590       }
4591     }
4592
4593     /* Make a printable string */
4594   
4595     p_chars = make_printable_string( objkey, seqlen );
4596   
4597     if(tree) {
4598       proto_tree_add_text (tree, tvb, *offset -seqlen, seqlen,
4599                          "Object Key: %s", p_chars);
4600     }
4601
4602     g_free(p_chars);
4603     g_free(objkey);  
4604   }
4605   
4606   /*
4607    * Now see if if its v1.1 or 1.2, as they can contain
4608    * extra sequence of IOP::TaggedComponents
4609    *
4610    */
4611   
4612   switch(v_minor) {
4613   case 0:
4614
4615     /* nothing extra */
4616     break;
4617
4618   case 1:
4619   case 2:
4620
4621     /* sequence of IOP::TaggedComponents */
4622     /* Ref Chap 13 in Corba Spec */
4623
4624     /* get sequence length */
4625     seqlen = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
4626
4627     if (tree) {
4628       proto_tree_add_uint(tree,hf_giop_sequence_length,tvb,
4629                           *offset-sizeof(seqlen),4,seqlen);
4630     }
4631
4632     for (i=0; i< seqlen; i++) {
4633       /* get tag */
4634       u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
4635       if (tree) {
4636         proto_tree_add_uint(tree,hf_giop_IIOP_tag,tvb,
4637                             *offset-sizeof(u_octet4),4,u_octet4);
4638       }
4639
4640       /* get component_data */
4641       seqlen1 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
4642       if (tree) {
4643         proto_tree_add_uint(tree,hf_giop_sequence_length,tvb,
4644                             *offset-sizeof(seqlen1),4,seqlen1);
4645       }
4646
4647       if (seqlen1 > 0) {
4648         get_CDR_octet_seq(tvb, &buf, offset, seqlen1);
4649
4650         if (tree) {
4651           /* Make a printable string of data */
4652   
4653           p_chars = make_printable_string(buf, seqlen1);
4654   
4655           proto_tree_add_text (tree, tvb, *offset -seqlen1, seqlen1,
4656                                "component_data: %s", p_chars);
4657   
4658           g_free(p_chars);
4659         }
4660
4661         g_free(buf);
4662       }
4663
4664     }
4665
4666
4667     break;
4668
4669   default:
4670     g_warning("giop:Invalid v_minor value = %u ", v_minor);
4671     break;
4672   }
4673   
4674 }
4675
4676
4677 /* 
4678  * Service Contexts Begin
4679  *
4680  */
4681
4682
4683
4684
4685
4686 void dissect_SID_BI_DIR_IIOP(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
4687                                MessageHeader *header, gchar *operation, guint32 boundary) {
4688
4689   return;
4690
4691 };
4692
4693
4694
4695
4696 /*
4697  * Service Contexts End
4698  *
4699  */
4700
4701
4702
4703
4704 /*
4705  * Corba , chp 13.7
4706  *
4707  *
4708  *
4709  *      typedef unsigned long ServiceID;
4710  *
4711  *      struct ServiceContext {
4712  *              ServiceID context_id;
4713  *              sequence <octet> context_data;
4714  *      };
4715  *      typedef sequence <ServiceContext> ServiceContextList;
4716  *
4717  *
4718  * Note: Spec says context_data is an encapsulation.
4719  *
4720  *
4721  */
4722
4723
4724
4725 void decode_ServiceContextList(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ptree, int *offset,
4726                                gboolean stream_is_be, guint32 boundary) {
4727
4728   guint32 seqlen;               /* sequence length  */
4729   guint32 seqlen_cd;            /* sequence length, context_data  */
4730
4731   proto_tree *tree = NULL;      /* ServiceContext tree */
4732   proto_item *tf;
4733
4734   guint32 context_id;
4735   gchar *context_data;
4736   gchar *p_context_data;
4737
4738   guint32 i;
4739   guint32 vscid;                /* Vendor Service context id */
4740   guint32 scid;
4741
4742   /* create a subtree */
4743
4744   if (ptree) {
4745     tf = proto_tree_add_text (ptree, tvb, *offset, -1, "ServiceContextList");
4746     tree = proto_item_add_subtree (tf, ett_giop_scl);
4747   }
4748
4749   /* Get sequence length (number of elements) */
4750   
4751   seqlen = get_CDR_ulong(tvb,offset,stream_is_be,boundary);
4752   if (tree) {
4753     proto_tree_add_uint(tree,hf_giop_sequence_length,tvb,
4754                         *offset-sizeof(seqlen),4,seqlen);
4755   }
4756
4757   /* return if zero length sequence */
4758
4759   if(seqlen == 0)
4760     return;
4761      
4762   /* Loop for all ServiceContext's */
4763
4764   for (i=0; i<seqlen; i++) {
4765
4766     context_id = get_CDR_ulong(tvb,offset,stream_is_be,boundary);
4767     if (tree) {
4768       proto_tree_add_uint(tree,hf_giop_iop_vscid,tvb,
4769                           *offset-sizeof(context_id),4,context_id);
4770
4771       proto_tree_add_uint(tree,hf_giop_iop_scid,tvb,
4772                           *offset-sizeof(context_id),4,context_id);
4773
4774     }
4775  
4776     vscid = context_id && 0xfffff000; /* vendor info, top 20 bits */
4777     scid = context_id  && 0x00000fff; /* standard service info, lower 12 bits */
4778
4779
4780 #if CONTEXT_DATA_IS_ENCAPSULATED
4781
4782     /* get sequence length, new endianness and boundary for encapsulation */
4783   
4784     seqlen_cd = get_CDR_encap_info(tvb, tree, offset, 
4785                                stream_is_be, boundary,
4786                                &new_big_endianess, &new_boundary);
4787
4788
4789 #else
4790    /* get sequence length, and NO  encapsulation */
4791
4792     seqlen_cd = get_CDR_ulong(tvb, offset, stream_is_be,boundary);
4793
4794 #endif
4795
4796     /* return if zero length sequence */
4797
4798     if(seqlen_cd == 0)
4799       return;
4800     
4801     /*
4802      * Now decode sequence according to vendor ServiceId, but I dont
4803      * have that yet, so just dump it as data.
4804      */    
4805
4806     /* fetch all octets in this sequence */
4807   
4808     get_CDR_octet_seq(tvb, &context_data, offset, seqlen_cd);
4809
4810     /* Make a printable string */
4811   
4812     p_context_data = make_printable_string( context_data, seqlen_cd );
4813   
4814     if(tree) {
4815       proto_tree_add_text (tree, tvb, *offset - seqlen_cd , seqlen_cd,
4816                            "context_data: %s", p_context_data);
4817     }
4818
4819     g_free(context_data);
4820     g_free(p_context_data);
4821
4822   } /* seqlen  */
4823
4824
4825   return;                       /* for now, fix later */
4826     
4827
4828 }
4829
4830 /* Decode SystemExceptionReplyBody as defined in the CORBA spec chapter 15.
4831  */
4832
4833 static void decode_SystemExceptionReplyBody (tvbuff_t *tvb, proto_tree *tree, gint *offset,
4834                                              gboolean stream_is_big_endian,
4835                                              guint32 boundary) {
4836
4837   guint32 length;            /* string length */
4838   guint32 minor_code_value;
4839   guint32 completion_status;
4840
4841   gchar *buf;                /* pointer to string buffer */ 
4842
4843   length = get_CDR_string(tvb, &buf, offset, stream_is_big_endian, boundary);
4844
4845   if (tree) {
4846     proto_tree_add_text(tree, tvb, *offset-4, 4,
4847                         "Exception length: %u", length);
4848     if (length > 0) {
4849       proto_tree_add_text(tree, tvb, *offset - length, length,
4850                           "Exception id: %s", buf );
4851     }
4852   }
4853   g_free(buf);
4854
4855   minor_code_value = get_CDR_ulong(tvb, offset, stream_is_big_endian, boundary);
4856   completion_status = get_CDR_ulong(tvb, offset, stream_is_big_endian, boundary);
4857         
4858   if (tree) {
4859     proto_tree_add_text(tree, tvb, *offset-8, 4,
4860                         "Minor code value: %u", minor_code_value);
4861     proto_tree_add_text(tree, tvb, *offset-4, 4,
4862                         "Completion Status: %u", completion_status);
4863   }
4864 }
4865
4866
4867 /*
4868  * Helper functions for dissecting TypeCodes 
4869  *
4870  * These functions decode the complex parameter lists
4871  * of TypeCodes as defined in the CORBA spec chapter 15.
4872  */
4873
4874 static void dissect_tk_objref_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
4875                                      gboolean stream_is_big_endian, guint32 boundary,
4876                                      MessageHeader * header) {
4877
4878   guint32  new_boundary;             /* new boundary for encapsulation */
4879   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
4880
4881   guint32 seqlen;   /* sequence length */
4882
4883   /* get sequence length, new endianness and boundary for encapsulation */
4884   seqlen = get_CDR_encap_info(tvb, tree, offset, 
4885                                    stream_is_big_endian, boundary,
4886                                    &new_stream_is_big_endian, &new_boundary);
4887
4888   /* get repository ID */
4889   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4890                                 hf_giop_repoid);
4891
4892   /* get name */
4893   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4894                                 hf_giop_typecode_name);
4895
4896 }
4897
4898
4899 static void dissect_tk_struct_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
4900                                      gboolean stream_is_big_endian, guint32 boundary,
4901                                      MessageHeader * header ) {
4902
4903   guint32  new_boundary;             /* new boundary for encapsulation */
4904   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
4905
4906   guint32 count;    /* parameter count (of tuples)  */
4907   guint32 seqlen;   /* sequence length */
4908   guint32 i;        /* loop index */
4909
4910   /* get sequence lengt,h new endianness and boundary for encapsulation */
4911   seqlen = get_CDR_encap_info(tvb, tree, offset, 
4912                                    stream_is_big_endian, boundary,
4913                                    &new_stream_is_big_endian, &new_boundary);
4914
4915   /* get repository ID */
4916   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4917                                 hf_giop_repoid);
4918
4919   /* get name */
4920   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4921                                 hf_giop_typecode_name);
4922
4923   /* get count of tuples */
4924   count = get_CDR_ulong(tvb,offset,new_stream_is_big_endian,new_boundary);
4925   if (tree) {
4926     proto_tree_add_uint(tree,hf_giop_typecode_count,tvb,
4927                         *offset-sizeof(count),4,count);
4928   }
4929
4930   /* get all tuples */
4931   for (i=0; i< count; i++) {
4932     /* get member name */
4933     dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4934                                   hf_giop_typecode_member_name);
4935
4936     /* get member type */
4937     get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
4938   }
4939
4940 }
4941
4942
4943 static void dissect_tk_union_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
4944                                     gboolean stream_is_big_endian, guint32 boundary,
4945                                     MessageHeader * header) {
4946
4947   guint32  new_boundary;             /* new boundary for encapsulation */
4948   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
4949
4950   guint32  TCKind;    /* TypeCode */
4951   gint32   s_octet4;  /* signed int32 */
4952
4953   guint32 count;    /* parameter count (of tuples)  */
4954   guint32 seqlen;   /* sequence length */
4955   guint32 i;        /* loop index */
4956
4957   /* get sequence legnth, new endianness and boundary for encapsulation */
4958   seqlen = get_CDR_encap_info(tvb, tree, offset, 
4959                                    stream_is_big_endian, boundary,
4960                                    &new_stream_is_big_endian, &new_boundary);
4961
4962   /* get repository ID */
4963   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4964                                 hf_giop_repoid);
4965
4966   /* get name */
4967   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4968                                 hf_giop_typecode_name);
4969
4970   /* get discriminant type */
4971   TCKind = get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
4972
4973   /* get default used */
4974   s_octet4 = get_CDR_long(tvb,offset,new_stream_is_big_endian,new_boundary);
4975   if (tree) {
4976     proto_tree_add_int(tree,hf_giop_typecode_default_used,tvb,
4977                         *offset-sizeof(s_octet4),4,s_octet4);
4978   }
4979   /* get count of tuples */
4980   count = get_CDR_ulong(tvb,offset,new_stream_is_big_endian,new_boundary);
4981   if (tree) {
4982     proto_tree_add_uint(tree,hf_giop_typecode_count,tvb,
4983                         *offset-sizeof(count),4,count);
4984   }
4985
4986   /* get all tuples */
4987   for (i=0; i< count; i++) {
4988     /* get label value, based on TCKind above  */
4989     dissect_data_for_typecode(tvb, tree, offset, new_stream_is_big_endian, new_boundary, header, TCKind );
4990
4991     /* get member name */
4992     dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4993                                   hf_giop_typecode_member_name);
4994
4995     /* get member type */
4996     get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
4997   }
4998
4999 }
5000
5001
5002 static void dissect_tk_enum_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5003                                    gboolean stream_is_big_endian, guint32 boundary,
5004                                    MessageHeader * header) {
5005
5006   guint32  new_boundary;             /* new boundary for encapsulation */
5007   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5008
5009   guint32 count;    /* parameter count (of tuples)  */
5010   guint32 seqlen;   /* sequence length */
5011   guint32 i;        /* loop index */
5012
5013   /* get sequence length, new endianness and boundary for encapsulation */
5014   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5015                                    stream_is_big_endian, boundary,
5016                                    &new_stream_is_big_endian, &new_boundary);
5017
5018   /* get repository ID */
5019   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5020                                 hf_giop_repoid);
5021
5022   /* get name */
5023   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5024                                 hf_giop_typecode_name);
5025
5026   /* get count of tuples */
5027   count = get_CDR_ulong(tvb,offset,new_stream_is_big_endian,new_boundary);
5028   if (tree) {
5029     proto_tree_add_uint(tree,hf_giop_typecode_count,tvb,
5030                         *offset-sizeof(count),4,count);
5031   }
5032
5033   /* get all tuples */
5034   for (i=0; i< count; i++) {
5035     /* get member name */
5036     dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5037                                   hf_giop_typecode_member_name);
5038   }
5039
5040 }
5041
5042
5043 static void dissect_tk_sequence_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5044                                        gboolean stream_is_big_endian, guint32 boundary,
5045                                        MessageHeader * header) {
5046
5047   guint32  new_boundary;             /* new boundary for encapsulation */
5048   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5049
5050   guint32 u_octet4; /* unsigned int32 */
5051
5052   guint32 seqlen;   /* sequence length */
5053
5054   /* get sequence length, new endianness and boundary for encapsulation */
5055   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5056                                    stream_is_big_endian, boundary,
5057                                    &new_stream_is_big_endian, &new_boundary);
5058
5059   /* get element type */
5060   get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5061
5062   /* get max length */
5063   u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
5064   if (tree) {
5065     proto_tree_add_uint(tree,hf_giop_typecode_max_length,tvb,
5066                         *offset-sizeof(u_octet4),4,u_octet4);
5067   }
5068 }
5069
5070
5071 static void dissect_tk_array_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5072                                     gboolean stream_is_big_endian, guint32 boundary,
5073                                     MessageHeader * header) {
5074
5075   guint32  new_boundary;             /* new boundary for encapsulation */
5076   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5077
5078   guint32 u_octet4; /* unsigned int32 */
5079
5080   guint32 seqlen;   /* sequence length */
5081
5082   /* get sequence length, new endianness and boundary for encapsulation */
5083   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5084                                    stream_is_big_endian, boundary,
5085                                    &new_stream_is_big_endian, &new_boundary);
5086
5087   /* get element type */
5088   get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5089
5090   /* get length */
5091   u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
5092   if (tree) {
5093     proto_tree_add_uint(tree,hf_giop_typecode_length,tvb,
5094                         *offset-sizeof(u_octet4),4,u_octet4);
5095   }
5096 }
5097
5098
5099 static void dissect_tk_alias_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5100                                     gboolean stream_is_big_endian, guint32 boundary,
5101                                     MessageHeader * header) {
5102
5103   guint32  new_boundary;             /* new boundary for encapsulation */
5104   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5105
5106   guint32 seqlen;   /* sequence length */
5107
5108   /* get sequence legnth, new endianness and boundary for encapsulation */
5109   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5110                                    stream_is_big_endian, boundary,
5111                                    &new_stream_is_big_endian, &new_boundary);
5112
5113   /* get repository ID */
5114   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5115                                 hf_giop_repoid);
5116
5117   /* get name */
5118   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5119                                 hf_giop_typecode_name);
5120
5121   /* get ??? (noname) TypeCode */
5122   get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5123
5124 }
5125
5126
5127 static void dissect_tk_except_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5128                                      gboolean stream_is_big_endian, guint32 boundary,
5129                                      MessageHeader * header) {
5130
5131   guint32  new_boundary;             /* new boundary for encapsulation */
5132   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5133
5134   guint32 count;    /* parameter count (of tuples)  */
5135   guint32 seqlen;   /* sequence length */
5136   guint32 i;        /* loop index */
5137
5138   /* get sequence length, new endianness and boundary for encapsulation */
5139   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5140                                    stream_is_big_endian, boundary,
5141                                    &new_stream_is_big_endian, &new_boundary);
5142
5143   /* get repository ID */
5144   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5145                                 hf_giop_repoid);
5146
5147   /* get name */
5148   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5149                                 hf_giop_typecode_name);
5150
5151   /* get count of tuples */
5152   count = get_CDR_ulong(tvb,offset,new_stream_is_big_endian,new_boundary);
5153   if (tree) {
5154     proto_tree_add_uint(tree,hf_giop_typecode_count,tvb,
5155                         *offset-sizeof(count),4,count);
5156   }
5157
5158   /* get all tuples */
5159   for (i=0; i< count; i++) {
5160     /* get member name */
5161     dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5162                                   hf_giop_typecode_member_name);
5163
5164     /* get member type */
5165     get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5166   }
5167
5168 }
5169
5170
5171 static void dissect_tk_value_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5172                                     gboolean stream_is_big_endian, guint32 boundary,
5173                                     MessageHeader * header) {
5174
5175   guint32  new_boundary;             /* new boundary for encapsulation */
5176   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5177
5178   gint16  s_octet2; /* signed int16 */
5179
5180   guint32 count;    /* parameter count (of tuples)  */
5181   guint32 seqlen;   /* sequence length */
5182   guint32 i;        /* loop index */
5183
5184   /* get sequence length, new endianness and boundary for encapsulation */
5185   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5186                                    stream_is_big_endian, boundary,
5187                                    &new_stream_is_big_endian, &new_boundary);
5188
5189   /* get repository ID */
5190   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5191                                 hf_giop_repoid);
5192
5193   /* get name */
5194   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5195                                 hf_giop_typecode_name);
5196
5197   /* get ValueModifier */
5198   s_octet2 = get_CDR_short(tvb,offset,stream_is_big_endian,boundary);
5199   if (tree) {
5200     proto_tree_add_int(tree,hf_giop_typecode_ValueModifier,tvb,
5201                        *offset-sizeof(s_octet2),2,s_octet2);
5202   }
5203
5204   /* get conrete base */
5205   get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5206
5207   /* get count of tuples */
5208   count = get_CDR_ulong(tvb,offset,new_stream_is_big_endian,new_boundary);
5209   if (tree) {
5210     proto_tree_add_uint(tree,hf_giop_typecode_count,tvb,
5211                         *offset-sizeof(count),4,count);
5212   }
5213
5214   /* get all tuples */
5215   for (i=0; i< count; i++) {
5216     /* get member name */
5217     dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5218                                   hf_giop_typecode_member_name);
5219
5220     /* get member type */
5221     get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5222
5223     /* get Visibility */
5224     s_octet2 = get_CDR_short(tvb,offset,stream_is_big_endian,boundary);
5225     if (tree) {
5226       proto_tree_add_int(tree,hf_giop_typecode_Visibility,tvb,
5227                           *offset-sizeof(s_octet2),2,s_octet2);
5228     }
5229   }
5230
5231 }
5232
5233
5234 static void dissect_tk_value_box_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5235                                         gboolean stream_is_big_endian, guint32 boundary,
5236                                         MessageHeader * header) {
5237
5238   guint32  new_boundary;             /* new boundary for encapsulation */
5239   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5240
5241   guint32 seqlen;   /* sequence length */
5242
5243   /* get sequence length, new endianness and boundary for encapsulation */
5244   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5245                                    stream_is_big_endian, boundary,
5246                                    &new_stream_is_big_endian, &new_boundary);
5247
5248   /* get repository ID */
5249   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5250                                 hf_giop_repoid);
5251
5252   /* get name */
5253   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5254                                 hf_giop_typecode_name);
5255
5256   /* get ??? (noname) TypeCode */
5257   get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5258 }
5259
5260
5261 static void dissect_tk_native_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5262                                      gboolean stream_is_big_endian, guint32 boundary,
5263                                      MessageHeader * header) {
5264
5265   guint32  new_boundary;             /* new boundary for encapsulation */
5266   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5267
5268   guint32 seqlen;   /* sequence length */
5269
5270   /* get sequence length, new endianness and boundary for encapsulation */
5271   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5272                                    stream_is_big_endian, boundary,
5273                                    &new_stream_is_big_endian, &new_boundary);
5274
5275   /* get repository ID */
5276   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5277                                 hf_giop_repoid);
5278
5279   /* get name */
5280   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5281                                 hf_giop_typecode_name);
5282
5283 }
5284
5285
5286 static void dissect_tk_abstract_interface_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5287                                                  gboolean stream_is_big_endian, guint32 boundary,
5288                                                  MessageHeader * header) {
5289
5290   guint32  new_boundary;              /* new boundary for encapsulation */
5291   gboolean new_stream_is_big_endian;  /* new endianness for encapsulation */
5292
5293   guint32 seqlen;   /* sequence length */
5294
5295   /* get sequence length, new endianness and boundary for encapsulation */
5296   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5297                                    stream_is_big_endian, boundary,
5298                                    &new_stream_is_big_endian, &new_boundary);
5299
5300   /* get repository ID */
5301   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5302                                 hf_giop_repoid);
5303
5304   /* get name */
5305   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5306                                 hf_giop_typecode_name);
5307
5308 }
5309
5310 /* Typecode parameter lists are encoded as encapsulations and
5311  * this function gets the encapsulation information; see
5312  * CORBA spec chapter 15 
5313  *
5314  *
5315  * Renamed to get_CDR_encap_info() for any encapsulation 
5316  * we come across, useful helper function 
5317  *
5318  * Also, should return immediately if seqlen == 0.
5319  * ie: Forget about trying to grab endianess for
5320  *     zero length sequence.
5321  *
5322  * Caller must always check seqlen == 0, and not assume its value
5323  *
5324  *
5325  * Note: there seemed to be considerable confusion in corba
5326  * circles as to the correct interpretation of encapsulations,
5327  * and zero length sequences etc, but this is our best bet at the 
5328  * moment.
5329  *
5330  * -- FS
5331  *
5332  */
5333
5334 guint32 get_CDR_encap_info(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5335                        gboolean old_stream_is_big_endian, guint32 old_boundary,
5336                        gboolean *new_stream_is_big_endian_ptr, guint32 *new_boundary_ptr ) {
5337  
5338   guint32 seqlen;   /* sequence length */
5339   guint8  giop_endianess;
5340
5341   /* Get sequence length of parameter list */
5342   seqlen = get_CDR_ulong(tvb,offset,old_stream_is_big_endian,old_boundary);
5343   if (tree) {
5344     proto_tree_add_uint(tree,hf_giop_sequence_length,tvb,
5345                         *offset-sizeof(seqlen),4,seqlen);
5346   }
5347
5348   
5349
5350   /*
5351    * seqlen == 0, implies no endianess and no data
5352    * so just return. Populate new_boundary_ptr and
5353    * new_stream_is_big_endian_ptr with current (old)
5354    * values, just to keep everyone happy. -- FS
5355    *
5356    */
5357
5358   if (seqlen == 0) {
5359
5360     *new_boundary_ptr = old_boundary;
5361     *new_stream_is_big_endian_ptr = old_stream_is_big_endian;
5362
5363     return seqlen;
5364
5365   }
5366
5367   /*  Start of encapsulation of parameter list */
5368   *new_boundary_ptr = *offset;  /* remember  */
5369   giop_endianess =  get_CDR_octet(tvb,offset);
5370
5371   *new_stream_is_big_endian_ptr = ! giop_endianess;
5372
5373   /*
5374    * Glib: typedef gint   gboolean;
5375    * ie: It is not a guint8, so cannot use sizeof to correctly
5376    * highlight octet.
5377    */
5378
5379
5380   if (tree) {
5381     proto_tree_add_uint(tree,hf_giop_endianess,tvb,
5382                         *offset-1,1,giop_endianess);
5383   }
5384
5385
5386   return seqlen;
5387
5388
5389 }
5390
5391 /* 
5392  * gets a TypeCode complex string parameter and
5393  * displays it in the relevant tree.
5394  */
5395
5396 static void dissect_typecode_string_param(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5397                                           gboolean new_stream_is_big_endian, guint32 new_boundary, int hf_id ) {
5398
5399   guint32 u_octet4;  /* unsigned int32 */
5400   gchar *buf;        /* ptr to string buffer */
5401
5402   /* get string */
5403   u_octet4 = get_CDR_string(tvb,&buf,offset,new_stream_is_big_endian,new_boundary);
5404    
5405   if (tree) {    
5406     proto_tree_add_uint(tree,hf_giop_string_length,tvb,
5407                         *offset-u_octet4-sizeof(u_octet4),4,u_octet4);
5408     if (u_octet4 > 0) {
5409       proto_tree_add_string(tree,hf_id,tvb,*offset-u_octet4,u_octet4,buf);
5410     }
5411   }
5412   
5413   g_free(buf);          /* dont forget */
5414
5415 }
5416
5417 /*
5418  * For a given data type, given by a TypeCode gets the associated data
5419  * and displays it in the relevant tree.
5420  */
5421
5422 static void dissect_data_for_typecode(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5423                                       gboolean stream_is_big_endian, guint32 boundary,
5424                                       MessageHeader * header, guint32 data_type ) {
5425
5426   gboolean my_boolean; /* boolean */
5427
5428   gint8  s_octet1;   /* signed int8 */
5429   guint8 u_octet1;   /* unsigned int8 */
5430
5431   gint16  s_octet2;  /* signed int16 */
5432   guint16 u_octet2;  /* unsigned int16 */
5433
5434   gint32  s_octet4;  /* signed int32 */
5435   guint32 u_octet4;  /* unsigned int32 */
5436
5437   gdouble my_double; /* double */
5438   gfloat  my_float;  /* float */
5439
5440   gchar *buf = NULL;            /* ptr to string buffer */
5441
5442   /* Grab the data according to data type */
5443
5444   switch (data_type) {
5445   case tk_null:
5446     /* nothing to decode */
5447     break;
5448   case tk_void:
5449     /* nothing to decode */
5450     break;
5451   case tk_short:
5452     s_octet2 = get_CDR_short(tvb,offset,stream_is_big_endian,boundary);
5453     if (tree) {
5454       proto_tree_add_int(tree,hf_giop_type_short,tvb,
5455                          *offset-sizeof(s_octet2),2,s_octet2);
5456     }
5457     break;
5458   case tk_long:
5459     s_octet4 = get_CDR_long(tvb,offset,stream_is_big_endian,boundary);
5460     if (tree) {
5461       proto_tree_add_int(tree,hf_giop_type_long,tvb,
5462                          *offset-sizeof(s_octet4),4,s_octet4);
5463     }
5464     break;
5465   case tk_ushort:
5466     u_octet2 = get_CDR_ushort(tvb,offset,stream_is_big_endian,boundary);
5467     if (tree) {
5468       proto_tree_add_uint(tree,hf_giop_type_ushort,tvb,
5469                           *offset-sizeof(u_octet2),2,u_octet2);
5470     }
5471     break;
5472   case tk_ulong:
5473     u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
5474     if (tree) {
5475       proto_tree_add_uint(tree,hf_giop_type_ulong,tvb,
5476                          *offset-sizeof(u_octet4),4,u_octet4);
5477     }
5478     break;
5479   case tk_float:
5480     my_float = get_CDR_float(tvb,offset,stream_is_big_endian,boundary);
5481     if (tree) {
5482       proto_tree_add_double(tree,hf_giop_type_float,tvb,
5483                             *offset-sizeof(my_float),4,my_float);
5484     }
5485     break;
5486   case tk_double:
5487     my_double = get_CDR_double(tvb,offset,stream_is_big_endian,boundary);
5488     if (tree) {
5489       proto_tree_add_double(tree,hf_giop_type_double,tvb,
5490                             *offset-sizeof(my_double),8,my_double);
5491     }
5492     break;
5493   case tk_boolean:
5494     my_boolean = get_CDR_boolean(tvb,offset);
5495     if (tree) {
5496       proto_tree_add_boolean(tree,hf_giop_type_boolean,tvb,
5497                              *offset-1,1,my_boolean);
5498     }
5499     break;
5500   case tk_char:
5501     u_octet1 = get_CDR_char(tvb,offset);
5502     if (tree) {
5503       proto_tree_add_uint(tree,hf_giop_type_char,tvb,
5504                           *offset-sizeof(u_octet1),1,u_octet1);
5505     }
5506     break;
5507   case tk_octet:
5508     u_octet1 = get_CDR_octet(tvb,offset);
5509     if (tree) {
5510       proto_tree_add_uint(tree,hf_giop_type_octet,tvb,
5511                           *offset-sizeof(u_octet1),1,u_octet1);
5512     }
5513     break;
5514   case tk_any:
5515     get_CDR_any(tvb,tree,offset,stream_is_big_endian,boundary,header);
5516     break;
5517   case tk_TypeCode:
5518     get_CDR_typeCode(tvb,tree,offset,stream_is_big_endian,boundary,header);
5519     break;
5520   case tk_Principal:
5521     break;
5522   case tk_objref:
5523     break;
5524   case tk_struct:
5525     break;
5526   case tk_union:
5527     break;
5528   case tk_enum:
5529     u_octet4 = get_CDR_enum(tvb,offset,stream_is_big_endian,boundary);
5530     if (tree) {
5531       proto_tree_add_uint(tree,hf_giop_type_enum,tvb,
5532                           *offset-sizeof(u_octet4),4,u_octet4);
5533     }
5534     break;
5535   case tk_string:
5536     u_octet4 = get_CDR_string(tvb,&buf,offset,stream_is_big_endian,boundary);
5537     if (tree) {
5538       proto_tree_add_uint(tree,hf_giop_string_length,tvb,
5539                           *offset-u_octet4-sizeof(u_octet4),4,u_octet4);
5540       if (u_octet4 > 0) {
5541         proto_tree_add_string(tree,hf_giop_type_string,tvb,
5542                               *offset-u_octet4,u_octet4,buf);
5543       }
5544     }
5545     
5546     g_free(buf);                /* dont forget */
5547     break;
5548   case tk_sequence:
5549     break;
5550   case tk_array:
5551     break;
5552   case tk_alias:
5553     break;
5554   case tk_except:
5555     break;
5556   case tk_longlong:
5557     break;
5558   case tk_ulonglong:
5559     break;
5560   case tk_longdouble:
5561     break;
5562   case tk_wchar:
5563     s_octet1 = get_CDR_wchar(tvb,&buf,offset,header);
5564     if (tree) {
5565       /*
5566        * XXX - can any of these throw an exception?
5567        * If so, we need to catch the exception and free "buf".
5568        */
5569       if (s_octet1 < 0) { /* no size to add to tree */
5570         proto_tree_add_string(tree,hf_giop_type_string,tvb,
5571                               *offset+s_octet1,(-s_octet1),buf);
5572       } else {
5573         proto_tree_add_uint(tree,hf_giop_string_length,tvb,
5574                             *offset-s_octet1-sizeof(s_octet1),1,s_octet1);
5575         proto_tree_add_string(tree,hf_giop_type_string,tvb,
5576                               *offset-s_octet1,s_octet1,buf);
5577       }
5578     }
5579
5580     g_free(buf);              /* dont forget */
5581     break;
5582   case tk_wstring:
5583     u_octet4 = get_CDR_wstring(tvb,&buf,offset,stream_is_big_endian,boundary,header);
5584     if (tree) {
5585       /*
5586        * XXX - can any of these throw an exception?
5587        * If so, we need to catch the exception and free "buf".
5588        */
5589        proto_tree_add_uint(tree,hf_giop_string_length,tvb,
5590                            *offset-u_octet4-sizeof(u_octet4),4,u_octet4);
5591        proto_tree_add_string(tree,hf_giop_type_string,tvb,
5592                              *offset-u_octet4,u_octet4,buf);
5593      }
5594
5595     g_free(buf);              /* dont forget */
5596     break;
5597   case tk_fixed:
5598     break;
5599   case tk_value:
5600     break;
5601   case tk_value_box:
5602     break;
5603   case tk_native:
5604     break;
5605   case tk_abstract_interface:
5606     break;
5607   default:
5608     g_warning("giop: Unknown typecode data type %u \n", data_type);
5609   break;
5610   } /* data_type */
5611
5612 }