Fix some news items.
[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.53 2001/12/19 08:59:06 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 "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, "GIOP FILE IOR");
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,
3086                               tvb_length (tvb),
3087                               "General Inter-ORB Protocol Reply");
3088     if (reply_tree == NULL)
3089       {
3090         reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
3091         
3092       }
3093   }
3094   
3095   /*
3096    * Decode IOP::ServiceContextList
3097    */
3098   
3099   decode_ServiceContextList(tvb, pinfo, reply_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3100
3101   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3102
3103   if (check_col(pinfo->cinfo, COL_INFO)) {
3104     col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3105   }
3106
3107   if (tree) {
3108     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3109                          "Request id: %u", request_id);
3110   }
3111
3112   reply_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3113
3114   if (check_col(pinfo->cinfo, COL_INFO)) {
3115     col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
3116                     val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3117
3118   }
3119
3120   if (tree) {
3121     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3122                          "Reply status: %s",
3123                          val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3124     
3125   }
3126
3127   /*
3128    * Save FN and MFN in complete_reply_hash, only if user is NOT clicking
3129    */
3130
3131   if (! pinfo->fd->flags.visited) {
3132     mfn = get_mfn_from_fn_and_reqid(pinfo->fd->num,request_id); /* find MFN for this FN */
3133     if (mfn != pinfo->fd->num) { /* if mfn is not fn, good */
3134       insert_in_complete_reply_hash(pinfo->fd->num, mfn);
3135     }
3136   }
3137
3138   header->req_id = request_id;          /* save for sub dissector */
3139   header->rep_status = reply_status;   /* save for sub dissector */
3140
3141   dissect_reply_body(tvb, offset, pinfo, reply_tree, stream_is_big_endian,
3142     reply_status, header,tree);
3143
3144
3145 }
3146
3147 /** The format of the GIOP 1.2 Reply header is very similar to the 1.0
3148  *  and 1.1 header, only the fields have been rearranged.  From Section
3149  *  15.4.3.1 of the CORBA 2.4 specification:
3150  *
3151  *   struct ReplyHeader_1_2 {
3152  *         unsigned long request_id;
3153  *         ReplyStatusType_1_2 reply_status;
3154  *         IOP:ServiceContextList service_context; 
3155  *    };
3156  */
3157
3158 static void dissect_giop_reply_1_2 (tvbuff_t * tvb, packet_info * pinfo,
3159                                     proto_tree * tree, proto_tree * clnp_tree,
3160                                     MessageHeader * header,
3161                                     gboolean stream_is_big_endian) {
3162
3163   u_int offset = 0;
3164   guint32 request_id;
3165   guint32 reply_status;
3166   proto_tree *reply_tree = NULL;
3167   proto_item *tf;
3168   guint32 mfn;                  /* matching frame number */
3169   
3170   if (tree) {
3171     tf = proto_tree_add_text (tree, tvb, offset,
3172                               tvb_length (tvb),
3173                               "General Inter-ORB Protocol Reply");
3174     reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
3175   }
3176   
3177   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3178   
3179   if (check_col(pinfo->cinfo, COL_INFO)) {
3180     col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3181   }
3182
3183   if (tree) {
3184     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3185                          "Request id: %u", request_id);
3186   }
3187
3188   reply_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3189   
3190   if (check_col(pinfo->cinfo, COL_INFO)) {
3191     col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
3192                     val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3193
3194   }
3195
3196   if (tree) {
3197     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3198                          "Reply status: %s",
3199                          val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3200
3201   }
3202
3203   /*
3204    * Decode IOP::ServiceContextList
3205    */
3206
3207   decode_ServiceContextList(tvb, pinfo, reply_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3208
3209   /*
3210    * GIOP 1.2 Reply body must fall on an 8 octet alignment.
3211    */
3212
3213   set_new_alignment(&offset, GIOP_HEADER_SIZE, 8);
3214
3215   /*
3216    * Save FN and MFN in complete_reply_hash, only if user is NOT clicking
3217    */
3218   
3219   if (! pinfo->fd->flags.visited) {
3220     mfn = get_mfn_from_fn_and_reqid(pinfo->fd->num,request_id); /* find MFN for this FN */
3221     if (mfn != pinfo->fd->num) { /* if mfn is not fn, good */
3222       insert_in_complete_reply_hash(pinfo->fd->num, mfn);
3223     }
3224   }
3225
3226   /*
3227    * Add header to argument list so sub dissector can get header info.
3228    */
3229
3230   header->req_id = request_id;          /* save for sub dissector */
3231   header->rep_status = reply_status;   /* save for sub dissector */
3232
3233   dissect_reply_body(tvb, offset, pinfo, reply_tree, stream_is_big_endian,
3234                      reply_status,header,tree);
3235
3236 }
3237
3238
3239
3240 static void dissect_giop_cancel_request (tvbuff_t * tvb, packet_info * pinfo,
3241                         proto_tree * tree, proto_tree * clnp_tree,
3242                         MessageHeader * header, gboolean stream_is_big_endian) {
3243
3244   u_int offset = 0;
3245   guint32 request_id;
3246   proto_tree *cancel_request_tree = NULL;
3247   proto_item *tf;
3248
3249   if (tree) {
3250     tf = proto_tree_add_text (tree, tvb, offset,
3251                               tvb_length (tvb),
3252                               "General Inter-ORB Protocol CancelRequest");
3253     cancel_request_tree = proto_item_add_subtree (tf, ett_giop_cancel_request);
3254   }
3255
3256   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3257   
3258   if (check_col(pinfo->cinfo, COL_INFO)) {
3259     col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3260   }
3261
3262   if (tree) {
3263     proto_tree_add_text (cancel_request_tree, tvb, offset-4, 4,
3264                          "Request id: %u", request_id);
3265   }
3266
3267   
3268 }
3269
3270 /**  The formats for GIOP 1.0 and 1.1 Request messages are defined
3271  *   in section 15.4.2.1 of the CORBA 2.4 specification.
3272  *
3273  *   struct RequestHeader{
3274  *          IOP::ServiceContextList   service_context;
3275  *          unsigned long             request_id;
3276  *          boolean                   response_expected;
3277  *          octet                     reserved[3];  // Only in GIOP 1.1
3278  *          sequence<octet>           object_key;
3279  *          string                    operation;
3280  *          CORBA::OctetSeq           requesting_principal;
3281  *   }
3282  */
3283 static void
3284 dissect_giop_request_1_1 (tvbuff_t * tvb, packet_info * pinfo,
3285                         proto_tree * tree, proto_tree * clnp_tree,
3286                         MessageHeader * header, gboolean stream_is_big_endian)
3287 {
3288   guint32 offset = 0;
3289   guint32 request_id;
3290   guint32 len = 0;
3291
3292   guint32 objkey_len = 0;       /* object key length */
3293   gchar *objkey = NULL;         /* object key sequence */
3294   gchar *print_objkey;          /* printable object key sequence */
3295   gboolean exres = FALSE;       /* result of trying explicit dissectors */
3296
3297   gchar *operation;
3298   gchar *requesting_principal;
3299   gchar *print_requesting_principal;
3300   guint8 response_expected;
3301   gchar *reserved;
3302   proto_tree *request_tree = NULL;
3303   proto_item *tf;
3304
3305   gchar *repoid = NULL;         /* from object key lookup in objkey hash */
3306
3307
3308   if (tree)
3309     {
3310       tf = proto_tree_add_text (tree, tvb, offset,
3311                                 tvb_length (tvb),
3312                                 "General Inter-ORB Protocol Request");
3313       if (request_tree == NULL)
3314         {
3315           request_tree = proto_item_add_subtree (tf, ett_giop_request);
3316
3317         }
3318     }
3319
3320
3321
3322
3323   /*
3324    * Decode IOP::ServiceContextList
3325    */
3326   
3327   decode_ServiceContextList(tvb, pinfo, request_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3328
3329
3330   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3331   if (check_col(pinfo->cinfo, COL_INFO))
3332     {
3333       col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3334     }
3335   if (tree)
3336     {
3337       proto_tree_add_text (request_tree, tvb, offset-4, 4,
3338                            "Request id: %u", request_id);
3339     }
3340
3341   response_expected = tvb_get_guint8( tvb, offset );
3342   offset += 1;
3343   if (check_col(pinfo->cinfo, COL_INFO))
3344     {
3345       col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)",
3346                 response_expected ? "two-way" : "one-way");
3347     }
3348   if (tree)
3349     {
3350       proto_tree_add_text (request_tree, tvb, offset-1, 1,
3351                            "Response expected: %u", response_expected);
3352     }
3353
3354   if( header->GIOP_version.minor > 0)
3355   {
3356      get_CDR_octet_seq( tvb, &reserved, &offset, 3);
3357      if (tree)
3358        {
3359          proto_tree_add_text (request_tree, tvb, offset-3, 3,
3360                            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
3361        }
3362      g_free(reserved);
3363   }
3364
3365
3366
3367   /* Length of object_key sequence */
3368   objkey_len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3369
3370
3371   if(tree)
3372   {
3373          proto_tree_add_text (request_tree, tvb, offset-4, 4,
3374          /**/                 "Object Key length: %u", objkey_len);
3375   } 
3376
3377   if (objkey_len > 0)
3378   {
3379        get_CDR_octet_seq(tvb, &objkey, &offset, objkey_len);
3380
3381        print_objkey = make_printable_string(objkey, objkey_len);
3382
3383        if(tree)
3384        {
3385          proto_tree_add_text (request_tree, tvb, offset - objkey_len, objkey_len,
3386          /**/                 "Object Key: %s", print_objkey);
3387
3388        }
3389
3390        g_free( print_objkey );  
3391   } 
3392
3393   /*
3394    * Register a cleanup function in case on of our tvbuff accesses
3395    * throws an exception. We need to clean up objkey.
3396    */
3397   CLEANUP_PUSH(g_free, objkey);
3398
3399   /* length of operation string and string */ 
3400   len = get_CDR_string(tvb, &operation, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3401   if(tree)
3402   {
3403          proto_tree_add_text (request_tree, tvb, offset - 4 - len, 4,
3404          /**/                 "Operation length: %u", len);
3405   } 
3406
3407   if( len > 0)
3408   {
3409        if (check_col(pinfo->cinfo, COL_INFO))
3410        {
3411          col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", operation);
3412        }
3413        if(tree)
3414        {
3415          proto_tree_add_text (request_tree, tvb, offset - len, len,
3416          /**/                 "Operation: %s", operation);
3417
3418        }
3419   }
3420
3421   /*
3422    * Register a cleanup function in case on of our tvbuff accesses
3423    * throws an exception. We need to clean up operation.
3424    */
3425   CLEANUP_PUSH(g_free, operation);
3426
3427   /* length of requesting_principal string */ 
3428   len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3429   if(tree)
3430   {
3431          proto_tree_add_text (request_tree, tvb, offset-4, 4,
3432          /**/                 "Requesting Principal Length: %u", len);
3433   } 
3434
3435   if( len > 0)
3436   {
3437        get_CDR_octet_seq(tvb, &requesting_principal, &offset, len);
3438
3439        print_requesting_principal = make_printable_string(requesting_principal, len);
3440
3441        if(tree)
3442        {
3443          proto_tree_add_text (request_tree, tvb, offset - len, len, 
3444          /**/                 "Requesting Principal: %s", print_requesting_principal);
3445
3446        }
3447
3448        g_free( print_requesting_principal );
3449        g_free( requesting_principal );
3450   }
3451
3452
3453   /*
3454    * Save FN,reqid,and operation for later. Add sub_handle later.
3455    * But only if user is NOT clicking.
3456    */
3457
3458   if (! pinfo->fd->flags.visited)
3459     giop_complete_request_list = insert_in_comp_req_list(giop_complete_request_list,pinfo->fd->num,
3460                                                          request_id,operation,NULL);
3461
3462   
3463   /*
3464    * Call subdissector here before freeing "operation" and "key"
3465    * pass request_id also. 
3466    * First try an find an explicit sub_dissector, then if that
3467    * fails, try the heuristic method.
3468    *
3469    */
3470
3471
3472   header->req_id = request_id;          /* save for sub dissector */
3473   repoid = get_repoid_from_objkey(giop_objkey_hash,objkey,objkey_len);
3474
3475
3476   if(repoid) {    
3477     exres = try_explicit_giop_dissector(tvb,pinfo,tree,&offset,header,operation,repoid);
3478   }
3479
3480   /* Only call heuristic if no explicit dissector was found */
3481
3482   if (! exres) {
3483     try_heuristic_giop_dissector(tvb,pinfo,tree,&offset,header,operation);
3484   }
3485   
3486
3487   /*
3488    * We're done with operation, so we can call the cleanup handler to free
3489    * it, and then pop the cleanup handler.
3490    */
3491   CLEANUP_CALL_AND_POP;
3492
3493   /*
3494    * We're done with objkey, so we can call the cleanup handler to free
3495    * it, and then pop the cleanup handler.
3496    */
3497   CLEANUP_CALL_AND_POP;
3498
3499 }
3500
3501 /**  The format of a GIOP 1.2 RequestHeader message is 
3502  *   (CORBA 2.4, sec. 15.4.2):
3503  *
3504  *   struct RequestHeader_1_2 {
3505  *       unsigned long request_id;
3506  *       octet response_flags;
3507  *       octet reserved[3];
3508  *       TargetAddress target;
3509  *       string operation;
3510  *       IOP::ServiceContextList service_context;
3511  *       // requesting_principal not in GIOP 1.2
3512  *   };
3513  */
3514 static void
3515 dissect_giop_request_1_2 (tvbuff_t * tvb, packet_info * pinfo,
3516                         proto_tree * tree, proto_tree * clnp_tree,
3517                         MessageHeader * header, gboolean stream_is_big_endian)
3518 {
3519   guint32 offset = 0;
3520   guint32 request_id;
3521   guint32 len = 0;
3522   guint8 response_flags;
3523   gchar *reserved;
3524   gchar *operation = NULL;
3525   proto_tree *request_tree = NULL;
3526   proto_item *tf;
3527   gboolean exres = FALSE;               /* result of trying explicit dissectors */
3528
3529   gchar *repoid = NULL;
3530
3531
3532   if (tree)
3533     {
3534       tf = proto_tree_add_text (tree, tvb, offset,
3535                                 tvb_length (tvb),
3536                                 "General Inter-ORB Protocol Request");
3537       request_tree = proto_item_add_subtree (tf, ett_giop_reply);
3538     }
3539
3540   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3541   if (check_col(pinfo->cinfo, COL_INFO))
3542     {
3543       col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3544     }
3545   if (request_tree)
3546     {
3547       proto_tree_add_text (request_tree, tvb, offset-4, 4,
3548                            "Request id: %u", request_id);
3549     }
3550
3551   response_flags = tvb_get_guint8( tvb, offset );
3552   offset += 1;
3553   if (request_tree)
3554     {
3555       proto_tree_add_text (request_tree, tvb, offset-1, 1,
3556                            "Response flags: %s (%u)",
3557                                 match_strval(response_flags, sync_scope),  
3558                                 response_flags);
3559     }
3560
3561   get_CDR_octet_seq( tvb, &reserved, &offset, 3);
3562   if (request_tree)
3563    {
3564      proto_tree_add_text (request_tree, tvb, offset-3, 3,
3565            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
3566    }
3567   g_free(reserved);
3568
3569   dissect_target_address(tvb, pinfo, &offset, request_tree, header, stream_is_big_endian);
3570
3571   /* length of operation string */ 
3572   len = get_CDR_string(tvb, &operation, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3573   if(tree)
3574   {
3575          proto_tree_add_text (request_tree, tvb, offset - len - 4, 4,
3576          /**/                 "Operation length: %u", len);
3577   } 
3578
3579   if( len > 0)
3580   {
3581        if (check_col(pinfo->cinfo, COL_INFO))
3582        {
3583          col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", operation);
3584        }
3585        if(request_tree)
3586        {
3587          proto_tree_add_text (request_tree, tvb, offset - len, len,
3588          /**/                 "Operation: %s", operation);
3589
3590        }
3591
3592   }
3593
3594   /*
3595    * Register a cleanup function in case on of our tvbuff accesses
3596    * throws an exception. We need to clean up operation.
3597    */
3598   CLEANUP_PUSH(g_free, operation);
3599
3600   /*
3601    * Decode IOP::ServiceContextList
3602    */
3603
3604   decode_ServiceContextList(tvb, pinfo, request_tree, &offset,  stream_is_big_endian, GIOP_HEADER_SIZE);
3605
3606   /*
3607    * GIOP 1.2 Request body must fall on an 8 octet alignment, taking into
3608    * account we are in a new tvbuff, GIOP_HEADER_SIZE octets from the
3609    * GIOP octet stream start.
3610    */
3611
3612   set_new_alignment(&offset, GIOP_HEADER_SIZE, 8);
3613
3614   /*
3615    * Save FN,reqid,and operation for later. Add sub_handle later.
3616    * But only if user is NOT clicking.
3617    */
3618   
3619   if (! pinfo->fd->flags.visited)
3620     giop_complete_request_list = insert_in_comp_req_list(giop_complete_request_list,pinfo->fd->num,
3621                                                          request_id,operation,NULL);
3622
3623   /*
3624    *
3625    * Call sub dissector.
3626    * First try an find a explicit sub_dissector, then if that
3627    * fails, try the heuristic method.
3628    */
3629   
3630
3631   if(repoid) {    
3632     exres = try_explicit_giop_dissector(tvb,pinfo,tree,&offset,header,operation,repoid);
3633   }
3634
3635   /* Only call heuristic if no explicit dissector was found */
3636
3637   if (! exres) {
3638     try_heuristic_giop_dissector(tvb,pinfo,tree,&offset,header,operation);
3639   }
3640   
3641
3642   /*
3643    * We're done with operation, so we can call the cleanup handler to free
3644    * it, and then pop the cleanup handler.
3645    */
3646   CLEANUP_CALL_AND_POP;
3647 }
3648
3649 static void
3650 dissect_giop_locate_request( tvbuff_t * tvb, packet_info * pinfo,
3651                         proto_tree * tree, MessageHeader * header,
3652                         gboolean stream_is_big_endian)
3653 {
3654   guint32 offset = 0;
3655   guint32 request_id;
3656   guint32 len = 0;
3657   gchar *object_key;
3658   gchar *p_object_key;
3659   proto_tree *locate_request_tree = NULL;
3660   proto_item *tf;
3661
3662   if (tree)
3663     {
3664       tf = proto_tree_add_text (tree, tvb, offset,
3665                                 tvb_length (tvb),
3666                                 "General Inter-ORB Locate Request");
3667       if (locate_request_tree == NULL)
3668         {
3669           locate_request_tree = proto_item_add_subtree (tf, ett_giop_locate_request);
3670
3671         }
3672     }
3673
3674   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3675   if (check_col(pinfo->cinfo, COL_INFO))
3676     {
3677       col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3678     }
3679   if (locate_request_tree)
3680     {
3681       proto_tree_add_text (locate_request_tree, tvb, offset-4, 4,
3682                            "Request id: %u", request_id);
3683     }
3684
3685   if(header->GIOP_version.minor < 2)
3686   {
3687         len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3688         if (locate_request_tree)
3689           {
3690             proto_tree_add_text (locate_request_tree, tvb, offset-4, 4,
3691                                  "Object Key length: %u", len);
3692           }
3693
3694         if (len > 0) {
3695           get_CDR_octet_seq(tvb, &object_key, &offset, len);
3696
3697           p_object_key = make_printable_string(object_key, len);
3698   
3699           if(locate_request_tree)
3700             {
3701
3702               proto_tree_add_text (locate_request_tree, tvb, offset-len, len,
3703                                    "Object Key: %s", p_object_key);
3704             }
3705
3706           g_free(p_object_key);
3707           g_free(object_key);
3708         }
3709   }
3710   else     /* GIOP 1.2 and higher */
3711   {
3712       dissect_target_address(tvb, pinfo, &offset, locate_request_tree, header,
3713                              stream_is_big_endian);
3714
3715   }
3716 }
3717
3718 static void
3719 dissect_giop_locate_reply( tvbuff_t * tvb, packet_info * pinfo,
3720                         proto_tree * tree, MessageHeader * header,
3721                         gboolean stream_is_big_endian)
3722 {
3723   guint32 offset = 0;
3724   guint32 request_id;
3725   guint32 locate_status;
3726   guint16 addr_disp;
3727
3728   proto_tree *locate_reply_tree = NULL;
3729   proto_item *tf;
3730
3731   if (tree)
3732     {
3733       tf = proto_tree_add_text (tree, tvb, offset,
3734                                 tvb_length (tvb),
3735                                 "General Inter-ORB Locate Reply");
3736       if (locate_reply_tree == NULL)
3737         {
3738           locate_reply_tree = proto_item_add_subtree (tf, ett_giop_locate_reply);
3739
3740         }
3741     }
3742
3743   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3744   if (check_col(pinfo->cinfo, COL_INFO))
3745     {
3746       col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3747     }
3748   if (locate_reply_tree)
3749     {
3750       proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
3751                            "Request id: %u", request_id);
3752     }
3753
3754   locate_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3755   if (locate_reply_tree)
3756     {
3757       proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
3758                            "Locate status: %s", 
3759                            match_strval(locate_status, giop_locate_status_types)
3760                            );
3761     }
3762
3763   /* Decode the LocateReply body.
3764    *
3765    * For GIOP 1.0 and 1.1 body immediately follows header.
3766    * For GIOP 1.2 it is aligned on 8 octet boundary so need to
3767    * spin up.
3768    */
3769
3770   if (header->GIOP_version.minor > 1) {
3771     while( ( (offset + GIOP_HEADER_SIZE) % 8) != 0)
3772       ++(offset);
3773   }
3774
3775   switch(locate_status) {
3776   case OBJECT_FORWARD: /* fall through to OBJECT_FORWARD_PERM */
3777   case OBJECT_FORWARD_PERM:
3778     decode_IOR(tvb, pinfo, locate_reply_tree, &offset, GIOP_HEADER_SIZE, stream_is_big_endian);
3779     break;
3780   case LOC_SYSTEM_EXCEPTION:
3781     decode_SystemExceptionReplyBody (tvb, tree, &offset, stream_is_big_endian, GIOP_HEADER_SIZE);
3782     break;
3783   case LOC_NEEDS_ADDRESSING_MODE:
3784     addr_disp = get_CDR_ushort(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3785     if(locate_reply_tree) {
3786       proto_tree_add_text (tree, tvb, offset -2, 2,
3787                            "AddressingDisposition: %u", addr_disp);
3788     }
3789     break;
3790   default: /* others have no reply body */
3791     break;
3792   }
3793
3794 }
3795
3796 static void
3797 dissect_giop_fragment( tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
3798                         MessageHeader * header, gboolean stream_is_big_endian)
3799 {
3800   guint32 offset = 0;
3801   guint32 request_id;
3802   proto_tree *fragment_tree = NULL;
3803   proto_item *tf;
3804
3805   if (tree)
3806     {
3807       tf = proto_tree_add_text (tree, tvb, offset,
3808                                 tvb_length (tvb),
3809                                 "General Inter-ORB Fragment");
3810       if (fragment_tree == NULL)
3811         {
3812           fragment_tree = proto_item_add_subtree (tf, ett_giop_fragment);
3813
3814         }
3815     }
3816
3817   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3818   if (check_col(pinfo->cinfo, COL_INFO))
3819     {
3820       col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3821     }
3822   if (fragment_tree )
3823     {
3824       proto_tree_add_text (fragment_tree, tvb, offset-4, 4,
3825                            "Request id: %u", request_id);
3826     }
3827                                    
3828 }
3829
3830
3831 /* Main entry point */
3832
3833 gboolean dissect_giop (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) {
3834   u_int offset = 0;
3835   MessageHeader header;
3836   tvbuff_t *giop_header_tvb;
3837   tvbuff_t *payload_tvb;
3838
3839   proto_tree *clnp_tree = NULL;
3840   proto_item *ti;
3841   u_int message_size;
3842   u_int minor_version;
3843   gboolean stream_is_big_endian;
3844
3845
3846   /* DEBUG */
3847   
3848 #if DEBUG
3849   giop_dump_collection(cd_module_hash);
3850   giop_dump_collection(cd_objkey_hash);
3851   giop_dump_collection(cd_heuristic_users);
3852   giop_dump_collection(cd_complete_reply_hash);
3853   giop_dump_collection(cd_complete_request_list);
3854 #endif
3855
3856   header.exception_id = NULL;
3857
3858   /* check magic number and version */
3859
3860
3861   /*define END_OF_GIOP_MESSAGE (offset - first_offset - GIOP_HEADER_SIZE) */
3862
3863   if (tvb_length_remaining(tvb, 0) < GIOP_HEADER_SIZE)
3864     {
3865       /* Not enough data captured to hold the GIOP header; don't try
3866          to interpret it as GIOP. */
3867       return FALSE;
3868     }
3869
3870   giop_header_tvb = tvb_new_subset (tvb, 0, GIOP_HEADER_SIZE, -1);
3871   payload_tvb = tvb_new_subset (tvb, GIOP_HEADER_SIZE, -1, -1);
3872   
3873   /*
3874    * because I have added extra elements in MessageHeader struct
3875    * for sub dissectors. -- FS
3876    */
3877
3878   tvb_memcpy (giop_header_tvb, (guint8 *)&header, 0, GIOP_HEADER_SIZE );
3879
3880   if (memcmp (header.magic, GIOP_MAGIC, sizeof (header.magic)) != 0)
3881     {
3882       /* Not a GIOP message. */
3883
3884       return FALSE;
3885     }
3886
3887   if (check_col (pinfo->cinfo, COL_PROTOCOL))
3888     {
3889       col_set_str (pinfo->cinfo, COL_PROTOCOL, "GIOP");
3890     }
3891
3892   if (header.GIOP_version.major != GIOP_MAJOR ||
3893       ((minor_version = header.GIOP_version.minor) > GIOP_MINOR))
3894     {
3895       /* Bad version number; should we note that and dissect the rest
3896          as data, or should we return FALSE on the theory that it
3897          might have been some other packet that happened to begin with
3898          "GIOP"?  We shouldn't do *both*, so we return TRUE, for now.
3899          If we should return FALSE, we should do so *without* setting
3900          the "Info" column, *without* setting the "Protocol" column,
3901          and *without* adding anything to the protocol tree. */
3902
3903       if (check_col (pinfo->cinfo, COL_INFO))
3904         {
3905           col_add_fstr (pinfo->cinfo, COL_INFO, "Version %u.%u",
3906                         header.GIOP_version.major, header.GIOP_version.minor);
3907         }
3908       if (tree)
3909         {
3910           ti = proto_tree_add_item (tree, proto_giop, tvb, 0,
3911                                     tvb_length (tvb), FALSE);
3912           clnp_tree = proto_item_add_subtree (ti, ett_giop);
3913           proto_tree_add_text (clnp_tree, giop_header_tvb, 0,
3914                                tvb_length (giop_header_tvb),
3915                                "Version %u.%u not supported",
3916                                header.GIOP_version.major,
3917                                header.GIOP_version.minor);
3918         }
3919       call_dissector(data_handle,payload_tvb, pinfo, tree);
3920       return TRUE;
3921     }
3922
3923   if (check_col (pinfo->cinfo, COL_INFO)) 
3924   { 
3925       col_add_fstr (pinfo->cinfo, COL_INFO, "GIOP %u.%u %s",
3926                     header.GIOP_version.major, header.GIOP_version.minor,
3927                     val_to_str(header.message_type, giop_message_types,
3928                                "Unknown message type (0x%02x)"));
3929   }
3930
3931   stream_is_big_endian = is_big_endian (&header);
3932
3933   if (stream_is_big_endian)
3934     message_size = pntohl (&header.message_size);
3935   else
3936     message_size = pletohl (&header.message_size);
3937
3938   if (tree)
3939     {
3940       ti = proto_tree_add_item (tree, proto_giop, tvb, 0, 12, FALSE);
3941       clnp_tree = proto_item_add_subtree (ti, ett_giop);
3942       proto_tree_add_text (clnp_tree, giop_header_tvb, offset, 4,
3943                            "Magic number: %s", GIOP_MAGIC);
3944       proto_tree_add_text (clnp_tree, giop_header_tvb, 4, 2,
3945                            "Version: %u.%u",
3946                            header.GIOP_version.major,
3947                            header.GIOP_version.minor);
3948       switch (minor_version)
3949         {
3950         case 2:
3951         case 1:
3952           proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
3953                                "Flags: 0x%02x (%s %s)",
3954                                header.flags,
3955                                (stream_is_big_endian) ? "big-endian" : "little-endian",
3956                                (header.flags & 0x02) ? " fragment" : "");
3957           break;
3958         case 0:
3959           proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
3960                                "Byte ordering: %s-endian",
3961                                (stream_is_big_endian) ? "big" : "little");
3962           break;
3963         default:
3964           break;
3965         }                       /* minor_version */
3966
3967       proto_tree_add_uint_format (clnp_tree,
3968                                   hf_giop_message_type,
3969                                   giop_header_tvb, 7, 1,
3970                                   header.message_type,
3971                                   "Message type: %s", match_strval(header.message_type, giop_message_types));
3972
3973       proto_tree_add_uint (clnp_tree,
3974                            hf_giop_message_size,
3975                            giop_header_tvb, 8, 4, message_size);
3976
3977     }                           /* tree */
3978
3979 #if 0
3980   if (check_col (pinfo->cinfo, COL_INFO)) 
3981   { 
3982       col_add_fstr (pinfo->cinfo, COL_INFO, "GIOP %u.%u %s",
3983                     header.GIOP_version.major, header.GIOP_version.minor,
3984                     match_strval(header.message_type, giop_message_types));
3985   }
3986 #endif
3987
3988   switch (header.message_type)
3989     {
3990
3991     case Request:
3992       if(header.GIOP_version.minor < 2)
3993       {
3994            dissect_giop_request_1_1 (payload_tvb, pinfo, tree, clnp_tree,
3995                                      &header, stream_is_big_endian);
3996       }
3997       else
3998       {    
3999            dissect_giop_request_1_2 (payload_tvb, pinfo, tree, clnp_tree,
4000                                      &header, stream_is_big_endian);
4001       }
4002       
4003       break;
4004
4005
4006     case Reply:
4007       if(header.GIOP_version.minor < 2)
4008         {
4009            dissect_giop_reply (payload_tvb, pinfo, tree, clnp_tree, &header,
4010                                stream_is_big_endian);
4011         }
4012       else
4013         {
4014            dissect_giop_reply_1_2 (payload_tvb, pinfo, tree, clnp_tree,
4015                                    &header, stream_is_big_endian);
4016         }
4017       break;
4018     case CancelRequest:
4019         dissect_giop_cancel_request(payload_tvb, pinfo, tree, clnp_tree,
4020                                     &header, stream_is_big_endian);
4021         break;
4022     case LocateRequest:
4023         dissect_giop_locate_request(payload_tvb, pinfo, tree, &header,
4024                                     stream_is_big_endian);
4025         break;
4026     case LocateReply:
4027         dissect_giop_locate_reply(payload_tvb, pinfo, tree, &header,
4028                                   stream_is_big_endian);
4029         break;
4030     case Fragment:
4031         dissect_giop_fragment(payload_tvb, pinfo, tree, &header,
4032                               stream_is_big_endian);
4033         break;  
4034     default:
4035       break;
4036
4037     }                           /* switch message_type */
4038
4039
4040   /*
4041    * XXX - we should catch exceptions here, so that we can free
4042    * this if an exception is thrown.
4043    * We'd then have to forward the exception.
4044    */
4045   if (header.exception_id != NULL)
4046     g_free(header.exception_id);
4047
4048   return TRUE;
4049 }
4050
4051 void
4052 proto_register_giop (void)
4053 {
4054   static hf_register_info hf[] = {
4055     { &hf_giop_message_type,
4056      { "Message type", "giop.type",
4057        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4058     },
4059     
4060     { &hf_giop_message_size,
4061       { "Message size", "giop.len",
4062         FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4063     },
4064
4065     { &hf_giop_repoid,
4066      { "Repository ID", "giop.repoid",
4067        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4068     },
4069
4070     { &hf_giop_string_length,
4071      { "String Length", "giop.strlen",
4072        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4073     },
4074
4075     { &hf_giop_sequence_length,
4076      { "Sequence Length", "giop.seqlen",
4077        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4078     },
4079
4080     { &hf_giop_profile_id,
4081      { "Profile ID", "giop.profid",
4082        FT_UINT32, BASE_DEC, VALS(profile_id_vals), 0x0, "", HFILL }
4083     },
4084
4085
4086     { &hf_giop_type_id,
4087      { "IOR::type_id", "giop.typeid",
4088        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4089     },
4090
4091     { &hf_giop_iiop_v_maj,
4092      { "IIOP Major Version", "giop.iiop_vmaj",
4093        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4094     }
4095     ,
4096     { &hf_giop_iiop_v_min,
4097      { "IIOP Minor Version", "giop.iiop_vmin",
4098        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4099     },
4100
4101     { &hf_giop_endianess,
4102      { "Endianess", "giop.endianess",
4103        FT_UINT8, BASE_DEC, VALS(giop_endianess_vals), 0x0, "", HFILL }
4104     },
4105
4106     { &hf_giop_IIOP_tag,
4107      { "IIOP Component TAG", "giop.iioptag",
4108        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4109     },
4110
4111     { &hf_giop_IOR_tag,
4112      { "IOR Profile TAG", "giop.iortag",
4113        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4114     },
4115
4116     { &hf_giop_TCKind,
4117      { "TypeCode enum", "giop.TCKind",
4118        FT_UINT32, BASE_DEC, VALS(tckind_vals), 0x0, "", HFILL }
4119     },
4120
4121     { &hf_giop_typecode_count,
4122      { "TypeCode count", "giop.tccount",
4123        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4124     },
4125
4126     { &hf_giop_typecode_default_used,
4127      { "default_used", "giop.tcdefault_used",
4128        FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL }
4129     },
4130
4131     { &hf_giop_typecode_digits,
4132      { "Digits", "giop.tcdigits",
4133        FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
4134     },
4135
4136
4137     { &hf_giop_typecode_length,
4138      { "Length", "giop.tclength",
4139        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4140     },
4141
4142     { &hf_giop_typecode_max_length,
4143      { "Maximum length", "giop.tcmaxlen",
4144        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4145     },
4146
4147     { &hf_giop_typecode_member_name,
4148      { "TypeCode member name", "giop.tcmemname",
4149        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4150     },
4151
4152     { &hf_giop_typecode_name,
4153      { "TypeCode name", "giop.tcname",
4154        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4155     },
4156
4157     { &hf_giop_typecode_scale,
4158      { "Scale", "giop.tcscale",
4159        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4160     },
4161
4162     { &hf_giop_typecode_ValueModifier,
4163      { "ValueModifier", "giop.tcValueModifier",
4164        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4165     },
4166
4167     { &hf_giop_typecode_Visibility,
4168      { "Visibility", "giop.tcVisibility",
4169        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4170     },
4171
4172
4173
4174     { &hf_giop_type_boolean,
4175       { "TypeCode boolean data", "giop.tcboolean",
4176         FT_BOOLEAN, BASE_DEC,  NULL, 0x0, "", HFILL }
4177     },
4178
4179     { &hf_giop_type_char,
4180       { "TypeCode char data", "giop.tcchar",
4181         FT_UINT8, BASE_DEC,  NULL, 0x0, "", HFILL }
4182     },
4183
4184     { &hf_giop_type_double,
4185       { "TypeCode double data", "giop.tcdouble",
4186         FT_DOUBLE, BASE_DEC,  NULL, 0x0, "", HFILL }
4187     },
4188
4189     { &hf_giop_type_enum,
4190      { "TypeCode enum data", "giop.tcenumdata",
4191        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4192     },
4193
4194     /*
4195      * float as double ?? -- FIX
4196      */
4197
4198     { &hf_giop_type_float,
4199       { "TypeCode float data", "giop.tcfloat",
4200         FT_DOUBLE, BASE_DEC,  NULL, 0x0, "", HFILL }
4201     },
4202
4203     { &hf_giop_type_long,
4204      { "TypeCode long data", "giop.tclongdata",
4205        FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL }
4206     },
4207
4208     { &hf_giop_type_octet,
4209       { "TypeCode octet data", "giop.tcoctet",
4210         FT_UINT8, BASE_DEC,  NULL, 0x0, "", HFILL }
4211     },
4212
4213     { &hf_giop_type_short,
4214      { "TypeCode short data", "giop.tcshortdata",
4215        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4216     },
4217
4218     { &hf_giop_type_string,
4219       { "TypeCode string data", "giop.tcstring",
4220         FT_STRING, BASE_DEC,  NULL, 0x0, "", HFILL }
4221     },
4222
4223     { &hf_giop_type_ulong,
4224      { "TypeCode ulong data", "giop.tculongdata",
4225        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4226     },
4227
4228     { &hf_giop_type_ushort,
4229      { "TypeCode ushort data", "giop.tcushortdata",
4230        FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
4231     },
4232
4233     /*
4234      * IIOP Module - Chapter 15.10.2
4235      */
4236
4237     { &hf_giop_iiop_host,
4238      { "IIOP::Profile_host", "giop.iiop.host",
4239        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4240     }
4241     ,
4242
4243     { &hf_giop_iiop_port,
4244      { "IIOP::Profile_port", "giop.iiop.port",
4245        FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
4246     }
4247     ,
4248
4249     /*
4250      * IIOP ServiceContext
4251      */
4252
4253     { &hf_giop_iop_vscid,
4254      { "VSCID", "giop.iiop.vscid",
4255        FT_UINT32, BASE_HEX, NULL, 0xfffff000, "", HFILL }
4256     }
4257     ,
4258
4259     { &hf_giop_iop_scid,
4260      { "SCID", "giop.iiop.scid",
4261        FT_UINT32, BASE_HEX, NULL, 0x00000fff, "", HFILL }
4262     }
4263     ,
4264
4265
4266   };
4267
4268   static gint *ett[] = {
4269     &ett_giop,
4270     &ett_giop_reply,
4271     &ett_giop_request,
4272     &ett_giop_cancel_request,
4273     &ett_giop_locate_request,
4274     &ett_giop_locate_reply,
4275     &ett_giop_fragment,
4276     &ett_giop_scl,
4277     &ett_giop_ior
4278
4279   };
4280   proto_giop = proto_register_protocol("General Inter-ORB Protocol", "GIOP",
4281                                        "giop");
4282   proto_register_field_array (proto_giop, hf, array_length (hf));
4283   proto_register_subtree_array (ett, array_length (ett));
4284
4285
4286   /* register init routine */
4287
4288   register_init_routine( &giop_init); /* any init stuff */
4289
4290   /*
4291    * Init the giop user module hash tables here, as giop users
4292    * will populate it via register_giop_user_module BEFORE my
4293    * own giop_init() is called.
4294    */
4295
4296   giop_module_hash = g_hash_table_new(giop_hash_module_hash, giop_hash_module_equal);
4297   
4298   giop_module_keys = g_mem_chunk_new("giop_module_keys",
4299                                      sizeof(struct giop_module_key),
4300                                      giop_module_init_count * sizeof(struct giop_module_key), 
4301                                      G_ALLOC_AND_FREE);
4302   
4303   giop_module_vals = g_mem_chunk_new("giop_module_vals", 
4304                                      sizeof(struct giop_module_val),
4305                                      giop_module_init_count * sizeof(struct giop_module_val), 
4306                                      G_ALLOC_AND_FREE);
4307   
4308 }
4309
4310
4311
4312 void proto_reg_handoff_giop (void) {
4313   data_handle = find_dissector("data");
4314   heur_dissector_add("tcp", dissect_giop, proto_giop);
4315 }
4316
4317
4318
4319
4320 /*
4321  * Decode IOR
4322  *
4323  * Ref Corba v2.4.2 Chapter 13
4324  *
4325  */
4326
4327 /*
4328
4329 module IOP{ 
4330
4331     typedef unsigned long ProfileId;
4332
4333     const ProfileId TAG_INTERNET_IOP = 0;
4334     const ProfileId TAG_MULTIPLE_COMPONENTS = 1;
4335
4336     struct TaggedProfile {
4337       ProfileId tag;
4338       sequence <octet> profile_data;
4339     };
4340
4341     struct IOR {
4342       string type_id;
4343       sequence <TaggedProfile> profiles;
4344     };
4345
4346     typedef unsigned long ComponentId;
4347
4348     struct TaggedComponent {
4349       ComponentId tag;
4350       sequence <octet> component_data;
4351     };
4352
4353     typedef sequence <TaggedComponent> MultipleComponentProfile;
4354
4355 };
4356
4357 */
4358
4359 void decode_IOR(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ptree, int *offset,
4360                 guint32 boundary, gboolean stream_is_big_endian) {
4361
4362
4363   guint32 seqlen_p;             /* sequence length of profiles */
4364   guint32 u_octet4;
4365
4366   proto_tree *tree = NULL;      /* IOR tree */
4367   proto_item *tf;
4368
4369   gchar *repobuf;               /* for repository ID */
4370
4371   guint32 i;
4372
4373   /* create a subtree */
4374
4375   if (ptree) {
4376     tf = proto_tree_add_text (ptree, tvb, *offset, tvb_length (tvb), "IOR");
4377     tree = proto_item_add_subtree (tf, ett_giop_ior);
4378   }
4379
4380
4381   /* Get type_id  == Repository ID */
4382
4383   u_octet4 = get_CDR_string(tvb,&repobuf,offset,stream_is_big_endian,boundary);
4384
4385   if (tree) {    
4386     proto_tree_add_uint(tree,hf_giop_string_length,tvb,
4387                         *offset-u_octet4-sizeof(u_octet4),4,u_octet4);
4388     if (u_octet4 > 0) {
4389       proto_tree_add_string(tree,hf_giop_type_id,tvb,
4390                             *offset-u_octet4,u_octet4,repobuf);
4391     }
4392   }
4393
4394   /*
4395    * Register a cleanup function in case on of our tvbuff accesses
4396    * throws an exception. We need to clean up repobuf.
4397    * We can't free it yet, as we must wait until we have the object
4398    * key, as we have to add both to the hash table.
4399    */
4400   CLEANUP_PUSH(g_free, repobuf);
4401
4402   /* Now get a sequence of profiles */
4403   /* Get sequence length (number of elements) */
4404   
4405   seqlen_p = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
4406   if (tree) {
4407     proto_tree_add_uint(tree,hf_giop_sequence_length,tvb,
4408                         *offset-sizeof(seqlen_p),4,seqlen_p);
4409   }
4410   
4411
4412   /* fetch all TaggedProfiles in this sequence */
4413   
4414   for (i=0; i< seqlen_p; i++) { /* for every TaggedProfile */
4415     decode_TaggedProfile(tvb, pinfo, tree, offset, boundary, stream_is_big_endian, repobuf);
4416   }
4417
4418   /*
4419    * We're done with repobuf, so we can call the cleanup handler to free
4420    * it, and then pop the cleanup handler.
4421    */
4422   CLEANUP_CALL_AND_POP;
4423
4424 }
4425
4426 static void decode_TaggedProfile(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
4427                                  guint32 boundary, gboolean stream_is_big_endian, gchar *repobuf) {
4428
4429   guint32 seqlen_pd;            /* sequence length of profile data */
4430
4431   guint32 pidtag;               /* profile ID TAG */
4432
4433   gchar *profile_data;          /* profile_data pointer */
4434   gchar *p_profile_data;        /* printable profile_data pointer */
4435
4436   guint32 new_boundary;         /* for encapsulations encountered */
4437   gboolean new_big_endianess;   /* for encapsulations encountered */
4438
4439   /* Get ProfileId tag */
4440
4441   pidtag = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
4442
4443   if (tree) {
4444     proto_tree_add_uint(tree,hf_giop_profile_id,tvb,
4445                         *offset-sizeof(pidtag),4,pidtag);
4446   }
4447
4448   /* get sequence length, new endianness and boundary for encapsulation */
4449   
4450   seqlen_pd = get_CDR_encap_info(tvb, tree, offset, 
4451                                  stream_is_big_endian, boundary,
4452                                  &new_big_endianess, &new_boundary);
4453
4454   /* return if zero length sequence */
4455
4456   if(seqlen_pd == 0)
4457     return;
4458
4459     
4460   /*
4461    * Lets see what kind of TAG it is. If TAG_INTERNET_IOP then 
4462    * decode it, otherwise just dump the octet sequence 
4463    *
4464    * also, store IOR in our objectkey hash
4465    *
4466    * TODO - handle other TAGS
4467    */
4468
4469   switch(pidtag) {
4470   case IOP_TAG_INTERNET_IOP:
4471     
4472     decode_IIOP_IOR_profile(tvb, pinfo, tree, offset, new_boundary, new_big_endianess, repobuf, TRUE);
4473     break;
4474
4475   default:
4476     
4477     /* fetch all octets in this sequence , but skip endianess */
4478       
4479     get_CDR_octet_seq(tvb, &profile_data, offset, seqlen_pd -1);
4480       
4481     /* Make a printable string */
4482       
4483     p_profile_data = make_printable_string( profile_data, seqlen_pd -1);
4484       
4485     if(tree) {
4486       proto_tree_add_text (tree, tvb, *offset -seqlen_pd + 1, seqlen_pd - 1,
4487                            "Profile Data: %s", p_profile_data);
4488     }
4489       
4490     g_free(p_profile_data);
4491
4492     g_free(profile_data);
4493
4494     break;
4495       
4496   }
4497
4498 }
4499
4500
4501
4502 /*
4503  * Decode IIOP IOR Profile
4504  * Ref Chap 15.7.2 in Corba Spec
4505  */
4506
4507
4508 static void decode_IIOP_IOR_profile(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
4509                                     guint32 boundary, gboolean stream_is_big_endian, gchar *repo_id_buf,
4510                                     gboolean store_flag) {
4511
4512   guint32 i;                    /* loop index */
4513
4514   guint8 v_major,v_minor;       /* IIOP sersion */
4515   gchar *buf;
4516   guint32 u_octet4;             /* u long */
4517   guint16 u_octet2;             /* u short */
4518   guint32 seqlen;               /* generic sequence length */
4519   guint32 seqlen1;              /* generic sequence length */
4520   gchar *objkey;                /* object key pointer */
4521   gchar *p_chars;               /* printable characters pointer */
4522
4523   
4524   /* Get major/minor version */
4525
4526   v_major = get_CDR_octet(tvb,offset);
4527   v_minor = get_CDR_octet(tvb,offset);
4528
4529
4530   if (tree) {    
4531     proto_tree_add_uint(tree,hf_giop_iiop_v_maj,tvb,
4532                         *offset-sizeof(v_minor)-sizeof(v_major),1,v_major  );
4533     proto_tree_add_uint(tree,hf_giop_iiop_v_min,tvb,
4534                         *offset-sizeof(v_minor),1,v_minor  );
4535   }
4536
4537
4538   /* host */
4539   
4540   u_octet4 = get_CDR_string(tvb,&buf,offset,stream_is_big_endian,boundary);
4541    
4542   if (tree) {    
4543     proto_tree_add_uint(tree,hf_giop_string_length,tvb,
4544                         *offset-u_octet4-sizeof(u_octet4),4,u_octet4);
4545     if (u_octet4 > 0) {
4546       proto_tree_add_string(tree,hf_giop_iiop_host,tvb,
4547                             *offset-u_octet4,u_octet4,buf);
4548     }
4549   }
4550   
4551   g_free(buf);          /* dont forget */
4552     
4553   /* Port */
4554
4555   u_octet2 = get_CDR_ushort(tvb,offset,stream_is_big_endian,boundary);
4556
4557   if (tree) {    
4558     proto_tree_add_uint(tree,hf_giop_iiop_port,tvb,
4559                         *offset-sizeof(u_octet2),2,u_octet2);
4560   }
4561
4562
4563   /* Object Key - sequence<octet> object_key */
4564
4565   seqlen = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
4566
4567   if (tree) {
4568     proto_tree_add_uint(tree,hf_giop_sequence_length,tvb,
4569                         *offset-sizeof(seqlen),4,seqlen);
4570   }
4571
4572   if (seqlen > 0) {
4573     /* fetch all octets in this sequence */  
4574     get_CDR_octet_seq(tvb, &objkey, offset, seqlen);
4575
4576     /*
4577      * Now we may have the Repository ID from earlier, as well
4578      * as the object key sequence and lengh. So lets store them in
4579      * our objectkey hash and free buffers.
4580      *
4581      * But only insert if user is not clicking and repo id not NULL.
4582      *
4583      */
4584
4585     if (repo_id_buf) {
4586       if (pinfo) {
4587         if(!pinfo->fd->flags.visited)
4588           insert_in_objkey_hash(giop_objkey_hash,objkey,seqlen,repo_id_buf,req_res); 
4589       }
4590       else {
4591  
4592         /*
4593          * No pinfo, but store anyway if flag set. eg: IOR read from file
4594          */
4595
4596         if (store_flag)
4597           insert_in_objkey_hash(giop_objkey_hash,objkey,seqlen,repo_id_buf,file); 
4598       }
4599     }
4600
4601     /* Make a printable string */
4602   
4603     p_chars = make_printable_string( objkey, seqlen );
4604   
4605     if(tree) {
4606       proto_tree_add_text (tree, tvb, *offset -seqlen, seqlen,
4607                          "Object Key: %s", p_chars);
4608     }
4609
4610     g_free(p_chars);
4611     g_free(objkey);  
4612   }
4613   
4614   /*
4615    * Now see if if its v1.1 or 1.2, as they can contain
4616    * extra sequence of IOP::TaggedComponents
4617    *
4618    */
4619   
4620   switch(v_minor) {
4621   case 0:
4622
4623     /* nothing extra */
4624     break;
4625
4626   case 1:
4627   case 2:
4628
4629     /* sequence of IOP::TaggedComponents */
4630     /* Ref Chap 13 in Corba Spec */
4631
4632     /* get sequence length */
4633     seqlen = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
4634
4635     if (tree) {
4636       proto_tree_add_uint(tree,hf_giop_sequence_length,tvb,
4637                           *offset-sizeof(seqlen),4,seqlen);
4638     }
4639
4640     for (i=0; i< seqlen; i++) {
4641       /* get tag */
4642       u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
4643       if (tree) {
4644         proto_tree_add_uint(tree,hf_giop_IIOP_tag,tvb,
4645                             *offset-sizeof(u_octet4),4,u_octet4);
4646       }
4647
4648       /* get component_data */
4649       seqlen1 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
4650       if (tree) {
4651         proto_tree_add_uint(tree,hf_giop_sequence_length,tvb,
4652                             *offset-sizeof(seqlen1),4,seqlen1);
4653       }
4654
4655       if (seqlen1 > 0) {
4656         get_CDR_octet_seq(tvb, &buf, offset, seqlen1);
4657
4658         if (tree) {
4659           /* Make a printable string of data */
4660   
4661           p_chars = make_printable_string(buf, seqlen1);
4662   
4663           proto_tree_add_text (tree, tvb, *offset -seqlen1, seqlen1,
4664                                "component_data: %s", p_chars);
4665   
4666           g_free(p_chars);
4667         }
4668
4669         g_free(buf);
4670       }
4671
4672     }
4673
4674
4675     break;
4676
4677   default:
4678     g_warning("giop:Invalid v_minor value = %u ", v_minor);
4679     break;
4680   }
4681   
4682 }
4683
4684
4685 /* 
4686  * Service Contexts Begin
4687  *
4688  */
4689
4690
4691
4692
4693
4694 void dissect_SID_BI_DIR_IIOP(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
4695                                MessageHeader *header, gchar *operation, guint32 boundary) {
4696
4697   return;
4698
4699 };
4700
4701
4702
4703
4704 /*
4705  * Service Contexts End
4706  *
4707  */
4708
4709
4710
4711
4712 /*
4713  * Corba , chp 13.7
4714  *
4715  *
4716  *
4717  *      typedef unsigned long ServiceID;
4718  *
4719  *      struct ServiceContext {
4720  *              ServiceID context_id;
4721  *              sequence <octet> context_data;
4722  *      };
4723  *      typedef sequence <ServiceContext> ServiceContextList;
4724  *
4725  *
4726  * Note: Spec says context_data is an encapsulation.
4727  *
4728  *
4729  */
4730
4731
4732
4733 void decode_ServiceContextList(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ptree, int *offset,
4734                                gboolean stream_is_be, guint32 boundary) {
4735
4736   guint32 seqlen;               /* sequence length  */
4737   guint32 seqlen_cd;            /* sequence length, context_data  */
4738
4739   proto_tree *tree = NULL;      /* ServiceContext tree */
4740   proto_item *tf;
4741
4742   guint32 context_id;
4743   gchar *context_data;
4744   gchar *p_context_data;
4745
4746   guint32 i;
4747   guint32 vscid;                /* Vendor Service context id */
4748   guint32 scid;
4749
4750   /* create a subtree */
4751
4752   if (ptree) {
4753     tf = proto_tree_add_text (ptree, tvb, *offset, tvb_length (tvb), "ServiceContextList");
4754     tree = proto_item_add_subtree (tf, ett_giop_scl);
4755   }
4756
4757   /* Get sequence length (number of elements) */
4758   
4759   seqlen = get_CDR_ulong(tvb,offset,stream_is_be,boundary);
4760   if (tree) {
4761     proto_tree_add_uint(tree,hf_giop_sequence_length,tvb,
4762                         *offset-sizeof(seqlen),4,seqlen);
4763   }
4764
4765   /* return if zero length sequence */
4766
4767   if(seqlen == 0)
4768     return;
4769      
4770   /* Loop for all ServiceContext's */
4771
4772   for (i=0; i<seqlen; i++) {
4773
4774     context_id = get_CDR_ulong(tvb,offset,stream_is_be,boundary);
4775     if (tree) {
4776       proto_tree_add_uint(tree,hf_giop_iop_vscid,tvb,
4777                           *offset-sizeof(context_id),4,context_id);
4778
4779       proto_tree_add_uint(tree,hf_giop_iop_scid,tvb,
4780                           *offset-sizeof(context_id),4,context_id);
4781
4782     }
4783  
4784     vscid = context_id && 0xfffff000; /* vendor info, top 20 bits */
4785     scid = context_id  && 0x00000fff; /* standard service info, lower 12 bits */
4786
4787
4788 #if CONTEXT_DATA_IS_ENCAPSULATED
4789
4790     /* get sequence length, new endianness and boundary for encapsulation */
4791   
4792     seqlen_cd = get_CDR_encap_info(tvb, tree, offset, 
4793                                stream_is_be, boundary,
4794                                &new_big_endianess, &new_boundary);
4795
4796
4797 #else
4798    /* get sequence length, and NO  encapsulation */
4799
4800     seqlen_cd = get_CDR_ulong(tvb, offset, stream_is_be,boundary);
4801
4802 #endif
4803
4804     /* return if zero length sequence */
4805
4806     if(seqlen_cd == 0)
4807       return;
4808     
4809     /*
4810      * Now decode sequence according to vendor ServiceId, but I dont
4811      * have that yet, so just dump it as data.
4812      */    
4813
4814     /* fetch all octets in this sequence */
4815   
4816     get_CDR_octet_seq(tvb, &context_data, offset, seqlen_cd);
4817
4818     /* Make a printable string */
4819   
4820     p_context_data = make_printable_string( context_data, seqlen_cd );
4821   
4822     if(tree) {
4823       proto_tree_add_text (tree, tvb, *offset - seqlen_cd , seqlen_cd,
4824                            "context_data: %s", p_context_data);
4825     }
4826
4827     g_free(context_data);
4828     g_free(p_context_data);
4829
4830   } /* seqlen  */
4831
4832
4833   return;                       /* for now, fix later */
4834     
4835
4836 }
4837
4838 /* Decode SystemExceptionReplyBody as defined in the CORBA spec chapter 15.
4839  */
4840
4841 static void decode_SystemExceptionReplyBody (tvbuff_t *tvb, proto_tree *tree, gint *offset,
4842                                              gboolean stream_is_big_endian,
4843                                              guint32 boundary) {
4844
4845   guint32 length;            /* string length */
4846   guint32 minor_code_value;
4847   guint32 completion_status;
4848
4849   gchar *buf;                /* pointer to string buffer */ 
4850
4851   length = get_CDR_string(tvb, &buf, offset, stream_is_big_endian, boundary);
4852
4853   if (tree) {
4854     proto_tree_add_text(tree, tvb, *offset-4, 4,
4855                         "Exception length: %u", length);
4856     if (length > 0) {
4857       proto_tree_add_text(tree, tvb, *offset - length, length,
4858                           "Exception id: %s", buf );
4859     }
4860   }
4861   g_free(buf);
4862
4863   minor_code_value = get_CDR_ulong(tvb, offset, stream_is_big_endian, boundary);
4864   completion_status = get_CDR_ulong(tvb, offset, stream_is_big_endian, boundary);
4865         
4866   if (tree) {
4867     proto_tree_add_text(tree, tvb, *offset-8, 4,
4868                         "Minor code value: %u", minor_code_value);
4869     proto_tree_add_text(tree, tvb, *offset-4, 4,
4870                         "Completion Status: %u", completion_status);
4871   }
4872 }
4873
4874
4875 /*
4876  * Helper functions for dissecting TypeCodes 
4877  *
4878  * These functions decode the complex parameter lists
4879  * of TypeCodes as defined in the CORBA spec chapter 15.
4880  */
4881
4882 static void dissect_tk_objref_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
4883                                      gboolean stream_is_big_endian, guint32 boundary,
4884                                      MessageHeader * header) {
4885
4886   guint32  new_boundary;             /* new boundary for encapsulation */
4887   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
4888
4889   guint32 seqlen;   /* sequence length */
4890
4891   /* get sequence length, new endianness and boundary for encapsulation */
4892   seqlen = get_CDR_encap_info(tvb, tree, offset, 
4893                                    stream_is_big_endian, boundary,
4894                                    &new_stream_is_big_endian, &new_boundary);
4895
4896   /* get repository ID */
4897   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4898                                 hf_giop_repoid);
4899
4900   /* get name */
4901   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4902                                 hf_giop_typecode_name);
4903
4904 }
4905
4906
4907 static void dissect_tk_struct_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
4908                                      gboolean stream_is_big_endian, guint32 boundary,
4909                                      MessageHeader * header ) {
4910
4911   guint32  new_boundary;             /* new boundary for encapsulation */
4912   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
4913
4914   guint32 count;    /* parameter count (of tuples)  */
4915   guint32 seqlen;   /* sequence length */
4916   guint32 i;        /* loop index */
4917
4918   /* get sequence lengt,h new endianness and boundary for encapsulation */
4919   seqlen = get_CDR_encap_info(tvb, tree, offset, 
4920                                    stream_is_big_endian, boundary,
4921                                    &new_stream_is_big_endian, &new_boundary);
4922
4923   /* get repository ID */
4924   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4925                                 hf_giop_repoid);
4926
4927   /* get name */
4928   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4929                                 hf_giop_typecode_name);
4930
4931   /* get count of tuples */
4932   count = get_CDR_ulong(tvb,offset,new_stream_is_big_endian,new_boundary);
4933   if (tree) {
4934     proto_tree_add_uint(tree,hf_giop_typecode_count,tvb,
4935                         *offset-sizeof(count),4,count);
4936   }
4937
4938   /* get all tuples */
4939   for (i=0; i< count; i++) {
4940     /* get member name */
4941     dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4942                                   hf_giop_typecode_member_name);
4943
4944     /* get member type */
4945     get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
4946   }
4947
4948 }
4949
4950
4951 static void dissect_tk_union_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
4952                                     gboolean stream_is_big_endian, guint32 boundary,
4953                                     MessageHeader * header) {
4954
4955   guint32  new_boundary;             /* new boundary for encapsulation */
4956   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
4957
4958   guint32  TCKind;    /* TypeCode */
4959   gint32   s_octet4;  /* signed int32 */
4960
4961   guint32 count;    /* parameter count (of tuples)  */
4962   guint32 seqlen;   /* sequence length */
4963   guint32 i;        /* loop index */
4964
4965   /* get sequence legnth, new endianness and boundary for encapsulation */
4966   seqlen = get_CDR_encap_info(tvb, tree, offset, 
4967                                    stream_is_big_endian, boundary,
4968                                    &new_stream_is_big_endian, &new_boundary);
4969
4970   /* get repository ID */
4971   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4972                                 hf_giop_repoid);
4973
4974   /* get name */
4975   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
4976                                 hf_giop_typecode_name);
4977
4978   /* get discriminant type */
4979   TCKind = get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
4980
4981   /* get default used */
4982   s_octet4 = get_CDR_long(tvb,offset,new_stream_is_big_endian,new_boundary);
4983   if (tree) {
4984     proto_tree_add_int(tree,hf_giop_typecode_default_used,tvb,
4985                         *offset-sizeof(s_octet4),4,s_octet4);
4986   }
4987   /* get count of tuples */
4988   count = get_CDR_ulong(tvb,offset,new_stream_is_big_endian,new_boundary);
4989   if (tree) {
4990     proto_tree_add_uint(tree,hf_giop_typecode_count,tvb,
4991                         *offset-sizeof(count),4,count);
4992   }
4993
4994   /* get all tuples */
4995   for (i=0; i< count; i++) {
4996     /* get label value, based on TCKind above  */
4997     dissect_data_for_typecode(tvb, tree, offset, new_stream_is_big_endian, new_boundary, header, TCKind );
4998
4999     /* get member name */
5000     dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5001                                   hf_giop_typecode_member_name);
5002
5003     /* get member type */
5004     get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5005   }
5006
5007 }
5008
5009
5010 static void dissect_tk_enum_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5011                                    gboolean stream_is_big_endian, guint32 boundary,
5012                                    MessageHeader * header) {
5013
5014   guint32  new_boundary;             /* new boundary for encapsulation */
5015   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5016
5017   guint32 count;    /* parameter count (of tuples)  */
5018   guint32 seqlen;   /* sequence length */
5019   guint32 i;        /* loop index */
5020
5021   /* get sequence length, new endianness and boundary for encapsulation */
5022   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5023                                    stream_is_big_endian, boundary,
5024                                    &new_stream_is_big_endian, &new_boundary);
5025
5026   /* get repository ID */
5027   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5028                                 hf_giop_repoid);
5029
5030   /* get name */
5031   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5032                                 hf_giop_typecode_name);
5033
5034   /* get count of tuples */
5035   count = get_CDR_ulong(tvb,offset,new_stream_is_big_endian,new_boundary);
5036   if (tree) {
5037     proto_tree_add_uint(tree,hf_giop_typecode_count,tvb,
5038                         *offset-sizeof(count),4,count);
5039   }
5040
5041   /* get all tuples */
5042   for (i=0; i< count; i++) {
5043     /* get member name */
5044     dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5045                                   hf_giop_typecode_member_name);
5046   }
5047
5048 }
5049
5050
5051 static void dissect_tk_sequence_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5052                                        gboolean stream_is_big_endian, guint32 boundary,
5053                                        MessageHeader * header) {
5054
5055   guint32  new_boundary;             /* new boundary for encapsulation */
5056   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5057
5058   guint32 u_octet4; /* unsigned int32 */
5059
5060   guint32 seqlen;   /* sequence length */
5061
5062   /* get sequence length, new endianness and boundary for encapsulation */
5063   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5064                                    stream_is_big_endian, boundary,
5065                                    &new_stream_is_big_endian, &new_boundary);
5066
5067   /* get element type */
5068   get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5069
5070   /* get max length */
5071   u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
5072   if (tree) {
5073     proto_tree_add_uint(tree,hf_giop_typecode_max_length,tvb,
5074                         *offset-sizeof(u_octet4),4,u_octet4);
5075   }
5076 }
5077
5078
5079 static void dissect_tk_array_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5080                                     gboolean stream_is_big_endian, guint32 boundary,
5081                                     MessageHeader * header) {
5082
5083   guint32  new_boundary;             /* new boundary for encapsulation */
5084   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5085
5086   guint32 u_octet4; /* unsigned int32 */
5087
5088   guint32 seqlen;   /* sequence length */
5089
5090   /* get sequence length, new endianness and boundary for encapsulation */
5091   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5092                                    stream_is_big_endian, boundary,
5093                                    &new_stream_is_big_endian, &new_boundary);
5094
5095   /* get element type */
5096   get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5097
5098   /* get length */
5099   u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
5100   if (tree) {
5101     proto_tree_add_uint(tree,hf_giop_typecode_length,tvb,
5102                         *offset-sizeof(u_octet4),4,u_octet4);
5103   }
5104 }
5105
5106
5107 static void dissect_tk_alias_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5108                                     gboolean stream_is_big_endian, guint32 boundary,
5109                                     MessageHeader * header) {
5110
5111   guint32  new_boundary;             /* new boundary for encapsulation */
5112   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5113
5114   guint32 seqlen;   /* sequence length */
5115
5116   /* get sequence legnth, new endianness and boundary for encapsulation */
5117   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5118                                    stream_is_big_endian, boundary,
5119                                    &new_stream_is_big_endian, &new_boundary);
5120
5121   /* get repository ID */
5122   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5123                                 hf_giop_repoid);
5124
5125   /* get name */
5126   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5127                                 hf_giop_typecode_name);
5128
5129   /* get ??? (noname) TypeCode */
5130   get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5131
5132 }
5133
5134
5135 static void dissect_tk_except_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5136                                      gboolean stream_is_big_endian, guint32 boundary,
5137                                      MessageHeader * header) {
5138
5139   guint32  new_boundary;             /* new boundary for encapsulation */
5140   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5141
5142   guint32 count;    /* parameter count (of tuples)  */
5143   guint32 seqlen;   /* sequence length */
5144   guint32 i;        /* loop index */
5145
5146   /* get sequence length, new endianness and boundary for encapsulation */
5147   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5148                                    stream_is_big_endian, boundary,
5149                                    &new_stream_is_big_endian, &new_boundary);
5150
5151   /* get repository ID */
5152   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5153                                 hf_giop_repoid);
5154
5155   /* get name */
5156   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5157                                 hf_giop_typecode_name);
5158
5159   /* get count of tuples */
5160   count = get_CDR_ulong(tvb,offset,new_stream_is_big_endian,new_boundary);
5161   if (tree) {
5162     proto_tree_add_uint(tree,hf_giop_typecode_count,tvb,
5163                         *offset-sizeof(count),4,count);
5164   }
5165
5166   /* get all tuples */
5167   for (i=0; i< count; i++) {
5168     /* get member name */
5169     dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5170                                   hf_giop_typecode_member_name);
5171
5172     /* get member type */
5173     get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5174   }
5175
5176 }
5177
5178
5179 static void dissect_tk_value_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5180                                     gboolean stream_is_big_endian, guint32 boundary,
5181                                     MessageHeader * header) {
5182
5183   guint32  new_boundary;             /* new boundary for encapsulation */
5184   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5185
5186   gint16  s_octet2; /* signed int16 */
5187
5188   guint32 count;    /* parameter count (of tuples)  */
5189   guint32 seqlen;   /* sequence length */
5190   guint32 i;        /* loop index */
5191
5192   /* get sequence length, new endianness and boundary for encapsulation */
5193   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5194                                    stream_is_big_endian, boundary,
5195                                    &new_stream_is_big_endian, &new_boundary);
5196
5197   /* get repository ID */
5198   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5199                                 hf_giop_repoid);
5200
5201   /* get name */
5202   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5203                                 hf_giop_typecode_name);
5204
5205   /* get ValueModifier */
5206   s_octet2 = get_CDR_short(tvb,offset,stream_is_big_endian,boundary);
5207   if (tree) {
5208     proto_tree_add_int(tree,hf_giop_typecode_ValueModifier,tvb,
5209                        *offset-sizeof(s_octet2),2,s_octet2);
5210   }
5211
5212   /* get conrete base */
5213   get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5214
5215   /* get count of tuples */
5216   count = get_CDR_ulong(tvb,offset,new_stream_is_big_endian,new_boundary);
5217   if (tree) {
5218     proto_tree_add_uint(tree,hf_giop_typecode_count,tvb,
5219                         *offset-sizeof(count),4,count);
5220   }
5221
5222   /* get all tuples */
5223   for (i=0; i< count; i++) {
5224     /* get member name */
5225     dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5226                                   hf_giop_typecode_member_name);
5227
5228     /* get member type */
5229     get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5230
5231     /* get Visibility */
5232     s_octet2 = get_CDR_short(tvb,offset,stream_is_big_endian,boundary);
5233     if (tree) {
5234       proto_tree_add_int(tree,hf_giop_typecode_Visibility,tvb,
5235                           *offset-sizeof(s_octet2),2,s_octet2);
5236     }
5237   }
5238
5239 }
5240
5241
5242 static void dissect_tk_value_box_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5243                                         gboolean stream_is_big_endian, guint32 boundary,
5244                                         MessageHeader * header) {
5245
5246   guint32  new_boundary;             /* new boundary for encapsulation */
5247   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5248
5249   guint32 seqlen;   /* sequence length */
5250
5251   /* get sequence length, new endianness and boundary for encapsulation */
5252   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5253                                    stream_is_big_endian, boundary,
5254                                    &new_stream_is_big_endian, &new_boundary);
5255
5256   /* get repository ID */
5257   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5258                                 hf_giop_repoid);
5259
5260   /* get name */
5261   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5262                                 hf_giop_typecode_name);
5263
5264   /* get ??? (noname) TypeCode */
5265   get_CDR_typeCode(tvb,tree,offset,new_stream_is_big_endian,new_boundary,header);
5266 }
5267
5268
5269 static void dissect_tk_native_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5270                                      gboolean stream_is_big_endian, guint32 boundary,
5271                                      MessageHeader * header) {
5272
5273   guint32  new_boundary;             /* new boundary for encapsulation */
5274   gboolean new_stream_is_big_endian; /* new endianness for encapsulation */
5275
5276   guint32 seqlen;   /* sequence length */
5277
5278   /* get sequence length, new endianness and boundary for encapsulation */
5279   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5280                                    stream_is_big_endian, boundary,
5281                                    &new_stream_is_big_endian, &new_boundary);
5282
5283   /* get repository ID */
5284   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5285                                 hf_giop_repoid);
5286
5287   /* get name */
5288   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5289                                 hf_giop_typecode_name);
5290
5291 }
5292
5293
5294 static void dissect_tk_abstract_interface_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5295                                                  gboolean stream_is_big_endian, guint32 boundary,
5296                                                  MessageHeader * header) {
5297
5298   guint32  new_boundary;              /* new boundary for encapsulation */
5299   gboolean new_stream_is_big_endian;  /* new endianness for encapsulation */
5300
5301   guint32 seqlen;   /* sequence length */
5302
5303   /* get sequence length, new endianness and boundary for encapsulation */
5304   seqlen = get_CDR_encap_info(tvb, tree, offset, 
5305                                    stream_is_big_endian, boundary,
5306                                    &new_stream_is_big_endian, &new_boundary);
5307
5308   /* get repository ID */
5309   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5310                                 hf_giop_repoid);
5311
5312   /* get name */
5313   dissect_typecode_string_param(tvb, tree, offset, new_stream_is_big_endian, new_boundary,
5314                                 hf_giop_typecode_name);
5315
5316 }
5317
5318 /* Typecode parameter lists are encoded as encapsulations and
5319  * this function gets the encapsulation information; see
5320  * CORBA spec chapter 15 
5321  *
5322  *
5323  * Renamed to get_CDR_encap_info() for any encapsulation 
5324  * we come across, useful helper function 
5325  *
5326  * Also, should return immediately if seqlen == 0.
5327  * ie: Forget about trying to grab endianess for
5328  *     zero length sequence.
5329  *
5330  * Caller must always check seqlen == 0, and not assume its value
5331  *
5332  *
5333  * Note: there seemed to be considerable confusion in corba
5334  * circles as to the correct interpretation of encapsulations,
5335  * and zero length sequences etc, but this is our best bet at the 
5336  * moment.
5337  *
5338  * -- FS
5339  *
5340  */
5341
5342 guint32 get_CDR_encap_info(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5343                        gboolean old_stream_is_big_endian, guint32 old_boundary,
5344                        gboolean *new_stream_is_big_endian_ptr, guint32 *new_boundary_ptr ) {
5345  
5346   guint32 seqlen;   /* sequence length */
5347   guint8  giop_endianess;
5348
5349   /* Get sequence length of parameter list */
5350   seqlen = get_CDR_ulong(tvb,offset,old_stream_is_big_endian,old_boundary);
5351   if (tree) {
5352     proto_tree_add_uint(tree,hf_giop_sequence_length,tvb,
5353                         *offset-sizeof(seqlen),4,seqlen);
5354   }
5355
5356   
5357
5358   /*
5359    * seqlen == 0, implies no endianess and no data
5360    * so just return. Populate new_boundary_ptr and
5361    * new_stream_is_big_endian_ptr with current (old)
5362    * values, just to keep everyone happy. -- FS
5363    *
5364    */
5365
5366   if (seqlen == 0) {
5367
5368     *new_boundary_ptr = old_boundary;
5369     *new_stream_is_big_endian_ptr = old_stream_is_big_endian;
5370
5371     return seqlen;
5372
5373   }
5374
5375   /*  Start of encapsulation of parameter list */
5376   *new_boundary_ptr = *offset;  /* remember  */
5377   giop_endianess =  get_CDR_octet(tvb,offset);
5378
5379   *new_stream_is_big_endian_ptr = ! giop_endianess;
5380
5381   /*
5382    * Glib: typedef gint   gboolean;
5383    * ie: It is not a guint8, so cannot use sizeof to correctly
5384    * highlight octet.
5385    */
5386
5387
5388   if (tree) {
5389     proto_tree_add_uint(tree,hf_giop_endianess,tvb,
5390                         *offset-1,1,giop_endianess);
5391   }
5392
5393
5394   return seqlen;
5395
5396
5397 }
5398
5399 /* 
5400  * gets a TypeCode complex string parameter and
5401  * displays it in the relevant tree.
5402  */
5403
5404 static void dissect_typecode_string_param(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5405                                           gboolean new_stream_is_big_endian, guint32 new_boundary, int hf_id ) {
5406
5407   guint32 u_octet4;  /* unsigned int32 */
5408   gchar *buf;        /* ptr to string buffer */
5409
5410   /* get string */
5411   u_octet4 = get_CDR_string(tvb,&buf,offset,new_stream_is_big_endian,new_boundary);
5412    
5413   if (tree) {    
5414     proto_tree_add_uint(tree,hf_giop_string_length,tvb,
5415                         *offset-u_octet4-sizeof(u_octet4),4,u_octet4);
5416     if (u_octet4 > 0) {
5417       proto_tree_add_string(tree,hf_id,tvb,*offset-u_octet4,u_octet4,buf);
5418     }
5419   }
5420   
5421   g_free(buf);          /* dont forget */
5422
5423 }
5424
5425 /*
5426  * For a given data type, given by a TypeCode gets the associated data
5427  * and displays it in the relevant tree.
5428  */
5429
5430 static void dissect_data_for_typecode(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
5431                                       gboolean stream_is_big_endian, guint32 boundary,
5432                                       MessageHeader * header, guint32 data_type ) {
5433
5434   gboolean my_boolean; /* boolean */
5435
5436   gint8  s_octet1;   /* signed int8 */
5437   guint8 u_octet1;   /* unsigned int8 */
5438
5439   gint16  s_octet2;  /* signed int16 */
5440   guint16 u_octet2;  /* unsigned int16 */
5441
5442   gint32  s_octet4;  /* signed int32 */
5443   guint32 u_octet4;  /* unsigned int32 */
5444
5445   gdouble my_double; /* double */
5446   gfloat  my_float;  /* float */
5447
5448   gchar *buf = NULL;            /* ptr to string buffer */
5449
5450   /* Grab the data according to data type */
5451
5452   switch (data_type) {
5453   case tk_null:
5454     /* nothing to decode */
5455     break;
5456   case tk_void:
5457     /* nothing to decode */
5458     break;
5459   case tk_short:
5460     s_octet2 = get_CDR_short(tvb,offset,stream_is_big_endian,boundary);
5461     if (tree) {
5462       proto_tree_add_int(tree,hf_giop_type_short,tvb,
5463                          *offset-sizeof(s_octet2),2,s_octet2);
5464     }
5465     break;
5466   case tk_long:
5467     s_octet4 = get_CDR_long(tvb,offset,stream_is_big_endian,boundary);
5468     if (tree) {
5469       proto_tree_add_int(tree,hf_giop_type_long,tvb,
5470                          *offset-sizeof(s_octet4),4,s_octet4);
5471     }
5472     break;
5473   case tk_ushort:
5474     u_octet2 = get_CDR_ushort(tvb,offset,stream_is_big_endian,boundary);
5475     if (tree) {
5476       proto_tree_add_uint(tree,hf_giop_type_ushort,tvb,
5477                           *offset-sizeof(u_octet2),2,u_octet2);
5478     }
5479     break;
5480   case tk_ulong:
5481     u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
5482     if (tree) {
5483       proto_tree_add_uint(tree,hf_giop_type_ulong,tvb,
5484                          *offset-sizeof(u_octet4),4,u_octet4);
5485     }
5486     break;
5487   case tk_float:
5488     my_float = get_CDR_float(tvb,offset,stream_is_big_endian,boundary);
5489     if (tree) {
5490       proto_tree_add_double(tree,hf_giop_type_float,tvb,
5491                             *offset-sizeof(my_float),4,my_float);
5492     }
5493     break;
5494   case tk_double:
5495     my_double = get_CDR_double(tvb,offset,stream_is_big_endian,boundary);
5496     if (tree) {
5497       proto_tree_add_double(tree,hf_giop_type_double,tvb,
5498                             *offset-sizeof(my_double),8,my_double);
5499     }
5500     break;
5501   case tk_boolean:
5502     my_boolean = get_CDR_boolean(tvb,offset);
5503     if (tree) {
5504       proto_tree_add_boolean(tree,hf_giop_type_boolean,tvb,
5505                              *offset-1,1,my_boolean);
5506     }
5507     break;
5508   case tk_char:
5509     u_octet1 = get_CDR_char(tvb,offset);
5510     if (tree) {
5511       proto_tree_add_uint(tree,hf_giop_type_char,tvb,
5512                           *offset-sizeof(u_octet1),1,u_octet1);
5513     }
5514     break;
5515   case tk_octet:
5516     u_octet1 = get_CDR_octet(tvb,offset);
5517     if (tree) {
5518       proto_tree_add_uint(tree,hf_giop_type_octet,tvb,
5519                           *offset-sizeof(u_octet1),1,u_octet1);
5520     }
5521     break;
5522   case tk_any:
5523     get_CDR_any(tvb,tree,offset,stream_is_big_endian,boundary,header);
5524     break;
5525   case tk_TypeCode:
5526     get_CDR_typeCode(tvb,tree,offset,stream_is_big_endian,boundary,header);
5527     break;
5528   case tk_Principal:
5529     break;
5530   case tk_objref:
5531     break;
5532   case tk_struct:
5533     break;
5534   case tk_union:
5535     break;
5536   case tk_enum:
5537     u_octet4 = get_CDR_enum(tvb,offset,stream_is_big_endian,boundary);
5538     if (tree) {
5539       proto_tree_add_uint(tree,hf_giop_type_enum,tvb,
5540                           *offset-sizeof(u_octet4),4,u_octet4);
5541     }
5542     break;
5543   case tk_string:
5544     u_octet4 = get_CDR_string(tvb,&buf,offset,stream_is_big_endian,boundary);
5545     if (tree) {
5546       proto_tree_add_uint(tree,hf_giop_string_length,tvb,
5547                           *offset-u_octet4-sizeof(u_octet4),4,u_octet4);
5548       if (u_octet4 > 0) {
5549         proto_tree_add_string(tree,hf_giop_type_string,tvb,
5550                               *offset-u_octet4,u_octet4,buf);
5551       }
5552     }
5553     
5554     g_free(buf);                /* dont forget */
5555     break;
5556   case tk_sequence:
5557     break;
5558   case tk_array:
5559     break;
5560   case tk_alias:
5561     break;
5562   case tk_except:
5563     break;
5564   case tk_longlong:
5565     break;
5566   case tk_ulonglong:
5567     break;
5568   case tk_longdouble:
5569     break;
5570   case tk_wchar:
5571     s_octet1 = get_CDR_wchar(tvb,&buf,offset,header);
5572     if (tree) {
5573       /*
5574        * XXX - can any of these throw an exception?
5575        * If so, we need to catch the exception and free "buf".
5576        */
5577       if (s_octet1 < 0) { /* no size to add to tree */
5578         proto_tree_add_string(tree,hf_giop_type_string,tvb,
5579                               *offset+s_octet1,(-s_octet1),buf);
5580       } else {
5581         proto_tree_add_uint(tree,hf_giop_string_length,tvb,
5582                             *offset-s_octet1-sizeof(s_octet1),1,s_octet1);
5583         proto_tree_add_string(tree,hf_giop_type_string,tvb,
5584                               *offset-s_octet1,s_octet1,buf);
5585       }
5586     }
5587
5588     g_free(buf);              /* dont forget */
5589     break;
5590   case tk_wstring:
5591     u_octet4 = get_CDR_wstring(tvb,&buf,offset,stream_is_big_endian,boundary,header);
5592     if (tree) {
5593       /*
5594        * XXX - can any of these throw an exception?
5595        * If so, we need to catch the exception and free "buf".
5596        */
5597        proto_tree_add_uint(tree,hf_giop_string_length,tvb,
5598                            *offset-u_octet4-sizeof(u_octet4),4,u_octet4);
5599        proto_tree_add_string(tree,hf_giop_type_string,tvb,
5600                              *offset-u_octet4,u_octet4,buf);
5601      }
5602
5603     g_free(buf);              /* dont forget */
5604     break;
5605   case tk_fixed:
5606     break;
5607   case tk_value:
5608     break;
5609   case tk_value_box:
5610     break;
5611   case tk_native:
5612     break;
5613   case tk_abstract_interface:
5614     break;
5615   default:
5616     g_warning("giop: Unknown typecode data type %u \n", data_type);
5617   break;
5618   } /* data_type */
5619
5620 }