Patch from Bernd Becker: "header->exception_id" has to be set regardless
[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.46 2001/08/20 09:10:27 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
36 /*
37  * TODO: -- FS
38  * 1. heuristic giop dissector table [started]
39  * 2. GUI options, see 20
40  * 3. Remove unneccessary reply_status in heuristic dissector calls (now 
41  *    part of MessageHeader) [done]
42  * 4. get_CDR_xxx should be passed an alignment offset value
43  *    rather than GIOP_HEADER_SIZE, as alignment can also change in a
44  *    octet stream when eg: encapsulation is used [done]
45  * 5. GIOP users should eventually get there own tvbuff, and
46  *    not rely on the GIOP tvbuff, more robust
47  * 6. get_CDR_string,wchar,wstring etc should handle different 
48  *    GIOP versions [started]
49  * 7. Fix situation where req_id is not unique in a logfile [done, use FN/MFN, needs improving.]
50  *
51  * 8. Keep request_1_2 in step with request_1_1 [started]
52  * 9. Explicit module name dissection [done]
53  * 10. Decode IOR and put in a useful struct [IOR decode started]
54  * 11. Fix encapsulation of IOR etc and boundary [done]
55  * 12. handle get_CDR_typeCode() [started]
56  * 13. Handle different IOR profiles
57  * 14. Change printable_string to RETURN a new string, not to modify the old.
58  *     or, new function, make_printable_string [done, make_printable_string]
59  *
60  * 15. Handle "TCKind", and forget about eg: enum translation to symbolic values
61  *     otherwise need knowledge of sub dissectors data - YUK [done]
62  * 16. Handle multiple RepoId representations, besides IDL:Echo:1.0 (see 13.)
63  * 17. Pass subset of RepoID to explicit dissector.
64  *     eg : If IDL:Mod1/Mod2/Int3:1.0 then pass "Mod1/Mode2/Int3" to sub dissector[done]
65  * 18. Better hashing algorithms
66  * 19. Handle hash collision properly .
67  * 20. Allow users to paste a stringified IOR into the GUI, and tie it
68  *     to a sub_dissector.
69  * 21. Add complete_request_packet_list and complete_reply_packet_hash.[done]
70  * 22. Handle case where users click in any order, AND try and match
71  *     REPLY msg to the correct REQUEST msg when we have a request_id collision.[done]
72  * 23. Clean up memory management for all those g_malloc's etc
73  * 24. register_giop_user_module could return a key for every distinct Module/Interface
74  *     the sub_dissector uses. So, instead of strcmp()'s when  handling the
75  *     namespace of an operation, we could have a lookup table instead.
76  * 25. A few typedefs in the right place.
77  * 26  Improve handling of gchar *  and use const gchar * where possible.
78  * 27. Read/write IOR etc to/from file, allows objkey hash to be built from
79  *     external data [read done, write incomplete]
80  * 28. Call sub dissector only if tvb_offset_exists(). [Done, this is checked
81  *     inside try_explicit_giop_dissector() ]
82  *     
83  * 29. Make add/delete routine for objkey hash as it may be useful when say reading 
84  *     stringified IOR's from a file to add them to our hash. ie: There are other ways
85  *     to populate our object key hash besides REPLY's to RESOLVE(request) [done]
86  *
87  * 30. Add routine to encode/decode stringified IOR's [decode done]
88  * 31. Add routine to read IOR's from file [done]
89  * 32. TypeCode -none-, needs decoding.
90  * 33. Complete dissect_data_for_typecode.
91  * 34. For complex TypeCodes need to check final offset against original offset + sequence length.
92  * 35. Update REQUEST/REPLY 1_2 according to IDL (eg; ServiceContextList etc).
93  * 36. Adding decode_ServiceContextList, incomplete. 
94  * 37. Helper functions should not ALWAYS rely on header to find  current endianess. It should
95  *     be passed from user, eg Use   stream_is_big_endian. [started]
96  * 38. Remove unwanted/unused function parameters, see decode_IOR [started]
97  * 40. Add sequence <IOP::TaggedComponent> components to IIOP IOR profile. Perhaps 
98  *     decode_IOP_TaggedComponents as a helper function. [done - NOT helper]
99  *
100  * 41. Make important field searchable from Message header. ie: Remove add_text_
101  * 42. Use sub-tree for decode_ServiceContextList, looks better.
102  * 43. dissect_reply_body, no exception dissector calls
103  *       - call subdiss directly, as we already have handle.
104  *       - add repoid to heuristic call also.
105  *
106  * 44. typedef using xxx_t in .h file.
107  * 45. Subdissectors should not be passed MessageHeader to find endianness and
108  *     version, they should be passed directly ?
109  * 46. get_CDR_wchar and wstring need wide chars decoded (just dumped in
110  *     any readable form at present, not handled well at all, suggestions welcome -- FS
111  * 47. Change ...add_text to ...add_xxx (ie use hf fields).
112  *
113  * 48. BUG - file load with a GIOP filter set, causes the FN/MFN data struct to be
114  *     not initiated properly. Hit "Reload" as a workaround, til I fix this -- FS
115  *
116  */
117
118
119
120 /*
121  * Intended Decode strategy:
122  * =========================
123  *
124  * Initial Pass
125  * ------------
126  * REQUEST: objkey -> Repo_ID -> Module/Interface -> giop_sub_handle_t
127  *          and populate complete_request_packet_hash
128  *
129  * REPLY:   FN -> MFN (via complete_reply_packet_hash) = Request FN -> giop_sub_handle_t
130  *
131  * User Clicks
132  * -----------
133  *
134  * REQUEST: FN -> giop_sub_handle_t directly (via complete_request_packet_hash)
135  *
136  * REPLY:   FN -> MFN (via complete_reply_packet_hash) = Request FN -> giop_sub_handle_t
137  *                                                                     (via complete_request_packet_hash
138  *
139  *
140  * Limitations. 
141  * ============
142  *
143  * 1. Request_ID's are unique only per connection.
144  *
145  * 2. You must be monitoring the network when the client does
146  *    a REQUEST(resolve), otherwise I have no knowledge of the
147  *    association between object_key and REPOID. I could talk to 
148  *    a Nameserver, but then I would start "generating" packets.
149  *    This is probably not a good thing for a protocol analyser.
150  *    Also, how could I decode logfiles offline.
151  *
152  *    TODO -- Read stringified IORs from an input file.[done]
153  *
154  * 3. User clicks (REQUEST) is currently handle the same as
155  *    the initial pass handling.
156  *
157  *    ie: objkey -> Repo_ID -> Module/Interface -> giop_sub_handle_t
158  */
159
160
161 /*
162  * Important Data Structures:
163  *
164  * giop_module_hash 
165  * ----------------
166  *
167  * This is a hash table that maps IDL Module/Interface Names (Key)
168  * to sub_dissector handles, giop_sub_handle_t. It is populated
169  * by subdissectors, via register_giop_user_module(). This
170  * table is used when we have a REPOID, and explicitly wish to
171  * call the subdissector that has registered responsibility for
172  * that IDL module/interface.
173  *
174  * 
175  * giop_sub_list
176  * -------------
177  *
178  * This singly linked list is used to hold entries for
179  * heuristic based subdissectors. It is populated by sub_dissectors
180  * wishing to be called via heuristic mechanisms. They do this
181  * via the register_giop_user() function.
182  *
183  * 
184  * giop_objkey_hash
185  * ----------------
186  *
187  * This hash table maps object_key's (key) onto REPOID's (val).
188  * Once a client has REQUEST(resolve) an object , it knows about
189  * an object (interface) via its object_key (see IOR). So in order to follow
190  * packets that contain an object_key only, and to be able to forward it
191  * to the correct explicit subdissector, we need this table.
192  *
193  * So, I listen in on REQUEST(resolve) messages between client and
194  * Nameserver, and store the respones (REPLY/Objkey,Repo_ID) here.
195  *
196  * Also, stringified IOR's can be read from a file "IOR.txt" and used
197  * to populate  this hash also.
198  *
199  *
200  * Other Data structures 
201  * =======================
202  *
203  * These structures have  been added to minimise the possibility
204  * of incorrectly interpreted packets when people click all
205  * over the place, in no particular order, when the request_id's are
206  * not unique as captured. If all request_is'd are unique, as captured, then
207  * we would not have to deal with this problem.
208  *
209  *
210  * When the logfile or packets are initially being processed, I will
211  * build 2 structures. The intent is to be able to map a REPLY message
212  * back to the most recent REQUEST message with the same Request_ID
213  * (TODO and matching port and IP address ??)
214  * 
215  * Abbrevs:
216  * --------
217  *
218  * FN  - Frame Number
219  * MFN - Matching Frame Number
220  *
221  *
222  * complete_request_packet_list
223  * ----------------------------
224  *
225  * This is a list that contains ALL the FN's that are REQUEST's, along with 
226  * operation,request_id and giop_sub_handle_t
227  *
228  * complete_reply_packet_hash
229  * --------------------------
230  *
231  * This is a hash table. It is populated with FN (key) and MFN (val).
232  * This allows me to handle the case, where if you click on any REPLY
233  * message, I can lookup the matching request. This can improve
234  * the match rate between REQUEST and REPLY when people click in
235  * any old fashion, but is NOT foolproof. 
236  *
237  * The algorithm I use to populate this hash during initial pass,
238  * is as follows. 
239  *
240  * If packet is a REPLY, note the reqid, and then traverse backwards
241  * through the complete_request_packet_list from its tail, looking
242  * for a FN that has the same Request_id. Once found, take the found FN
243  * from complete_reply_packet_hash, and insert it into the MFN field
244  * of the complete_reply_packet_hash.
245  *
246  *
247  * See TODO for improvements to above algorithm.
248  *
249  * So now when people click on a REQUEST packet, I can call lookup the
250  * giop_sub_handle_t directly from complete_request_packet_list.
251  *
252  * And, when they click on a REPLY, I grab the MFN of this FN from
253  * complete_reply_packet_hash, then look that up in the complete_request_packet_list
254  * and call the sub_dissector directly.
255  *
256  * So, how do I differentiate between the initial processing of incoming
257  * packets, and a user clickin on one ? Good question.
258  *
259  * I leverage the pinfo_fd->flags.visited  on a per frame
260  * basis. 
261  *
262  * To quote from the ever helpful development list
263  *
264  * " When a capture file is initially loaded, all "visited" flags
265  * are 0. Ethereal then makes the first pass through file,
266  * sequentially dissecting each packet. After the packet is
267  * dissected the first time, "visited" is 1. (See the end of
268  * dissect_packet() in epan/packet.c; that's the code that
269  * sets "visited" to 1).
270
271  * By the time a user clicks on a packet, "visited" will already
272  * be 1 because Ethereal will have already done its first pass
273  * through the packets.
274
275  * Reload acts just like a normal Close/Open, except that it
276  * doesn't need to ask for a filename. So yes, the reload button
277  * clears the flags and re-dissects the file, just as if the file
278  * had been "opened".  "
279  *
280  */
281
282
283 #ifdef HAVE_CONFIG_H
284 # include "config.h"
285 #endif
286
287 #ifdef HAVE_SYS_TYPES_H
288 # include <sys/types.h>
289 #endif
290
291 #include <string.h>
292 #include <stdio.h>
293 #include <errno.h>
294 #include <ctype.h>
295 #include <glib.h>
296 #include <math.h>
297 #ifdef NEED_STRERROR_H
298 #include "strerror.h"
299 #endif
300
301 #include "packet.h"
302 #include "packet-giop.h"
303
304 /*
305  * This affects how we handle context_data inside ServiceContext structs.
306  * According to CORBA 2.4.2,  Context data is encapsulated in octet sequences,
307  * but so far I haven't seen the that on the wire. But, maybe its me -- FS 
308  *
309  */
310
311 #define CONTEXT_DATA_IS_ENCAPSULATED  0
312
313
314 /*
315  * Set to 1 for DEBUG output - TODO make this a runtime option
316  */
317
318 #define DEBUG   0
319
320
321
322 /*
323  * ------------------------------------------------------------------------------------------+ 
324  *                                 Private Helper function Declarations
325  * ------------------------------------------------------------------------------------------+
326  */
327
328
329 static void decode_IIOP_IOR_profile(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
330                                     guint32 boundary, gboolean new_endianess, gchar *repobuf,
331                                     gboolean store_flag);
332
333 static void decode_ServiceContextList(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
334                                       gboolean stream_is_be, guint32 boundary);
335
336 static void decode_TaggedProfile(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
337                                  guint32 boundary, gboolean stream_is_big_endian, gchar *repobuf);
338
339 static void decode_IOR(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
340                        guint32 boundary, gboolean stream_is_big_endian );
341
342 static void decode_SystemExceptionReplyBody (tvbuff_t *tvb, proto_tree *tree, gint *offset,
343                                              gboolean stream_is_big_endian,
344                                              guint32 boundary);
345
346 static void dissect_tk_objref_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
347                                      gboolean stream_is_big_endian, guint32 boundary,
348                                      MessageHeader * header);
349
350 static void dissect_tk_struct_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
351                                      gboolean stream_is_big_endian, guint32 boundary,
352                                      MessageHeader * header);
353
354 static void dissect_tk_union_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
355                                     gboolean stream_is_big_endian, guint32 boundary,
356                                     MessageHeader * header );
357  
358 static void dissect_tk_enum_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
359                                    gboolean stream_is_big_endian, guint32 boundary,
360                                    MessageHeader * header);
361
362 static void dissect_tk_sequence_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
363                                        gboolean stream_is_big_endian, guint32 boundary,
364                                        MessageHeader * header);
365
366 static void dissect_tk_array_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
367                                     gboolean stream_is_big_endian, guint32 boundary,
368                                     MessageHeader * header);
369
370 static void dissect_tk_alias_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
371                                     gboolean stream_is_big_endian, guint32 boundary,
372                                     MessageHeader * header);
373
374 static void dissect_tk_except_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
375                                      gboolean stream_is_big_endian, guint32 boundary,
376                                      MessageHeader * header);
377
378 static void dissect_tk_value_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
379                                     gboolean stream_is_big_endian, guint32 boundary,
380                                     MessageHeader * header);
381
382 static void dissect_tk_value_box_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
383                                         gboolean stream_is_big_endian, guint32 boundary,
384                                         MessageHeader * header);
385
386 static void dissect_tk_native_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
387                                      gboolean stream_is_big_endian, guint32 boundary,
388                                      MessageHeader * header);
389
390 static void dissect_tk_abstract_interface_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
391                                                  gboolean stream_is_big_endian, guint32 boundary,
392                                                  MessageHeader * header);
393
394
395 static void dissect_typecode_string_param(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
396                                           gboolean new_stream_is_big_endian, guint32 new_boundary, int hf_id );
397
398 static void dissect_data_for_typecode(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
399                                       gboolean stream_is_big_endian, guint32 boundary,
400                                       MessageHeader * header, guint32 data_type );
401
402
403
404
405 /*
406  * ------------------------------------------------------------------------------------------+ 
407  *                                 Data/Variables/Structs
408  * ------------------------------------------------------------------------------------------+
409  */
410
411
412 static int proto_giop = -1;
413 static int hf_giop_message_type = -1;
414 static int hf_giop_message_size = -1;
415 static int hf_giop_repoid = -1;
416 static int hf_giop_string_length = -1;
417 static int hf_giop_sequence_length = -1;
418 static int hf_giop_profile_id = -1;
419 static int hf_giop_type_id = -1;
420 static int hf_giop_iiop_v_maj = -1;
421 static int hf_giop_iiop_v_min = -1;
422 static int hf_giop_endianess = -1; /* esp encapsulations */
423 static int hf_giop_IOR_tag = -1; 
424 static int hf_giop_IIOP_tag = -1;
425
426 static int hf_giop_TCKind = -1;
427 static int hf_giop_typecode_count = -1;
428 static int hf_giop_typecode_default_used = -1;
429 static int hf_giop_typecode_digits = -1;
430 static int hf_giop_typecode_length = -1;
431 static int hf_giop_typecode_max_length = -1;
432 static int hf_giop_typecode_member_name = -1;
433 static int hf_giop_typecode_name = -1;
434 static int hf_giop_typecode_scale = -1;
435 static int hf_giop_typecode_ValueModifier = -1;
436 static int hf_giop_typecode_Visibility = -1;
437
438 static int hf_giop_type_boolean = -1;
439 static int hf_giop_type_char = -1;
440 static int hf_giop_type_double = -1;
441 static int hf_giop_type_enum = -1;
442 static int hf_giop_type_float = -1;
443 static int hf_giop_type_long = -1;
444 static int hf_giop_type_octet = -1;
445 static int hf_giop_type_short = -1;
446 static int hf_giop_type_string = -1;
447 static int hf_giop_type_ulong = -1;
448 static int hf_giop_type_ushort = -1;
449
450 static int hf_giop_iiop_host = -1; 
451 static int hf_giop_iiop_port = -1; 
452 static int hf_giop_iop_vscid = -1;
453 static int hf_giop_iop_scid = -1;
454
455 /*
456  * (sub)Tree declares
457  */
458
459 static gint ett_giop = -1;
460 static gint ett_giop_reply = -1;
461 static gint ett_giop_request = -1;
462 static gint ett_giop_cancel_request = -1;
463 static gint ett_giop_locate_request = -1;
464 static gint ett_giop_locate_reply = -1;
465 static gint ett_giop_fragment = -1;
466
467 static gint ett_giop_scl = -1;  /* ServiceContextList */
468 static gint ett_giop_ior = -1;  /* IOR  */
469
470
471 /* GIOP endianess */
472
473 static const value_string giop_endianess_vals[] = {
474   { 0x0, "Big Endian" },
475   { 0x1, "Little Endian" },
476   { 0, NULL}
477 };
478
479 static const value_string sync_scope[] = {
480         { 0x0, "SYNC_NONE" },
481         { 0x1, "SYNC_WITH_TRANSPORT"},
482         { 0x2, "SYNC_WITH_SERVER"},
483         { 0x3, "SYNC_WITH_TARGET"},
484         { 0, NULL}
485 };
486
487 /* Profile ID's */
488
489 static const value_string profile_id_vals[] = {
490         { 0x0, "TAG_INTERNET_IOP" },
491         { 0x1, "TAG_MULTIPLE_COMPONENTS"},
492         { 0x2, "TAG_SCCP_IOP"},
493         { 0, NULL}
494 };
495
496 static const value_string giop_message_types[] = {
497         { 0x0, "Request" },
498         { 0x1, "Reply"},
499         { 0x2, "CancelRequest"},
500         { 0x3, "LocateRequest"},
501         { 0x4, "LocateReply"},
502         { 0x5, "CloseConnection"},
503         { 0x6, "MessageError"},
504         { 0x7, "Fragment"},
505         { 0, NULL}
506 };
507
508 static const value_string giop_locate_status_types[] = {
509         { 0x0, "Unknown Object" },
510         { 0x1, "Object Here"},
511         { 0x2, "Object Forward"},
512         { 0x3, "Object Forward Perm"},
513         { 0x4, "Loc System Exception"},
514         { 0x5, "Loc Needs Addressing Mode"},
515         { 0, NULL }     
516 };
517
518 static const value_string tckind_vals[] = {
519   { 0, "tk_null"},
520   { 1, "tk_void"},
521   { 2, "tk_short"},
522   { 3, "tk_long"},
523   { 4, "tk_ushort"},
524   { 5, "tk_ulong"},
525   { 6, "tk_float"},
526   { 7, "tk_double"},
527   { 8, "tk_boolean"},
528   { 9, "tk_char"},
529   { 10, "tk_octet"},
530   { 11, "tk_any"},
531   { 12, "tk_TypeCode"},
532   { 13, "tk_Principal"},
533   { 14, "tk_objref"},
534   { 15, "tk_struct"},
535   { 16, "tk_union"},
536   { 17, "tk_enum"},
537   { 18, "tk_string"},
538   { 19, "tk_sequence"},
539   { 20, "tk_array"},
540   { 21, "tk_alias"},
541   { 22, "tk_except"},
542   { 23, "tk_longlong"},
543   { 24, "tk_ulonglong"},
544   { 25, "tk_longdouble"},
545   { 26, "tk_wchar"},
546   { 27, "tk_wstring"},
547   { 28, "tk_fixed"},
548   { 29, "tk_value"},
549   { 30, "tk_value_box"},
550   { 31, "tk_native"},
551   { 32, "tk_abstract_interface"},
552   { 0, NULL }   
553 };
554
555
556
557 #define GIOP_MAGIC       "GIOP"
558
559 /*
560  * TAGS for IOR Profiles
561  *
562  * Chapter 13 Corba 2.4.2
563  *
564  */
565
566 #define IOP_TAG_INTERNET_IOP          0
567 #define IOP_TAG_MULTIPLE_COMPONENTS   1
568
569
570 /* Max Supported versions */
571
572 static const guint GIOP_MAJOR =  1;
573 static const guint GIOP_MINOR =  2;
574
575
576 static const int KeyAddr       = 0;
577 static const int ProfileAddr   = 1;
578 static const int ReferenceAddr = 2;
579
580
581
582 static const value_string reply_status_types[] = { 
583    { NO_EXCEPTION, "No Exception" } ,
584    { USER_EXCEPTION, "User Exception" } ,
585    { SYSTEM_EXCEPTION, "System Exception" } ,
586    { LOCATION_FORWARD, "Location Forward" } ,
587    { LOCATION_FORWARD_PERM, "Location Forward Perm" } ,
588    { NEEDS_ADDRESSING_MODE, "Needs Addressing Mode" } ,
589    { 0, NULL }
590 };
591
592
593
594 typedef enum LocateStatusType
595 {
596   UNKNOWN_OBJECT,
597   OBJECT_HERE,
598   OBJECT_FORWARD,
599   OBJECT_FORWARD_PERM,      /* new value for GIOP 1.2 */
600   LOC_SYSTEM_EXCEPTION,     /* new value for GIOP 1.2 */
601   LOC_NEEDS_ADDRESSING_MODE /* new value for GIOP 1.2 */
602 }
603 LocateStatusType_t;
604
605 typedef struct LocateReplyHeader
606 {
607   guint32 request_id;
608   guint32 locate_status;
609 }
610 LocateReplyHeader_t;
611
612
613 /*
614  * DATA - complete_request_list 
615  */
616
617 static GList *giop_complete_request_list;
618
619 struct comp_req_list_entry {
620   guint32 fn;                   /* frame number */
621   gchar * operation;            /* echo echoString */
622   giop_sub_handle_t *subh;      /* handle to sub dissector */
623   guint32 reqid;                /* request id */  
624   gchar * repoid;               /* repository ID */
625 };
626
627 typedef struct comp_req_list_entry comp_req_list_entry_t;
628
629
630 /*
631  * DATA - complete_reply_hash
632  *
633  * Maps reply FN to request MFN
634  */
635
636 static int complete_reply_hash_count = 1000; /* storage size for our permanent data */
637                                              /* ie: 1000 entries -- needs tweaking -- FS */
638
639 struct complete_reply_hash_key {
640   guint32 fn;                   /* reply frame number  */
641 };
642
643 struct complete_reply_hash_val {
644   guint32 mfn;                  /* matching frame number (request)  */
645 };
646
647 GHashTable *giop_complete_reply_hash = NULL; /* hash */
648 GMemChunk  *giop_complete_reply_keys = NULL; /* key storage */
649 GMemChunk  *giop_complete_reply_vals = NULL; /* val storage */
650
651
652 /*
653  * DATA - Module Hash stuff to store data from register_giop_user_module
654  *
655  * ie: module (or interface ?) name, and ptr to sub_dissector handle
656  *
657  * With this knowledge, we can call a sub dissector directly, 
658  * by :
659  * 
660  * objkey -> repoid -> sub_dissector via registered module/interface
661  *
662  */
663
664
665 static int giop_module_init_count = 100; /* storage size for our permanent data */
666                                          /* ie: 100 entries -- needs tweaking -- FS */
667
668 struct giop_module_key {
669   gchar *module;                /* module (interface?) name  */
670 };
671
672 struct giop_module_val {
673   giop_sub_handle_t *subh;      /* handle to sub dissector */
674 };
675
676 GHashTable *giop_module_hash = NULL; /* hash */
677 GMemChunk  *giop_module_keys = NULL; /* key storage */
678 GMemChunk  *giop_module_vals = NULL; /* val storage */
679
680
681 /*
682  * DATA - GSList to store list of function (dissector) pointers.
683  * for heuristic dissection.
684  *
685  */
686
687 static GSList *giop_sub_list = NULL;
688
689 /*
690  * DATA - Hash stuff to follow request/reply. This is so if we get a REPLY
691  * to a REQUEST (resolve), we can dump/store the RepoId and Object Key.
692  *
693  * With this knowledge, we can call a sub dissector directly later
694  * by :
695  * 
696  * objkey -> repoid -> sub_dissector via registered module/interface
697  *
698  * rather than heuristic calls that do not provide operation context.
699  * (unless we pass the RepoID for a given objkey -- hmmm)
700  *
701  */
702
703 /*
704  * Interesting operation list, add more if you want to save
705  * interesting data.
706  */
707
708 static const char  giop_op_resolve[]           = "resolve";
709 static const char  giop_op_bind_new_context[]  = "bind_new_context";
710 static const char  giop_op_bind[]              = "bind";
711
712 /*
713  * Enums  for interesting local operations, that we may need to monitor
714  * with their subsequent replies
715  * 
716  */
717
718 enum giop_op_val {
719   request_resolve_op_val,            /* REQUEST (resolve) to get RepoID etc*/
720   request_bind_new_context_op_val,   /* bind_new_context */
721   request_bind_op_val,               /* bind */
722   request_get_INIT_op_val,           /* finding Nameserver */
723
724 };
725
726
727 /*
728  * hash for mapping object keys onto object namespaces, so
729  * I can call the correct dissector.
730  *
731  *
732  */
733
734 /*
735  * Where did I get the IOR from.
736  */
737
738 enum ior_src {
739   req_res = 0,                  /* REQUEST (resolve) */
740   file,                         /* stringified IOR' in a file */
741
742 };
743
744 typedef enum ior_src ior_src_t;
745
746
747
748 /*
749  * Enums for my lists and hash's 
750  */
751
752 enum collection_data {
753   cd_heuristic_users = 0,
754   cd_module_hash,
755   cd_objkey_hash,
756   cd_complete_request_list,
757   cd_complete_reply_hash
758 };
759
760 typedef enum collection_data collection_data_t;
761
762
763
764 static int giop_objkey_init_count = 100; /* storage size for our permanent data */
765                                          /* ie: 100 entries -- needs tweaking -- FS */
766
767 struct giop_object_key {
768   guint8 *objkey;               /* ptr to object key */
769   guint32 objkey_len;           /* length */
770 };
771
772 struct giop_object_val { 
773   guint8 *repo_id;              /* ptr to Repository ID string */
774   ior_src_t src;                /* where did Iget this IOR from */
775 };
776
777 GHashTable *giop_objkey_hash = NULL; /* hash */
778 GMemChunk  *giop_objkey_keys = NULL; /* key storage */
779 GMemChunk  *giop_objkey_vals = NULL; /* val storage */
780
781
782
783 /*
784  * ------------------------------------------------------------------------------------------+ 
785  *                                 Private helper functions
786  * ------------------------------------------------------------------------------------------+
787  */
788
789
790
791 /*
792  * Insert FN,reqid,operation and sub handle in list. DOES not check for duplicates yet.
793  */
794
795 static GList *insert_in_comp_req_list(GList *list, guint32 fn, guint32 reqid, gchar * op, giop_sub_handle_t *sh ) {
796   GList * newlist_start;
797   comp_req_list_entry_t * entry = NULL;
798   gchar * opn;
799
800   entry =  g_malloc(sizeof(comp_req_list_entry_t));
801   opn =  g_strdup(op); /* duplicate operation for storage */
802     
803   entry->fn = fn;
804   entry->reqid = reqid;
805   entry->subh = sh;             
806   entry->operation = opn;       
807   entry->repoid = NULL;         /* dont have yet */
808
809   newlist_start = g_list_append (list, entry); /* append */
810
811   return newlist_start;
812 }
813
814
815 /*
816  * Used to find an entry with matching Frame Number FN
817  * in the complete_request_list list.
818  */
819
820 static comp_req_list_entry_t * find_fn_in_list(guint32 fn) {
821
822   GList * element;              /*  entry in list */
823   comp_req_list_entry_t * entry_ptr = NULL;
824   
825   element = g_list_last(giop_complete_request_list); /* start from  last  */
826   
827   while(element) {                      /* valid list entry */
828     entry_ptr = element->data;  /* grab data pointer */
829     if (entry_ptr->fn == fn) {  /* similar FN  */
830       return entry_ptr;
831     }    
832     element = g_list_previous(element); /* try next previous */
833   }
834   
835   return NULL;                  /* no match so return NULL */
836 }
837
838
839 /*
840  * Add/update a sub_dissector handle and repoid to a FN entry in the complete_request_list
841  *
842  * Call this when you know a FN and matching giop_sub_handle_t and repoid
843  *
844  * This is done in say, try_explicit_dissector for example.
845  *
846  */
847
848 static void add_sub_handle_repoid_to_comp_req_list(guint32 fn, giop_sub_handle_t *sh, gchar *repoid ) {
849
850   comp_req_list_entry_t * entry = NULL;
851   entry = find_fn_in_list(fn);  /* grab FN data entry */
852
853   if (entry) {
854     entry->subh = sh;           
855     entry->repoid = g_strdup(repoid); /* copy and store */
856
857   }
858 }
859
860
861
862
863 /* giop_complete_reply_hash  "EQUAL" Functions */
864
865 static gint complete_reply_equal_fn(gconstpointer v, gconstpointer w) {
866   struct complete_reply_hash_key *mk1 = (struct complete_reply_hash_key *)v;
867   struct complete_reply_hash_key *mk2 = (struct complete_reply_hash_key *)w;
868
869   if (mk1->fn == mk2->fn) {    
870     return 1;
871   }
872
873   return 0;                     /* found  differences */
874 }
875
876 /* giop_complete_reply_hash "HASH" Functions */
877
878 static guint32 complete_reply_hash_fn(gconstpointer v) {
879   guint32 val;          /* init hash value */
880   struct complete_reply_hash_key *key = (struct complete_reply_hash_key *)v;
881
882   val = key->fn;                /* simple and unique */
883
884   return val;
885 }
886
887
888 /*
889  * Insert the FN and MFN together in our complete_reply_hash.
890  */
891
892 static void insert_in_complete_reply_hash(guint32 fn, guint32 mfn) {
893
894   struct complete_reply_hash_key key, *new_key;
895   struct complete_reply_hash_val *val = NULL;
896
897   key.fn = fn;
898
899   val = (struct complete_reply_hash_val *)g_hash_table_lookup(giop_complete_reply_hash, &key);
900
901   if (val) {
902     return;                     /* FN collision */
903   }
904
905   new_key = g_mem_chunk_alloc(giop_complete_reply_keys);
906   new_key->fn = fn;             /* save FN */
907
908   val = g_mem_chunk_alloc(giop_complete_reply_vals);
909   val->mfn = mfn;               /* and MFN */
910   
911   g_hash_table_insert(giop_complete_reply_hash, new_key, val);
912
913 }
914
915 /*
916  * Find the MFN values from a given FN key.
917  * Assumes the complete_reply_hash is already populated.
918  */
919
920 static guint32 get_mfn_from_fn(guint32 fn) {
921
922   struct complete_reply_hash_key key;
923   struct complete_reply_hash_val *val = NULL;
924   guint32 mfn = fn;             /* save */
925
926   key.fn = fn;
927   val = (struct complete_reply_hash_val *)g_hash_table_lookup(giop_complete_reply_hash, &key);
928
929   if (val) {
930     mfn = val->mfn;             /* grab it */
931   }
932   
933   return mfn;                   /* mfn or fn if not found */
934
935 }
936
937 /*
938  * Attempt to find the MFN for this FN, and return it.
939  * Return MFN if found, or just FN if not. This is
940  * only used when we are building
941  */
942
943 static guint32 get_mfn_from_fn_and_reqid(guint32 fn, guint32 reqid) {
944
945   GList * element;              /* last entry in list */
946   comp_req_list_entry_t * entry_ptr = NULL;
947
948   /* Need Some pretty snappy code */
949   
950   /* Loop back from current end of complete_request_list looking for */
951   /* a FN with the same reqid -- TODO enhance with port/address checks -- FS */
952
953   /*
954    * As this routine is only called during initial pass of data,
955    * and NOT when a user clicks, it is ok to start from Current
956    * end of complete_request_list when searching for a match.
957    * As that list is bing populated in the same order as FN's
958    * are being read.
959    *
960    * Also, can make check for same reqid more detailed, but I start
961    * with reqid. Could add say port or address checks etc later ??
962    */
963
964
965   element = g_list_last(giop_complete_request_list); /* get last  */
966   
967   while(element) {                      /* valid list entry */
968     entry_ptr = element->data;  /* grab data pointer */
969     if (entry_ptr->reqid == reqid) {    /* similar reqid  */
970       return entry_ptr->fn;     /* return MFN */
971     }    
972     element = g_list_previous(element); /* try next previous */
973   }
974   
975   return fn;                    /* no match so return FN */
976 }
977
978
979 /* Module Hash "EQUAL" Functions */
980
981 static gint giop_hash_module_equal(gconstpointer v, gconstpointer w) {
982   struct giop_module_key *mk1 = (struct giop_module_key *)v;
983   struct giop_module_key *mk2 = (struct giop_module_key *)w;
984   
985   if (!strcmp(mk1->module, mk2->module)) {    
986     return 1;
987   }
988
989   return 0;                     /* found  differences */
990 }
991
992 /* Module Hash "HASH" Functions */
993
994 static guint32 giop_hash_module_hash(gconstpointer v) {
995   
996   int i,len;
997   guint32 val = 0;              /* init hash value */
998
999   struct giop_module_key *key = (struct giop_module_key *)v;
1000   
1001   /*
1002    * Hmm, try this simple hashing scheme for now.
1003    * ie: Simple summation, FIX later -- FS
1004    *
1005    *
1006    */
1007
1008   len = strlen(key->module);
1009
1010   for (i=0; i<len; i++) {
1011     val += (guint8) key->module[i];
1012   }
1013
1014   return val;
1015
1016 }
1017
1018
1019 /*
1020  * ------------------------------------------------------------------------------------------+ 
1021  *                                 Public Utility functions
1022  * ------------------------------------------------------------------------------------------+
1023  */
1024
1025
1026
1027
1028 /*
1029  * Routine to  allow giop users to register their sub dissector function, name, and
1030  * IDL module/interface name. Store in giop_module_hash. Also pass along their proto_XXX
1031  * value returned from their proto_register_protocol(), so we can enable/disbale it
1032  * through the GUI (edit protocols).
1033  *
1034  * This is used by try_explicit_giop_dissector() to find the
1035  * correct sub-dissector.
1036  *
1037  */
1038
1039 void register_giop_user_module(giop_sub_dissector_t *sub, gchar *name, gchar *module, int sub_proto) {
1040
1041   struct giop_module_key module_key, *new_module_key;
1042   struct giop_module_val *module_val = NULL;
1043
1044   module_key.module = module; /*  module name */
1045   
1046   module_val = (struct giop_module_val *)g_hash_table_lookup(giop_module_hash, &module_key);
1047
1048   if (module_val) {
1049     return;                     /* module name collision */
1050   }
1051   
1052   /* So, passed module name should NOT exist in hash at this point.*/
1053
1054 #if DEBUG    
1055   printf("giop:register_module: Adding Module %s to module hash \n", module);
1056   printf("giop:register_module: Module sub dissector name is %s \n", name);
1057 #endif
1058
1059   new_module_key = g_mem_chunk_alloc(giop_module_keys);
1060   new_module_key->module = module; /* save Module or interface name from IDL */
1061   
1062   module_val = g_mem_chunk_alloc(giop_module_vals);
1063
1064   module_val->subh = g_malloc(sizeof (giop_sub_handle_t)); /* init subh  */
1065
1066   module_val->subh->sub_name = name;    /* save dissector name */
1067   module_val->subh->sub_fn = sub;       /* save subdissector*/
1068   module_val->subh->sub_proto = sub_proto;      /* save subdissector's proto_XXX value */
1069   
1070   g_hash_table_insert(giop_module_hash, new_module_key, module_val);
1071
1072 }
1073
1074
1075
1076
1077 /* Object Key Hash "EQUAL" Functions */
1078
1079 static gint giop_hash_objkey_equal(gconstpointer v, gconstpointer w) {
1080   struct giop_object_key *v1 = (struct giop_object_key *)v;
1081   struct giop_object_key *v2 = (struct giop_object_key *)w;
1082
1083   if (v1->objkey_len != v2->objkey_len)
1084     return 0;                   /* no match because different length */
1085
1086   /* Now do a byte comaprison */
1087
1088   if (!memcmp(v1->objkey,v2->objkey, v1->objkey_len)) {
1089     return 1;           /* compares ok */
1090   }
1091
1092 #if DEBUG
1093   printf("giop:giop_hash_objkey_equal: Objkey's DO NOT match");
1094 #endif
1095
1096   return 0;                     /* found  differences */
1097 }
1098
1099 /* Object Key Hash "HASH" Functions */
1100
1101 static guint32 giop_hash_objkey_hash(gconstpointer v) {
1102   struct giop_object_key *key = (struct giop_object_key *)v;
1103
1104   guint32 i;
1105   guint32 val = 0;              /* init hash value */
1106
1107
1108   /*
1109    * Hmm, try this simple hashing scheme for now.
1110    * ie: Simple summation
1111    *
1112    *
1113    */
1114
1115 #if DEBUG
1116   printf("giop:hash_objkey: Key length = %u \n", key->objkey_len );
1117 #endif
1118
1119   for (i=0; i< key->objkey_len; i++) {
1120     val += (guint8) key->objkey[i];
1121   }
1122
1123   return val;
1124
1125 }
1126
1127 /*
1128  * Routine to take an object key octet sequence, and length, and ptr to
1129  * a (null terminated )repository ID string, and store them in the obect key hash.
1130  *
1131  * Blindly Inserts even if it does exist, See TODO at top for reason.
1132  */
1133
1134 static void insert_in_objkey_hash(GHashTable *hash, gchar *obj, guint32 len, gchar *repoid, ior_src_t src) {
1135
1136   struct giop_object_key objkey_key, *new_objkey_key;
1137   struct giop_object_val *objkey_val = NULL;
1138
1139   objkey_key.objkey_len  = len; /*  length  */
1140   objkey_key.objkey  = obj;     /*  object key octet sequence  */
1141
1142   /* Look it up to see if it exists */
1143
1144   objkey_val = (struct giop_object_val *)g_hash_table_lookup(hash, &objkey_key);
1145
1146   /* CHANGED -- Same reqid, so abandon old entry */
1147
1148   if (objkey_val) {
1149     g_hash_table_remove(hash, &objkey_key);
1150   }
1151   
1152   /* So, passed key should NOT exist in hash at this point.*/
1153     
1154   new_objkey_key = g_mem_chunk_alloc(giop_objkey_keys);
1155   new_objkey_key->objkey_len = len; /* save it */
1156   new_objkey_key->objkey = (guint8 *) g_memdup(obj,len);        /* copy from object and allocate ptr */
1157     
1158   objkey_val = g_mem_chunk_alloc(giop_objkey_vals);
1159   objkey_val->repo_id = g_strdup(repoid); /* duplicate and store Respository ID string */
1160   objkey_val->src = src; /* where IOR came from */
1161
1162
1163 #if DEBUG  
1164   printf("giop: ******* Inserting Objkey with RepoID = %s and key length = %u into hash  \n",
1165          objkey_val->repo_id, new_objkey_key->objkey_len);
1166 #endif
1167
1168   g_hash_table_insert(hash, new_objkey_key, objkey_val);
1169
1170 }
1171
1172
1173
1174 /*
1175  * convert an ascii char representing a hex value,
1176  * to a numeric value.
1177  *
1178  * returns value, or -1 if problem.
1179  *
1180  */
1181
1182 static gint8 hex_char_to_val(guchar c){
1183   gint8 retval ;
1184
1185   if (!isxdigit(c)) {
1186     return -1;
1187   }
1188   if (isdigit(c)) {
1189     retval = c - 48;            /* convert digit */
1190     return retval;
1191   }
1192
1193   c = toupper(c);               /* convert to uppercase */
1194   if (c >= 'A' && c <= 'F') {
1195     retval = c - 55;
1196     return retval;
1197   } 
1198   else {
1199     return -1;
1200   }
1201
1202 }
1203
1204 /*
1205  * Convert from  stringified IOR of the kind IOR:af4f7e459f....
1206  * to an IOR octet sequence.
1207  *
1208  * User must free buffer.
1209  *
1210  * Creates a new tvbuff and call decode_IOR with a NULL tree, just to
1211  * grab repoid etc for our objkey hash. 
1212  *
1213  */
1214
1215 static guint32 string_to_IOR(guchar *in, guint32 in_len, guint8 **out){
1216   gint8 tmpval_lsb;
1217   gint8 tmpval_msb;
1218   gint8 tmpval;         /* complete value */
1219   guint32 i;
1220
1221   *out = g_new0(guint8, in_len); /* allocate buffer */
1222
1223   if (*out == NULL) {
1224     return 0;
1225   }
1226
1227   /* skip past IOR:  and convert character pairs to guint8 */
1228
1229   for (i=4; i<in_len-1; i+=2) {
1230     if ( isxdigit(in[i]) && isxdigit(in[i+1]) ) { /* hex ? */
1231       
1232       if ( (tmpval_msb = hex_char_to_val(in[i])) < 0 ) {
1233         g_warning("giop: Invalid value in IOR %i \n", tmpval_msb);
1234
1235       }
1236       
1237       if ( (tmpval_lsb = hex_char_to_val(in[i+1])) < 0 ) {
1238         g_warning("giop: Invalid value in IOR %i \n", tmpval_lsb);
1239       }
1240       
1241       tmpval = tmpval_msb << 4;
1242       tmpval += tmpval_lsb;
1243       (*out)[(i-4)/2] = (guint8) tmpval;
1244
1245     }
1246     else {
1247       /* hmm  */
1248       break;
1249     }
1250     
1251   }
1252
1253   return (i-4)/2;               /* length  */
1254
1255 }
1256
1257
1258
1259 /*
1260  * Simple getline, copied from somewhere :)
1261  *
1262  */
1263
1264 static int getline(FILE *fp, gchar *line, int maxlen) {
1265
1266   if (fgets(line,maxlen,fp) == NULL)
1267     return 0;
1268   else
1269     return strlen(line);
1270
1271 }
1272
1273
1274 /* 
1275  * Read a list of stringified IOR's from a named file, convert to IOR's
1276  * and store in object key hash
1277  */
1278
1279 static void read_IOR_strings_from_file(gchar *name, int max_iorlen) {
1280   guchar *buf = NULL;           /* NOTE reused for every line */
1281   int len;
1282   int ior_val_len;              /* length after unstringifying. */
1283   FILE *fp;             
1284   guint8 *out = NULL;           /* ptr to unstringified IOR */
1285   tvbuff_t *tvb = NULL;         /* temp tvbuff for dissectin IORs */
1286   guint32 my_offset = 0;
1287   gboolean stream_is_big_endian;
1288
1289
1290   fp = fopen(name,"r"); /* open read only */
1291
1292   if (fp == NULL) {
1293     if (errno == EACCES)
1294       fprintf(stderr, "Error opening file IOR.txt for reading: %s \n",strerror(errno));
1295     return;
1296   }
1297
1298   buf = g_malloc0(max_iorlen+1);        /* input buf */
1299
1300   while ((len = getline(fp,buf,max_iorlen+1)) > 0) {
1301     my_offset = 0;              /* reset for every IOR read */
1302
1303     ior_val_len = string_to_IOR(buf,len,&out);  /* convert */
1304
1305     if(ior_val_len>0) {
1306     
1307       /* Combination of tvb_new() and tvb_set_real_data(). Can throw ReportedBoundsError. */
1308
1309       tvb =  tvb_new_real_data(out,ior_val_len,ior_val_len, "GIOP FILE IOR");
1310
1311       stream_is_big_endian = !get_CDR_octet(tvb,&my_offset);
1312       decode_IOR(tvb, NULL, NULL, &my_offset, 0, stream_is_big_endian);
1313             
1314       tvb_free(tvb);
1315       
1316     }
1317   }
1318   
1319   fclose(fp);                   /* be nice */
1320
1321   g_free(out);
1322   g_free(buf);
1323 }
1324
1325
1326
1327 /*
1328  * Init routine, setup our request hash stuff, or delete old ref's
1329  *
1330  * Cannot setup the module hash here as my init() may not be called before
1331  * users start registering. So I will move the module_hash stuff to
1332  * proto_register_giop, as is done with packet-rpc
1333  *
1334  *
1335  *
1336  * Also, setup our objectkey/repoid hash here.
1337  *
1338  */
1339
1340 static void giop_init(void) {
1341
1342
1343   /*
1344    * Create objkey/repoid  hash, use my "equal" and "hash" functions.
1345    * 
1346    */
1347
1348   if (giop_objkey_hash)
1349     g_hash_table_destroy(giop_objkey_hash);
1350   if (giop_objkey_keys)
1351     g_mem_chunk_destroy(giop_objkey_keys);
1352   if (giop_objkey_vals)
1353     g_mem_chunk_destroy(giop_objkey_vals);
1354
1355
1356   /*
1357    * Create hash, use my "equal" and "hash" functions.
1358    * 
1359    */
1360
1361   giop_objkey_hash = g_hash_table_new(giop_hash_objkey_hash, giop_hash_objkey_equal);
1362
1363   giop_objkey_keys = g_mem_chunk_new("giop_objkey_keys",
1364                                          sizeof(struct giop_object_key),
1365                                          giop_objkey_init_count * sizeof(struct giop_object_key), 
1366                                          G_ALLOC_AND_FREE);
1367
1368   giop_objkey_vals = g_mem_chunk_new("giop_objkey_vals", 
1369                                          sizeof(struct giop_object_val),
1370                                          giop_objkey_init_count * sizeof(struct giop_object_val), 
1371                                          G_ALLOC_AND_FREE);
1372
1373
1374   /*
1375    * Create complete_reply_hash, use my "equal" and "hash" functions.
1376    * 
1377    */
1378
1379   if (giop_complete_reply_hash)
1380     g_hash_table_destroy(giop_complete_reply_hash);
1381   if (giop_complete_reply_keys)
1382     g_mem_chunk_destroy(giop_complete_reply_keys);
1383   if (giop_complete_reply_vals)
1384     g_mem_chunk_destroy(giop_complete_reply_vals);
1385
1386
1387   /*
1388    * Create hash, use my "equal" and "hash" functions.
1389    * 
1390    */
1391
1392   giop_complete_reply_hash = g_hash_table_new(complete_reply_hash_fn, complete_reply_equal_fn);
1393
1394   giop_complete_reply_keys = g_mem_chunk_new("giop_complete_reply_keys",
1395                                          sizeof(struct complete_reply_hash_key),
1396                                          complete_reply_hash_count * sizeof(struct complete_reply_hash_key), 
1397                                          G_ALLOC_AND_FREE);
1398
1399   giop_complete_reply_vals = g_mem_chunk_new("giop_complete_reply_vals", 
1400                                          sizeof(struct complete_reply_hash_val),
1401                                          complete_reply_hash_count * sizeof(struct complete_reply_hash_val), 
1402                                          G_ALLOC_AND_FREE);
1403
1404
1405   
1406   read_IOR_strings_from_file("IOR.txt", 600); /* testing */
1407
1408
1409 }
1410
1411
1412 /* 
1413  * Insert an entry in the GIOP Heuristic User table.
1414  * Uses a GList.
1415  * Uses giop_sub_handle_t to wrap giop user info.
1416  *
1417  */
1418     
1419 void register_giop_user(giop_sub_dissector_t *sub, gchar *name, int sub_proto) {
1420
1421   giop_sub_handle_t *subh;
1422   
1423   subh = g_malloc(sizeof (giop_sub_handle_t));
1424
1425   subh->sub_name = name;
1426   subh->sub_fn = sub;
1427   subh->sub_proto = sub_proto;  /* proto_XXX from sub dissectors's proto_register_protocol() */
1428
1429   giop_sub_list = g_slist_append (giop_sub_list, subh);
1430  
1431 }
1432
1433
1434 /*
1435  * Lookup an object key in our object key hash, and return the corresponding
1436  * Repo Id.
1437  *
1438  */
1439
1440 static gchar * get_repoid_from_objkey(GHashTable *hash, guint8 *obj, guint32 len) {
1441
1442   struct giop_object_key objkey_key;
1443   struct giop_object_val *objkey_val = NULL;
1444
1445   objkey_key.objkey_len  = len; /*  length  */
1446   objkey_key.objkey  = obj;     /*  object key octet sequence  */
1447
1448   /* Look it up to see if it exists */
1449
1450   objkey_val = (struct giop_object_val *)g_hash_table_lookup(hash, &objkey_key);
1451
1452   if (objkey_val) {
1453 #if DEBUG
1454     printf("Lookup of object key returns  RepoId = %s \n",objkey_val->repo_id );
1455 #endif
1456     return objkey_val->repo_id; /* found  */
1457   }
1458
1459 #if DEBUG    
1460   printf("FAILED Lookup of object key \n" );
1461 #endif
1462   
1463   return NULL;                  /* not  found */
1464 }
1465
1466
1467
1468 /*
1469  * Extract top level module/interface from repoid 
1470  *
1471  * eg from -  "IDL:Echo/interface1:1.0"
1472  * get "Echo"
1473  *
1474  * Or, from "IDL:linux.org/Penguin/Teeth:1.0" get
1475  * get linux.org/Penguin/Teeth
1476  * 
1477  *
1478  * User must free returned ptr after use.
1479  *
1480  * TODO -- generalize for other Repoid encodings
1481  */
1482
1483 static gchar * get_modname_from_repoid(gchar *repoid) {
1484
1485   gchar *modname = NULL;
1486   gchar *saved_repoid = NULL;
1487   gchar c = 'a';
1488   guint8 stop_mod;              /* Index of last character of modname in Repoid  */
1489   guint8 start_mod = 4;         /* Index where Module name starts in repoid */
1490   int i;
1491
1492   saved_repoid = g_strdup(repoid); /* make a copy */
1493
1494   /* Must start with IDL: , otherwise I get confused */
1495
1496   if (g_strncasecmp("IDL:",repoid,4))
1497     return NULL;
1498
1499   /* Looks like a RepoID to me, so get Module or interface name */
1500
1501   /* TODO -- put some code here to get Module name */
1502
1503   for(i=4; c != '\0'; i++) {
1504     c = repoid[i];
1505     stop_mod = i;               /* save */
1506     if (c == ':' )              /* delimiters */
1507       break;
1508     
1509   }
1510
1511   /* Now create a new string based on start and stop and \0 */
1512   
1513   modname = g_strndup(repoid+4, stop_mod - start_mod);
1514     
1515   return modname;
1516   
1517 }
1518
1519 /*
1520  * DEBUG CODE
1521  *
1522  */
1523
1524
1525 #if DEBUG
1526
1527 /*
1528  * Display a "module" hash entry
1529  */
1530
1531 static void display_module_hash(gpointer key, gpointer val, gpointer user_data) {
1532
1533   struct giop_module_val *mv = (struct giop_module_val *) val;
1534   struct giop_module_key *mk = (struct giop_module_key *) key;
1535
1536   printf("giop:module: Key = (%s) , Val = (%s) \n", mk->module, mv->subh->sub_name);
1537   
1538   return;
1539
1540 }
1541
1542 /*
1543  * Display a "complete_reply " hash entry
1544  */
1545
1546 static void display_complete_reply_hash(gpointer key, gpointer val, gpointer user_data) {
1547
1548   struct complete_reply_hash_val *mv = (struct complete_reply_hash_val *) val;
1549   struct complete_reply_hash_key *mk = (struct complete_reply_hash_key *) key;
1550
1551   printf("giop:complete_reply: FN (key) = %8u , MFN (val) = %8u \n", mk->fn, mv->mfn);
1552   
1553   return;
1554
1555 }
1556
1557
1558 /*
1559  * Display an "objkey" hash entry
1560  */
1561
1562 static void display_objkey_hash(gpointer key, gpointer val, gpointer user_data) {
1563   guint32 i;
1564   struct giop_object_val *mv = (struct giop_object_val *) val;
1565   struct giop_object_key *mk = (struct giop_object_key *) key;
1566
1567
1568   printf("giop:objkey: Key->objkey_len = %u,  Key->objkey ",  mk->objkey_len);
1569
1570   for (i=0; i<mk->objkey_len; i++) {
1571     printf("%.2x ", mk->objkey[i]);
1572   }
1573
1574   /*
1575    * If read from file, mark it as such..
1576    */
1577
1578   if(mv->src == 0) {
1579     printf(", Repo ID = %s \n", mv->repo_id);
1580   }
1581   else {
1582     printf(", Repo ID = %s , (file) \n", mv->repo_id);    
1583   }
1584   
1585   return;
1586
1587 }
1588
1589 /*
1590  * Display all giop_sub_list (GSList) entries
1591  */
1592
1593 static void display_heuristic_user_list() {
1594   int i;
1595   int len;
1596   giop_sub_handle_t *subh;      /* handle */
1597   
1598   /* Get length of list */
1599   len = g_slist_length(giop_sub_list); /* find length */
1600
1601   if (len == 0)
1602     return;
1603
1604   for (i=0; i<len; i++) {
1605     subh = ( giop_sub_handle_t *) g_slist_nth_data(giop_sub_list,i); /* grab entry */
1606     printf("giop:heuristic_user: Element = %i, Val (user) = %s \n", i, subh->sub_name);
1607   }
1608   
1609 }
1610
1611 /*
1612  * Display all complete_request_list (GList) entries
1613  */
1614
1615 static void display_complete_request_list() {
1616   int i;
1617   int len;
1618   comp_req_list_entry_t *entry;
1619   
1620   /* Get length of list */
1621   len = g_list_length(giop_complete_request_list); /* find length */
1622
1623   if (len == 0)
1624     return;
1625
1626   for (i=0; i<len; i++) {
1627     entry = (comp_req_list_entry_t *) g_list_nth_data(giop_complete_request_list,i); /* grab entry */
1628     printf("giop:Index = %8i , FN = %8i, reqid = %8u , operation = %20s , repoid = %30s \n", i, entry->fn, 
1629            entry->reqid,entry->operation, entry->repoid);
1630   }
1631   
1632 }
1633
1634
1635
1636
1637 /* Dump Hash/List contents 
1638  *
1639  * collection_type specifies the list or hash to dump
1640  *
1641  */
1642
1643 static void giop_dump_collection(collection_data_t collection_type) {
1644
1645   switch(collection_type) {
1646   case cd_heuristic_users:
1647     printf("+----------------------------------------------+ \n");
1648     printf("+-------------- Heuristic User (Begin) --------+ \n");
1649     printf("+----------------------------------------------+ \n");
1650
1651     display_heuristic_user_list();
1652
1653     printf("+----------------------------------------------+ \n");
1654     printf("+-------------- Heuristic User (End) ----------+ \n");
1655     printf("+----------------------------------------------+ \n");
1656
1657     break;
1658
1659   case cd_complete_request_list:
1660     printf("+----------------------------------------------+ \n");
1661     printf("+------------- Complete Request List (Begin) --+ \n");
1662     printf("+----------------------------------------------+ \n");
1663
1664     display_complete_request_list();
1665
1666     printf("+----------------------------------------------+ \n");
1667     printf("+------------ Complete Request List (End) -----+ \n");
1668     printf("+----------------------------------------------+ \n");
1669
1670     break;
1671
1672   case cd_module_hash:
1673     printf("+----------------------------------------------+ \n");
1674     printf("+-------------- Module (Begin) ----------------+ \n");
1675     printf("+----------------------------------------------+ \n");
1676
1677     g_hash_table_foreach(giop_module_hash, display_module_hash, NULL);
1678
1679     printf("+----------------------------------------------+ \n");
1680     printf("+-------------- Module ( End) -----------------+ \n");
1681     printf("+----------------------------------------------+ \n\n");
1682
1683     break;
1684
1685   case cd_objkey_hash:
1686     printf("+----------------------------------------------+ \n");
1687     printf("+-------------- Objkey (Begin) ----------------+ \n");
1688     printf("+----------------------------------------------+ \n");
1689
1690     g_hash_table_foreach(giop_objkey_hash, display_objkey_hash,NULL);
1691
1692     printf("+----------------------------------------------+ \n");
1693     printf("+-------------- Objkey (End) ------------------+ \n");
1694     printf("+----------------------------------------------+ \n\n");
1695   
1696     break;
1697
1698   case cd_complete_reply_hash:
1699     printf("+----------------------------------------------+ \n");
1700     printf("+-------------- Complete_Reply_Hash (Begin) ---+ \n");
1701     printf("+----------------------------------------------+ \n");
1702
1703     g_hash_table_foreach(giop_complete_reply_hash, display_complete_reply_hash, NULL);
1704
1705     printf("+----------------------------------------------+ \n");
1706     printf("+------------- Complete_Reply_Hash (End) ------+ \n");
1707     printf("+----------------------------------------------+ \n");
1708
1709     break;
1710     
1711   default:
1712
1713     printf("giop: giop_dump_collection: Unknown type   \n");
1714
1715   }
1716
1717
1718 }
1719
1720
1721 #endif /* DEBUG */
1722
1723 /*
1724  * Loop through all  subdissectors, and call them until someone
1725  * answers (returns TRUE). This function then returns TRUE, otherwise
1726  * it return FALSE
1727  *
1728  * But skip a subdissector if it has been disabled in GUI "edit protocols".
1729  */
1730
1731 static gboolean try_heuristic_giop_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
1732                 MessageHeader *header, gchar *operation  ) {
1733
1734   int i,len;
1735   gboolean res = FALSE;         /* result of calling a heuristic sub dissector */
1736   giop_sub_handle_t *subh = NULL; 
1737
1738   len = g_slist_length(giop_sub_list); /* find length */
1739
1740   if (len == 0)
1741     return FALSE;
1742
1743   for (i=0; i<len; i++) {
1744     subh = (giop_sub_handle_t *) g_slist_nth_data(giop_sub_list,i); /* grab dissector handle */
1745
1746     if (proto_is_protocol_enabled(subh->sub_proto)) {
1747       res = (subh->sub_fn)(tvb,pinfo,tree,offset,header,operation,NULL); /* callit TODO - replace NULL */
1748       if (res) {
1749         return TRUE;            /* found one, lets return */
1750       }  
1751     } /* protocol_is_enabled */
1752   } /* loop */
1753
1754   return res;                   /* result */
1755
1756 }
1757
1758
1759 /*
1760  * Find the matching repoid in the module hash and call
1761  * the dissector function if offset exists.
1762  * 
1763  *
1764  * Repoid is eg IDL:tux.antarctic/Penguin/Teeth:1.0 but subdissectors 
1765  * will register possibly "tux.antarctic/Penguin" and "tux.antarctic/Penguin/Teeth". 
1766  *
1767  *
1768  *
1769  */
1770
1771 static gboolean try_explicit_giop_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
1772                                             MessageHeader *header, gchar *operation, gchar *repoid ) {
1773
1774   giop_sub_handle_t *subdiss = NULL; /* handle */
1775   gboolean res = FALSE;
1776   gchar *modname = NULL;
1777   struct giop_module_key module_key;
1778   struct giop_module_val *module_val = NULL;
1779
1780
1781   /*
1782    * Get top level module/interface from complete repoid 
1783    */
1784
1785   modname = get_modname_from_repoid(repoid); 
1786   if (modname == NULL) {
1787     return res;                 /* unknown module name */
1788   }
1789
1790
1791   /* Search for Module or interface name */
1792
1793   module_key.module = modname; /*  module name */
1794   module_val = (struct giop_module_val *)g_hash_table_lookup(giop_module_hash, &module_key);
1795
1796   if (module_val == NULL) {
1797     return res;                 /* module not registered */
1798   }
1799   
1800   subdiss = (giop_sub_handle_t *) module_val->subh; /* grab dissector handle */
1801
1802   if (subdiss) {
1803     /* Add giop_sub_handle_t and repoid into complete_request_list, so REPLY can */
1804     /* look it up directly, later ie: FN -> MFN -> giop_sub_handle_t and repoid */
1805     /* but only if user not clicking */
1806
1807     if (!pinfo->fd->flags.visited)
1808       add_sub_handle_repoid_to_comp_req_list(pinfo->fd->num,subdiss,repoid);
1809
1810
1811     /* Call subdissector if current offset exists , and dissector is enabled in GUI "edit protocols" */
1812
1813     if (tvb_offset_exists(tvb, *offset)) {   
1814 #if DEBUG  
1815       printf("giop:try_explicit_dissector calling sub = %s with module = (%s) \n", subdiss->sub_name  , modname);
1816 #endif
1817
1818       if (proto_is_protocol_enabled(subdiss->sub_proto)) {
1819
1820         res = (subdiss->sub_fn)(tvb,pinfo,tree,offset,header,operation, modname); /* callit, TODO replace NULL with idlname */
1821
1822       } /* protocol_is_enabled */
1823     } /* offset exists */
1824   } /* subdiss */
1825   
1826   return res;                   /* return result */
1827 }
1828
1829
1830
1831 /* Take in an array of char and create a new string.
1832  * Replace non-printable characters with periods.
1833  *
1834  * The array may contain \0's so dont use strdup
1835  * The string is \0 terminated, and thus longer than
1836  * the initial sequence. 
1837  * Caller must free the new string.
1838  */
1839
1840 static gchar * make_printable_string (gchar *in, guint32 len) {
1841   guint32 i = 0;
1842   gchar *print_string = NULL;
1843
1844   print_string = (gchar * )g_malloc0(len + 1); /* make some space and zero it */
1845   memcpy(print_string, in, len);        /* and make a copy of input data */
1846   
1847   for(i=0; i < len; i++) {
1848     if( !isprint( (unsigned char)print_string[i] ) ) 
1849       print_string[i] = '.';
1850   }
1851
1852   return print_string;          /* return ptr */
1853 }
1854
1855 /* Determine the byte order from the GIOP MessageHeader */
1856
1857 gboolean is_big_endian (MessageHeader * header) {
1858   gboolean big_endian = FALSE;
1859
1860   switch (header->GIOP_version.minor) {
1861   case 2:
1862   case 1:
1863     if (header->flags & 0x01)
1864       big_endian = FALSE;
1865     else
1866       big_endian = TRUE;
1867     break;
1868   case 0:
1869     if (header->flags)
1870       big_endian = FALSE;
1871     else
1872       big_endian = TRUE;
1873     break;
1874   default:
1875     break;
1876   }
1877   return big_endian;
1878 }
1879
1880
1881
1882 /* 
1883  * Calculate new offset, based on the current offset, and user supplied 
1884  * "offset delta" value, and the alignment requirement.
1885  *
1886  *
1887  *
1888  * eg: Used for GIOP 1.2 where Request and Reply bodies are 
1889  *     aligned on 8 byte boundaries.
1890  */
1891
1892 static void set_new_alignment(int *offset, int delta, int  alignment) {
1893
1894   while( ( (*offset + delta) % alignment) != 0)
1895           ++(*offset);
1896
1897
1898 }
1899
1900
1901
1902 /*
1903  * ------------------------------------------------------------------------------------------+ 
1904  *                                 Public get_CDR_xxx functions.
1905  * ------------------------------------------------------------------------------------------+
1906  */
1907
1908
1909
1910 /*
1911  * Gets data of type any. This is encoded as a TypeCode
1912  * followed by the encoded value.
1913  */
1914
1915 void get_CDR_any(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
1916                  gboolean stream_is_big_endian, int boundary,
1917                  MessageHeader * header ) {
1918   
1919   guint32  TCKind;    /* TypeCode */
1920
1921   /* get TypeCode of any */
1922   TCKind = get_CDR_typeCode(tvb, tree, offset, stream_is_big_endian, boundary, header );
1923
1924   /* dissect data of type TCKind */
1925   dissect_data_for_typecode(tvb, tree, offset, stream_is_big_endian, boundary, header, TCKind );
1926 }
1927
1928
1929 /* Copy a 1 octet sequence from the tvbuff 
1930  * which represents a boolean value, and convert
1931  * it to a boolean value.
1932  * Offset is then incremented by 1, to indicate the 1 octet which
1933  * has been processed.
1934  */
1935
1936 gboolean get_CDR_boolean(tvbuff_t *tvb, int *offset) {
1937   guint8 val;
1938
1939   val = tvb_get_guint8(tvb, *offset); /* easy */
1940   (*offset)++;
1941   return val;
1942 }
1943
1944 /* Copy a 1 octet sequence from the tvbuff 
1945  * which represents a char, and convert
1946  * it to an char value.
1947  * offset is then incremented by 1, to indicate the 1 octet which
1948  * has been processed.
1949  */
1950
1951 guint8 get_CDR_char(tvbuff_t *tvb, int *offset) {
1952   guint8 val;
1953
1954   val = tvb_get_guint8(tvb, *offset); /* easy */
1955   (*offset)++;
1956   return val;
1957 }
1958
1959
1960
1961 /* 
1962  * Floating Point Data Type double IEEE 754-1985 
1963  *
1964  * Copy an 8 octet sequence from the tvbuff 
1965  * which represents a double value, and convert
1966  * it to a double value, taking into account byte order.
1967  * offset is first incremented so that it falls on a proper alignment
1968  * boundary for double values.
1969  * offset is then incremented by 8, to indicate the 8 octets which
1970  * have been processed.
1971  */
1972
1973 gdouble get_CDR_double(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
1974
1975   guint8 sign;
1976   guint8 e1,e2,f1,f2,f3,f4,f5,f6,f7;
1977   gdouble val;
1978   guint16 exp;
1979   guint32 fract0, fract1;
1980   gdouble d_fract;              
1981   
1982
1983   /* double values must be aligned on a 8 byte boundary */
1984
1985   while( ( (*offset + boundary) % 8) != 0)
1986           ++(*offset);
1987
1988
1989   if(stream_is_big_endian) {    
1990     e1  = get_CDR_octet(tvb,offset);
1991     sign = e1 >> 7;                     /* sign value */
1992     e1 &= 0x7f;         /* bottom 7 bits */
1993     f1  = get_CDR_octet(tvb,offset);
1994     e2 = f1 >> 4;
1995     f1 &= 0x0f;         /* bottom 4 bits */
1996     f2  = get_CDR_octet(tvb,offset);
1997     f3  = get_CDR_octet(tvb,offset);
1998     f4  = get_CDR_octet(tvb,offset);
1999     f5  = get_CDR_octet(tvb,offset);
2000     f6  = get_CDR_octet(tvb,offset);
2001     f7  = get_CDR_octet(tvb,offset);
2002
2003   } else {
2004
2005     f7  = get_CDR_octet(tvb,offset);
2006     f6  = get_CDR_octet(tvb,offset);
2007     f5  = get_CDR_octet(tvb,offset);
2008     f4  = get_CDR_octet(tvb,offset);
2009     f3  = get_CDR_octet(tvb,offset);
2010     f2  = get_CDR_octet(tvb,offset);
2011     f1  = get_CDR_octet(tvb,offset);
2012     e2 = f1 >> 4;
2013     f1 &= 0x0f;         /* bottom 4 bits */
2014     e1  = get_CDR_octet(tvb,offset);
2015     sign = e1 >> 7;                     /* sign value */
2016     e1 &= 0x7f;         /* bottom 7 bits */
2017
2018   }
2019
2020   exp = (e1 << 4) + e2;
2021
2022   /* Now lets do some 52 bit math with 32 bit constraint */
2023
2024   fract0 = f7 + (f6 << 8) + (f5 << 16) + (f4 << 24); /* lower 32 bits of fractional part */
2025   fract1 = f3 + (f2 << 8) + (f1 << 16);              /* top 20 bits of fractional part   */
2026
2027   d_fract = (fract1 / (pow(2,20))) + (fract0 / (pow(2,52))); /* 52 bits represent a fraction */
2028
2029   val = pow(-1,sign) * pow(2,(exp - 1023)) * (1 + d_fract);
2030
2031   return val;           /* FIX rounding ?? */
2032
2033 }
2034
2035
2036 /* Copy a 4 octet sequence from the tvbuff 
2037  * which represents an enum value, and convert
2038  * it to an enum value, taking into account byte order.
2039  * offset is first incremented so that it falls on a proper alignment
2040  * boundary for an enum (4)
2041  * offset is then incremented by 4, to indicate the 4 octets which
2042  * have been processed.
2043  *
2044  * Enum values are encoded as unsigned long.
2045  */
2046
2047
2048 guint32 get_CDR_enum(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2049
2050   return get_CDR_ulong(tvb, offset, stream_is_big_endian, boundary );
2051
2052 }
2053
2054
2055 /*
2056  * Copy an octet sequence from the tvbuff
2057  * which represents a Fixed point decimal type, and create a string representing
2058  * a Fixed point decimal type. There are no alignment restrictions.
2059  * Size and scale of fixed decimal type is determined by IDL.
2060  * 
2061  * digits - IDL specified number of "digits" for this fixed type
2062  * scale  - IDL specified "scale" for this fixed type
2063  *
2064  *
2065  * eg: typedef fixed <5,2> fixed_t;
2066  *     could represent numbers like 123.45, 789.12, 
2067  *
2068  *
2069  * As the fixed type could be any size, I will not try to fit it into our
2070  * simple types like gdouble or glong etc. I will just create a string buffer holding
2071  * a  representation (after scale is applied), and with a decimal point or zero padding
2072  * inserted at the right place if necessary. The string is null terminated
2073  *
2074  * so string may look like 
2075  *
2076  *
2077  *  "+1.234" or "-3456.78" or "1234567309475760377365465897891" or "-2789000000" etc
2078  *
2079  * According to spec, digits <= 31
2080  * and scale is positive (except for constants eg: 1000 has digit=1 and implied scale = -3)
2081  * or <4,0> ?
2082  *
2083  * User must remember to free the buffer
2084  *
2085  */
2086
2087
2088 void get_CDR_fixed(tvbuff_t *tvb, gchar **seq, gint *offset, guint32 digits, gint32 scale) {
2089
2090   guint8 sign;                  /* 0x0c is positive, 0x0d is negative */
2091   guint32 i ;                   /* loop */
2092   guint32 slen;                 /* number of bytes to hold digits + extra 0's if scale <0 */
2093                                 /* this does not include sign, decimal point and \0 */
2094   guint32 sindex = 0;           /* string index */
2095   gchar *tmpbuf = NULL;         /* temp buff, holds string without scaling */
2096   guint8 tval;                  /* temp val storage */
2097
2098   /*
2099    * how many bytes to hold digits and scale (if scale <0) 
2100    *
2101    * eg: fixed <5,2> = 5 digits
2102    *     fixed <5,-2> = 7 digits (5 + 2 added 0's)
2103    */
2104
2105 #if DEBUG
2106     printf("giop:get_CDR_fixed() called , digits = %u, scale = %u \n", digits, scale);
2107 #endif
2108
2109   if (scale <0) {
2110     slen = digits - scale;      /* allow for digits + padding 0's for negative scal */
2111   } else {
2112     slen = digits;              /*  digits */
2113   }
2114
2115 #if DEBUG
2116     printf("giop:get_CDR_fixed(): slen =  %.2x \n", slen);
2117 #endif
2118   
2119   tmpbuf = g_new0(gchar, slen); /* allocate temp buffer */ 
2120   
2121   /* If even , grab 1st dig */
2122
2123   if (!(digits & 0x01)) {
2124     tval = get_CDR_octet(tvb,offset);
2125 #if DEBUG
2126     printf("giop:get_CDR_fixed():even: octet = %.2x \n", tval);
2127 #endif
2128     tmpbuf[sindex] = (tval & 0x0f) + 0x30; /* convert top nibble to ascii */
2129     sindex++;
2130   }
2131
2132   /*
2133    * Loop, but stop BEFORE we hit last digit and sign 
2134    * if digits = 1 or 2, then this part is skipped 
2135    */
2136
2137   if (digits>2) {
2138     for(i=0; i< ((digits-1)/2 ); i++) {
2139       tval = get_CDR_octet(tvb,offset);
2140 #if DEBUG
2141       printf("giop:get_CDR_fixed():odd: octet = %.2x \n", tval);
2142 #endif
2143       
2144       tmpbuf[sindex] = ((tval & 0xf0) >> 4) + 0x30; /* convert top nibble to ascii */
2145       sindex++;
2146       tmpbuf[sindex] = (tval & 0x0f)  + 0x30; /* convert bot nibble to ascii */
2147       sindex++;
2148       
2149     }
2150   } /* digits > 3 */
2151
2152 #if DEBUG
2153     printf("giop:get_CDR_fixed(): before last digit \n");
2154 #endif
2155   
2156
2157   /* Last digit and sign if digits >1, or 1st dig and sign if digits = 1 */
2158
2159     tval = get_CDR_octet(tvb,offset);
2160 #if DEBUG
2161     printf("giop:get_CDR_fixed(): octet = %.2x \n", tval);
2162 #endif
2163     tmpbuf[sindex] = (( tval & 0xf0)>> 4) + 0x30; /* convert top nibble to ascii */
2164     sindex++;
2165
2166     sign = tval & 0x0f; /* get sign */
2167
2168     /* So now, we have all digits in an array, and the sign byte 
2169      * so lets generate a printable string, taking into account the scale
2170      * and sign values.
2171      */
2172  
2173     sindex = 0;                         /* reset */
2174     *seq = g_new0(gchar, slen + 3);     /* allocate temp buffer , including space for sign, decimal point and 
2175                                          * \0 -- TODO check slen is reasonable first */
2176 #if DEBUG
2177     printf("giop:get_CDR_fixed(): sign =  %.2x \n", sign);
2178 #endif                                  
2179     
2180     switch(sign) {
2181     case 0x0c:
2182       (*seq)[sindex] = '+';     /* put sign in first string position */
2183       break;                    
2184     case 0x0d:
2185       (*seq)[sindex] = '-';
2186       break;
2187     default:
2188       g_warning("giop: Unknown sign value in fixed type %u \n", sign);
2189       (*seq)[sindex] = '*';     /* flag as sign unkown */
2190       break;
2191     }
2192
2193     sindex++;
2194
2195     /* Add decimal point or padding 0's, depending if scale is positive or
2196      * negative, respectively
2197      */
2198
2199     if (scale>0) {
2200       for (i=0; i<digits-scale; i++) {
2201         (*seq)[sindex] = tmpbuf[i]; /* digits to the left of the decimal point */       
2202         sindex++;
2203       }
2204       
2205       (*seq)[sindex] = '.'; /* decimal point */ 
2206       sindex++;
2207       
2208       for (i=digits-scale; i<digits; i++) {
2209         (*seq)[sindex] = tmpbuf[i]; /* remaining digits to the right of the decimal point */    
2210         sindex++;
2211       }
2212
2213       (*seq)[sindex] = '\0'; /* string terminator */    
2214
2215     } else {
2216
2217       /* negative scale, dump digits and  pad out with 0's */
2218
2219       for (i=0; i<digits-scale; i++) {
2220         if (i<digits) {
2221           (*seq)[sindex] = tmpbuf[i]; /* save digits */ 
2222         } else {
2223           (*seq)[sindex] = '0'; /* all digits used up, so pad with 0's */       
2224         }
2225         sindex++;
2226       }
2227
2228       (*seq)[sindex] = '\0'; /* string terminator */    
2229       
2230     }
2231     
2232     g_free(tmpbuf);             /* release temp buffer */
2233
2234
2235 #if DEBUG
2236     printf("giop:get_CDR_fixed(): value = %s \n", *seq);
2237 #endif
2238
2239     return; 
2240
2241 }
2242
2243
2244
2245 /*
2246  * Floating Point Data Type float IEEE 754-1985 
2247  * 
2248  * Copy an 4 octet sequence from the tvbuff 
2249  * which represents a float value, and convert
2250  * it to a float value, taking into account byte order.
2251  * offset is first incremented so that it falls on a proper alignment
2252  * boundary for float values.
2253  * offset is then incremented by 4, to indicate the 4 octets which
2254  * have been processed.
2255  */
2256
2257 gfloat get_CDR_float(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2258   
2259   guint8 sign;
2260   guint8 e1,e2,f1,f2,f3;
2261   gfloat val;
2262   guint8 exp;
2263   guint32 fract;
2264   gdouble d_fract;              
2265   
2266   /* float values must be aligned on a 4 byte boundary */
2267
2268   while( ( (*offset + boundary) % 4) != 0)
2269     ++(*offset);
2270
2271   if(stream_is_big_endian) {    
2272     e1  = get_CDR_octet(tvb,offset);
2273     sign = e1 >> 7;                     /* sign value */
2274     e1 &= 0x7f;         /* bottom 7 bits */
2275     f1  = get_CDR_octet(tvb,offset);
2276     e2 = f1 >> 7;
2277     f1 &= 0x7f;         /* bottom 7 bits */
2278     f2  = get_CDR_octet(tvb,offset);
2279     f3  = get_CDR_octet(tvb,offset);
2280
2281   } else {
2282
2283     f3  = get_CDR_octet(tvb,offset);
2284     f2  = get_CDR_octet(tvb,offset);
2285     f1  = get_CDR_octet(tvb,offset);
2286     e2 = f1 >> 7;
2287     f1 &= 0x7f;         /* bottom 7 bits */
2288     e1  = get_CDR_octet(tvb,offset);
2289     sign = e1 >> 7;                     /* sign value */
2290     e1 &= 0x7f;         /* bottom 7 bits */
2291
2292   }
2293
2294
2295   exp = (e1 << 1) + e2;
2296   fract = f3 + (f2 << 8) + (f1 << 16);
2297
2298   d_fract = fract / (pow(2,23)); /* 23 bits represent a fraction */
2299
2300   val = pow(-1,sign) * pow(2,(exp - 127)) * (1 + d_fract);
2301
2302   return val;           /* FIX rounding ?? */
2303
2304 }
2305
2306
2307 /*
2308  * Decode an Interface type, and display it on the tree.
2309  */
2310
2311 void get_CDR_interface(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, 
2312                        gboolean stream_is_big_endian, int boundary) {
2313
2314
2315   decode_IOR(tvb, pinfo, tree, offset, boundary, stream_is_big_endian);
2316   
2317   return;
2318 }
2319
2320
2321 /* Copy a 4 octet sequence from the tvbuff 
2322  * which represents a signed long value, and convert
2323  * it to an signed long vaule, taking into account byte order.
2324  * offset is first incremented so that it falls on a proper alignment
2325  * boundary for long values.
2326  * offset is then incremented by 4, to indicate the 4 octets which
2327  * have been processed.
2328  */
2329
2330 gint32 get_CDR_long(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2331
2332   gint32 val;
2333
2334   /* unsigned long values must be aligned on a 4 byte boundary */
2335   while( ( (*offset + boundary) % 4) != 0)
2336           ++(*offset);
2337
2338   val = (stream_is_big_endian) ? tvb_get_ntohl (tvb, *offset) :
2339                                  tvb_get_letohl (tvb, *offset);
2340
2341   *offset += 4; 
2342   return val; 
2343 }
2344
2345 /*
2346  * Decode an Object type, and display it on the tree.
2347  */
2348
2349 void get_CDR_object(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, 
2350                     gboolean stream_is_big_endian, int boundary) {
2351   
2352   decode_IOR(tvb, pinfo, tree, offset, boundary, stream_is_big_endian);
2353   
2354   return;
2355 }
2356
2357
2358 /* Copy a 1 octet sequence from the tvbuff 
2359  * which represents a octet, and convert
2360  * it to an octet value.
2361  * offset is then incremented by 1, to indicate the 1 octet which
2362  * has been processed.
2363  */
2364
2365 guint8 get_CDR_octet(tvbuff_t *tvb, int *offset) {
2366   guint8 val;
2367
2368   val = tvb_get_guint8(tvb, *offset); /* easy */
2369   (*offset)++;
2370   return val;
2371 }
2372
2373
2374 /* Copy a sequence of octets from the tvbuff.
2375  * Caller of this function must remember to free the 
2376  * array pointed to by seq.
2377  * This function also increments offset by len. 
2378  */
2379
2380 void get_CDR_octet_seq(tvbuff_t *tvb, gchar **seq, int *offset, int len) {
2381
2382   if (! tvb_bytes_exist(tvb, *offset,len)) {
2383     tvb_get_guint8(tvb,100000);  /* generate an exception, and stop processing */
2384                                 /* better than a core dump later */
2385   }
2386
2387      *seq = g_new0(gchar, len + 1);
2388      tvb_memcpy( tvb, *seq, *offset, len);
2389      *offset += len;
2390 }
2391
2392
2393 /* Copy a 2 octet sequence from the tvbuff 
2394  * which represents a signed short value, and convert
2395  * it to a signed short value, taking into account byte order.
2396  * offset is first incremented so that it falls on a proper alignment
2397  * boundary for short values.
2398  * offset is then incremented by 2, to indicate the 2 octets which
2399  * have been processed.
2400  */
2401
2402 gint16 get_CDR_short(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2403
2404   gint16 val;
2405
2406   /* short values must be aligned on a 2 byte boundary */
2407   while( ( (*offset + boundary) % 2) != 0)
2408           ++(*offset);
2409
2410   val = (stream_is_big_endian) ? tvb_get_ntohs (tvb, *offset) :
2411                                  tvb_get_letohs (tvb, *offset);
2412
2413   *offset += 2; 
2414   return val; 
2415 }
2416
2417
2418
2419 /* Copy an octet sequence from the tvbuff 
2420  * which represents a string, and convert
2421  * it to an string value, taking into account byte order.
2422  * offset is first incremented so that it falls on a proper alignment
2423  * boundary for string values. (begins with an unsigned long LI)
2424  *
2425  * String sequence is copied to a  buffer "seq". This must
2426  * be freed by the calling program.
2427  * offset is then incremented, to indicate the  octets which
2428  * have been processed.
2429  *
2430  * returns number of octets in the sequence
2431  *
2432  * Note: This function only supports single byte encoding at the
2433  *       moment until I get a handle on multibyte encoding etc.
2434  *
2435  */
2436
2437
2438 guint32 get_CDR_string(tvbuff_t *tvb, gchar **seq, int *offset, gboolean stream_is_big_endian, 
2439                        int boundary ) {
2440   
2441   guint32 slength;
2442
2443   slength = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get length first */
2444
2445   /*  Avoid crashing */
2446
2447   if (! tvb_bytes_exist(tvb, *offset, slength)) {
2448     tvb_get_guint8(tvb,100000); /* generate an exception, and stop processing */
2449                                 /* better than a core dump later */
2450   }
2451
2452 #if 0
2453   (*offset)++;                  /* must step past \0 delimiter */
2454 #endif
2455   
2456   if (slength > 0) {
2457     get_CDR_octet_seq(tvb, seq, offset, slength);
2458   }
2459
2460   return slength;               /* return length */
2461
2462 }
2463
2464 /* Process a sequence of octets that represent the 
2465  * Pseudo Object Type "TypeCode". Typecodes are used for example,
2466  * by "Any values". 
2467  * This function also increments offset to the correct position.
2468  *
2469  * It will parse the TypeCode and output data to the "tree" provided
2470  * by the user
2471  *
2472  * It returns a guint32 representing a TCKind value. 
2473  */
2474
2475 guint32 get_CDR_typeCode(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
2476                          gboolean stream_is_big_endian, int boundary,
2477                          MessageHeader * header ) {
2478   guint32 val;
2479
2480   gint16  s_octet2; /* signed int16 */
2481   guint16 u_octet2; /* unsigned int16 */
2482   guint32 u_octet4; /* unsigned int32 */
2483
2484   val = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get TCKind enum */
2485   if (tree) {
2486     proto_tree_add_uint(tree,hf_giop_TCKind,tvb,
2487                         *offset-sizeof(val),4,val);
2488   }
2489
2490   /* Grab the data according to Typecode Table - Corba Chapter 15 */
2491
2492   switch (val) {
2493   case tk_null: /* empty parameter list */
2494     break;
2495   case tk_void: /* empty parameter list */
2496     break;
2497   case tk_short: /* empty parameter list */
2498     break;
2499   case tk_long: /* empty parameter list */
2500     break;
2501   case tk_ushort: /* empty parameter list */
2502     break;
2503   case tk_ulong: /* empty parameter list */
2504     break;
2505   case tk_float: /* empty parameter list */
2506     break;
2507   case tk_double: /* empty parameter list */
2508     break;
2509   case tk_boolean: /* empty parameter list */
2510     break;
2511   case tk_char: /* empty parameter list */
2512     break;
2513   case tk_octet: /* empty parameter list */
2514     break;
2515   case tk_any: /* empty parameter list */
2516     break;
2517   case tk_TypeCode: /* empty parameter list */
2518     break;
2519   case tk_Principal: /* empty parameter list */
2520     break;
2521   case tk_objref: /* complex parameter list */
2522     dissect_tk_objref_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2523     break;
2524   case tk_struct: /* complex parameter list */
2525     dissect_tk_struct_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2526     break;
2527   case tk_union: /* complex parameter list */
2528     dissect_tk_union_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2529     break;
2530   case tk_enum: /* complex parameter list */
2531     dissect_tk_enum_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2532     break;
2533
2534   case tk_string: /* simple parameter list */
2535     u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get maximum length */
2536     if (tree) {
2537       proto_tree_add_uint(tree,hf_giop_typecode_max_length,tvb,
2538                           *offset-sizeof(u_octet4),4,u_octet4);
2539     }
2540     break;
2541
2542   case tk_sequence: /* complex parameter list */
2543     dissect_tk_sequence_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2544     break;
2545   case tk_array: /* complex parameter list */
2546     dissect_tk_array_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2547     break;
2548   case tk_alias: /* complex parameter list */
2549     dissect_tk_alias_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2550     break;
2551   case tk_except: /* complex parameter list */
2552     dissect_tk_except_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2553     break;
2554   case tk_longlong: /* empty parameter list */
2555     break;
2556   case tk_ulonglong: /* empty parameter list */
2557     break;
2558   case tk_longdouble: /* empty parameter list */
2559     break;
2560   case tk_wchar: /* empty parameter list */
2561     break;
2562   case tk_wstring: /* simple parameter list */
2563     u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get maximum length */
2564     if (tree) {
2565       proto_tree_add_uint(tree,hf_giop_typecode_max_length,tvb,
2566                           *offset-sizeof(u_octet4),4,u_octet4);
2567     }
2568     break;
2569
2570   case tk_fixed: /* simple parameter list */
2571     u_octet2 = get_CDR_ushort(tvb,offset,stream_is_big_endian,boundary); /* get digits */
2572     if (tree) {
2573       proto_tree_add_uint(tree,hf_giop_typecode_digits,tvb,
2574                           *offset-sizeof(u_octet2),2,u_octet2);
2575     }
2576
2577     s_octet2 = get_CDR_short(tvb,offset,stream_is_big_endian,boundary); /* get scale */
2578     if (tree) {
2579       proto_tree_add_int(tree,hf_giop_typecode_scale,tvb,
2580                           *offset-sizeof(s_octet2),2,s_octet2);
2581     }
2582     break;
2583
2584   case tk_value: /* complex parameter list */
2585     dissect_tk_value_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2586     break;
2587   case tk_value_box: /* complex parameter list */
2588     dissect_tk_value_box_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2589     break;
2590   case tk_native: /* complex parameter list */
2591     dissect_tk_native_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2592     break;
2593   case tk_abstract_interface: /* complex parameter list */
2594     dissect_tk_abstract_interface_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2595     break;
2596   default:
2597     g_warning("giop: Unknown TCKind %u \n", val);
2598     break;
2599   } /* val */
2600
2601   return val;
2602 }
2603
2604
2605
2606 /* Copy a 4 octet sequence from the tvbuff 
2607  * which represents an unsigned long value, and convert
2608  * it to an unsigned long vaule, taking into account byte order.
2609  * offset is first incremented so that it falls on a proper alignment
2610  * boundary for unsigned long values.
2611  * offset is then incremented by 4, to indicate the 4 octets which
2612  * have been processed.
2613  */
2614
2615 guint32 get_CDR_ulong(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2616
2617   guint32 val;
2618
2619   /* unsigned long values must be aligned on a 4 byte boundary */
2620   while( ( (*offset + boundary) % 4) != 0)
2621           ++(*offset);
2622
2623   val = (stream_is_big_endian) ? tvb_get_ntohl (tvb, *offset) :
2624                                  tvb_get_letohl (tvb, *offset);
2625
2626   *offset += 4; 
2627   return val; 
2628 }
2629
2630
2631 /* Copy a 2 octet sequence from the tvbuff 
2632  * which represents an unsigned short value, and convert
2633  * it to an unsigned short value, taking into account byte order.
2634  * offset is first incremented so that it falls on a proper alignment
2635  * boundary for unsigned short values.
2636  * offset is then incremented by 2, to indicate the 2 octets which
2637  * have been processed.
2638  */
2639
2640 guint16 get_CDR_ushort(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2641
2642   guint16 val;
2643
2644   /* unsigned short values must be aligned on a 2 byte boundary */
2645   while( ( (*offset + boundary) % 2) != 0)
2646           ++(*offset);
2647
2648   val = (stream_is_big_endian) ? tvb_get_ntohs (tvb, *offset) :
2649                                  tvb_get_letohs (tvb, *offset);
2650
2651   *offset += 2; 
2652   return val; 
2653 }
2654
2655
2656
2657 /* Copy a wchar from the tvbuff.
2658  * Caller of this function must remember to free the 
2659  * array pointed to by seq.
2660  * This function also increments offset according to
2661  * the wchar size.
2662  *
2663  * For GIOP 1.1 read 2 octets and return size -2. The
2664  * negation means there is no size element in the packet
2665  * and therefore no size to add to the tree.
2666  *
2667  * For GIOP 1.2 read size of wchar and the size
2668  * octets. size is returned as a gint8.
2669  *
2670  * For both GIOP versions the wchar is returned
2671  * as a printable string.
2672  *
2673  */
2674
2675 /* NOTE: This is very primitive in that it just reads
2676  * the wchar as a series of octets and returns them
2677  * to the user. No translation is attempted based on
2678  * byte orientation, nor on code set. I.e it only 
2679  * really reads past the wchar and sets the offset
2680  * correctly.
2681  */
2682
2683 /* The "decoding" is done according to CORBA chapter 15.
2684  * Wchar is not supported for GIOP 1.0.
2685  */
2686
2687 gint8 get_CDR_wchar(tvbuff_t *tvb, gchar **seq, int *offset, MessageHeader * header) {
2688   
2689   gint8 slength;
2690   gchar *raw_wstring = NULL;
2691
2692   /* CORBA chapter 15:
2693    *   - prior to GIOP 1.2 wchar limited to two octet fixed length.
2694    *   - GIOP 1.2 wchar is encoded as an unsigned binary octet
2695    *     followed by the elements of the octet sequence representing
2696    *     the encoded value of the wchar.
2697    */
2698
2699   *seq = NULL; /* set in case GIOP 1.2 length is 0 */
2700   slength = 2; /* set for GIOP 1.1 length in octets */
2701
2702   if (header->GIOP_version.minor > 1) /* if GIOP 1.2 get length of wchar */
2703     slength = get_CDR_octet(tvb,offset);
2704
2705   if (slength > 0) {
2706     /* ??? assume alignment is ok for GIOP 1.1 ??? */
2707     get_CDR_octet_seq(tvb, &raw_wstring, offset, slength);
2708
2709     /* now turn octets (wchar) into something that can be printed by the user */
2710     *seq = make_printable_string(raw_wstring, slength);
2711   }
2712
2713   /* if GIOP 1.1 negate length to indicate not an item to add to tree */
2714   if (header->GIOP_version.minor < 2)
2715     slength = -slength;
2716
2717   g_free(raw_wstring);  
2718
2719   return slength;               /* return length */
2720
2721 }
2722
2723
2724 /* Copy a wstring from the tvbuff.
2725  * Caller of this function must remember to free the 
2726  * array pointed to by seq.
2727  * This function also increments offset, according to
2728  * wstring length. length is returned as guint32
2729  */
2730
2731 /* NOTE: This is very primitive in that it just reads
2732  * the wstring as a series of octets and returns them
2733  * to the user. No translation is attempted based on
2734  * byte orientation, nor on code set. I.e it only 
2735  * really reads past the wstring and sets the offset
2736  * correctly.
2737  */
2738
2739 /* The "decoding" is done according to CORBA chapter 15.
2740  * Wstring is not supported for GIOP 1.0.
2741  */
2742
2743
2744 guint32 get_CDR_wstring(tvbuff_t *tvb, gchar **seq, int *offset, gboolean stream_is_big_endian, 
2745                        int boundary, MessageHeader * header) {
2746   
2747   guint32 slength;
2748   gchar *raw_wstring = NULL;
2749
2750   /* CORBA chapter 15:
2751    *   - prior to GIOP 1.2 wstring limited to two octet fixed length.
2752    *     length and string are NUL terminated (length???).
2753    *   - GIOP 1.2 length is total number of octets. wstring is NOT NUL
2754    *     terminated.
2755    */
2756
2757   *seq = NULL; /* set in case GIOP 1.2 length is 0 */
2758
2759   /* get length, same for all GIOP versions,
2760    * although for 1.2 CORBA doesnt say, so assume. 
2761    */
2762   slength = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
2763
2764 #ifdef DEBUG
2765   if (slength>200) {
2766         fprintf(stderr, "giop:get_CDR_wstring, length %u > 200, truncating to 5 \n", slength);
2767         slength = 5;            /* better than core dumping during debug */
2768   }
2769 #endif
2770   
2771   if (header->GIOP_version.minor < 2) {
2772 #if 0
2773     (*offset)++;  /* must step past \0 delimiter */
2774 #endif
2775     /* assume length is number of characters and not octets, spec not clear */
2776     slength = slength * 2; /* length in octets is 2 * wstring length */
2777   }
2778
2779   if (slength > 0) {
2780     get_CDR_octet_seq(tvb, &raw_wstring, offset, slength);
2781
2782     /* now turn octets (wstring) into something that can be printed by the user */
2783     *seq = make_printable_string(raw_wstring, slength);
2784   }
2785
2786   g_free(raw_wstring);  
2787
2788   return slength;               /* return length */
2789
2790 }
2791
2792
2793
2794 /**
2795  *  Dissects a TargetAddress which is defined in (CORBA 2.4, section 15.4.2)
2796  *  GIOP 1.2
2797  *  typedef short AddressingDisposition;
2798  *  const short KeyAddr = 0;
2799  *  const short ProfileAddr = 1;
2800  *  const short ReferenceAddr = 2;
2801  *  struct IORAddressingInfo {
2802  *    unsigned long selected_profile_index;
2803  *    IOP::IOR ior;
2804  *  };
2805  *
2806  *  union TargetAddress switch (AddressingDisposition) {
2807  *      case KeyAddr: sequence <octet> object_key;
2808  *      case ProfileAddr: IOP::TaggedProfile profile;
2809  *      case ReferenceAddr: IORAddressingInfo ior;
2810  *  };
2811  */
2812
2813 static void
2814 dissect_target_address(tvbuff_t * tvb, packet_info *pinfo, int *offset, proto_tree * tree, 
2815                        MessageHeader * header, gboolean stream_is_big_endian)
2816 {
2817    guint16 discriminant;
2818    gchar *object_key = NULL;
2819    gchar *p_object_key = NULL;
2820    guint32 len = 0;
2821    guint32 u_octet4;
2822
2823    discriminant = get_CDR_ushort(tvb, offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2824    if(tree)
2825    {
2826      proto_tree_add_text (tree, tvb, *offset -2, 2,
2827                  "TargetAddress Discriminant: %u", discriminant);
2828    }
2829   
2830    switch (discriminant)
2831    {
2832    case 0:  /* KeyAddr */
2833                    len = get_CDR_ulong(tvb, offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2834                    if(tree)
2835                    {
2836                       proto_tree_add_text (tree, tvb, *offset -4, 4,
2837                                            "KeyAddr (object key length): %u", len);
2838                    }
2839
2840                    if (len > 0) {
2841
2842                      get_CDR_octet_seq(tvb, &object_key, offset, len);
2843                      p_object_key = make_printable_string( object_key, len );
2844                    
2845                      if(tree)
2846                        {
2847                          proto_tree_add_text (tree, tvb, *offset -len, len,
2848                                                "KeyAddr (object key): %s", p_object_key);
2849                        }
2850                    }
2851                    break;
2852            case 1: /* ProfileAddr */
2853                    decode_TaggedProfile(tvb, pinfo, tree, offset, GIOP_HEADER_SIZE,
2854                                         stream_is_big_endian, NULL);
2855                    break;
2856            case 2: /* ReferenceAddr */
2857                    u_octet4 = get_CDR_ulong(tvb, offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2858
2859                    if(tree)
2860                    {
2861                       proto_tree_add_text (tree, tvb, *offset -len -4, 4,
2862                                            "ReferenceAddr (selected_profile_index): %u", u_octet4);
2863                    }
2864
2865                    decode_IOR(tvb, pinfo, tree, offset, GIOP_HEADER_SIZE, stream_is_big_endian);
2866                    break;
2867            default:
2868                    break;
2869    }
2870    g_free( object_key );
2871    g_free( p_object_key );
2872 }
2873
2874 static void
2875 dissect_reply_body (tvbuff_t *tvb, u_int offset, packet_info *pinfo,
2876                     proto_tree *tree, gboolean stream_is_big_endian,
2877                     guint32 reply_status, MessageHeader *header, proto_tree *clnp_tree) {
2878
2879   u_int sequence_length;
2880   gboolean exres = FALSE;               /* result of trying explicit dissectors */
2881   gchar * repoid = NULL;        /* Repositor ID looked up from  objkey */
2882   
2883   /*
2884    * comp_req_list stuff
2885    */
2886
2887   comp_req_list_entry_t * entry = NULL; /* data element in our list */
2888   
2889   guint32 mfn;
2890
2891   switch (reply_status)
2892     {
2893     case SYSTEM_EXCEPTION:
2894
2895       decode_SystemExceptionReplyBody (tvb, tree, &offset, stream_is_big_endian, GIOP_HEADER_SIZE);
2896       break;
2897
2898     case USER_EXCEPTION:
2899
2900       sequence_length = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2901
2902       if (tree)
2903       {
2904           proto_tree_add_text(tree, tvb, offset-4, 4,
2905                            "Exception length: %u", sequence_length);
2906       }
2907       if (sequence_length != 0)
2908         {
2909           if (tree)
2910           {
2911               proto_tree_add_text(tree, tvb, offset, sequence_length,
2912                            "Exception id: %s",
2913                            tvb_format_text(tvb, offset, sequence_length));
2914           }
2915 #if 1
2916
2917           header->exception_id = g_new0(gchar,sequence_length ); /* allocate buffer */
2918
2919           /* read exception id from buffer and store in*/
2920
2921           tvb_get_nstringz0(tvb,offset,sequence_length, header->exception_id );
2922           
2923
2924 #endif          
2925           
2926
2927           offset += sequence_length;
2928         }
2929
2930
2931
2932       /*
2933        * Now just fall through to the NO_EXCEPTION part
2934        * as this is common .
2935        */
2936       
2937
2938
2939     case NO_EXCEPTION:
2940
2941
2942       /* lookup MFN in hash directly */
2943  
2944       mfn = get_mfn_from_fn(pinfo->fd->num); 
2945       
2946       if (mfn == pinfo->fd->num)
2947         return;                 /* no matching frame number, what am I */
2948
2949       /* get entry for this MFN */
2950       entry = find_fn_in_list(mfn); /* get data entry in complete_request_list */
2951
2952       if (!entry)
2953         return;                 /* no matching entry */
2954         
2955
2956       /*
2957        * If this packet is a REPLY to a RESOLVE(request) 
2958        * then decode IOR.
2959        * TODO - make this lookup faster -- FS
2960        */
2961       
2962       if (!strcmp(giop_op_resolve,entry->operation)) {
2963         decode_IOR(tvb, pinfo, tree, &offset, GIOP_HEADER_SIZE,stream_is_big_endian);
2964         return;         /* done */
2965       }
2966       
2967       /* TODO -- Put stuff here for other "interesting operations" */
2968
2969       /*
2970        *
2971        * Call sub dissector.
2972        * First try an find a explicit sub_dissector, then if that
2973        * fails, try the heuristic method.
2974        */
2975
2976
2977       if(entry->repoid) {    
2978         exres = try_explicit_giop_dissector(tvb,pinfo,clnp_tree, &offset, header, entry->operation, entry->repoid );
2979       }
2980
2981       /* Only call heuristic if no explicit dixxector was found */
2982
2983       if(! exres) {
2984         try_heuristic_giop_dissector(tvb,pinfo,clnp_tree,&offset,header,entry->operation);
2985       } 
2986
2987
2988       break;
2989       
2990     case LOCATION_FORWARD:
2991       g_warning("giop: We don't yet dissect LOCATION_FORWARD\n");
2992
2993       break;
2994
2995     case LOCATION_FORWARD_PERM:
2996       g_warning("giop: We don't yet dissect LOCATION_FORWARD_PERM\n");
2997
2998       break;
2999
3000     case NEEDS_ADDRESSING_MODE:
3001       g_warning("giop: We don't yet dissect NEEDS_ADDRESSING_MODE\n");
3002
3003       break;
3004
3005     default:
3006       
3007       g_warning("giop: Unknown reply status %i request_id = %u\n",reply_status, header->req_id);
3008       
3009       break;
3010       
3011     } /* switch */
3012   
3013   g_free(repoid);               /* free resource */
3014   
3015   return;                       /* done */
3016   
3017 }
3018
3019
3020
3021
3022
3023 /* The format of the Reply Header for GIOP 1.0 and 1.1
3024  * is documented in Section 15.4.3.1 of the CORBA 2.4 standard.
3025
3026     struct ReplyHeader_1_0 {
3027           IOP::ServiceContextList service_context;
3028           unsigned long request_id;
3029           ReplyStatusType_1_0 reply_status;
3030     };
3031  */
3032
3033 static void dissect_giop_reply (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
3034                                 proto_tree * clnp_tree, MessageHeader * header,
3035                                 gboolean stream_is_big_endian) {
3036
3037   guint32 offset = 0;
3038   guint32 request_id;
3039   guint32 reply_status;
3040   proto_tree *reply_tree = NULL;
3041   proto_item *tf;
3042   guint32 mfn;                  /* matching frame number */
3043
3044   if (tree) {
3045     tf = proto_tree_add_text (tree, tvb, offset,
3046                               tvb_length (tvb),
3047                               "General Inter-ORB Protocol Reply");
3048     if (reply_tree == NULL)
3049       {
3050         reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
3051         
3052       }
3053   }
3054   
3055   /*
3056    * Decode IOP::ServiceContextList
3057    */
3058   
3059   decode_ServiceContextList(tvb, pinfo, reply_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3060
3061   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3062
3063   if (check_col(pinfo->fd, COL_INFO)) {
3064     col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3065   }
3066
3067   if (tree) {
3068     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3069                          "Request id: %u", request_id);
3070   }
3071
3072   reply_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3073
3074   if (check_col(pinfo->fd, COL_INFO)) {
3075     col_append_fstr(pinfo->fd, COL_INFO, ": %s",
3076                     val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3077
3078   }
3079
3080   if (tree) {
3081     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3082                          "Reply status: %s",
3083                          val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3084     
3085   }
3086
3087   /*
3088    * Save FN and MFN in complete_reply_hash, only if user is NOT clicking
3089    */
3090
3091   if (! pinfo->fd->flags.visited) {
3092     mfn = get_mfn_from_fn_and_reqid(pinfo->fd->num,request_id); /* find MFN for this FN */
3093     if (mfn != pinfo->fd->num) { /* if mfn is not fn, good */
3094       insert_in_complete_reply_hash(pinfo->fd->num, mfn);
3095     }
3096   }
3097
3098   header->req_id = request_id;          /* save for sub dissector */
3099   header->rep_status = reply_status;   /* save for sub dissector */
3100
3101   dissect_reply_body(tvb, offset, pinfo, reply_tree, stream_is_big_endian,
3102     reply_status, header,tree);
3103
3104
3105 }
3106
3107 /** The format of the GIOP 1.2 Reply header is very similar to the 1.0
3108  *  and 1.1 header, only the fields have been rearranged.  From Section
3109  *  15.4.3.1 of the CORBA 2.4 specification:
3110  *
3111  *   struct ReplyHeader_1_2 {
3112  *         unsigned long request_id;
3113  *         ReplyStatusType_1_2 reply_status;
3114  *         IOP:ServiceContextList service_context; 
3115  *    };
3116  */
3117
3118 static void dissect_giop_reply_1_2 (tvbuff_t * tvb, packet_info * pinfo,
3119                                     proto_tree * tree, proto_tree * clnp_tree,
3120                                     MessageHeader * header,
3121                                     gboolean stream_is_big_endian) {
3122
3123   u_int offset = 0;
3124   guint32 request_id;
3125   guint32 reply_status;
3126   proto_tree *reply_tree = NULL;
3127   proto_item *tf;
3128   guint32 mfn;                  /* matching frame number */
3129   
3130   if (tree) {
3131     tf = proto_tree_add_text (tree, tvb, offset,
3132                               tvb_length (tvb),
3133                               "General Inter-ORB Protocol Reply");
3134     reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
3135   }
3136   
3137   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3138   
3139   if (check_col(pinfo->fd, COL_INFO)) {
3140     col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3141   }
3142
3143   if (tree) {
3144     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3145                          "Request id: %u", request_id);
3146   }
3147
3148   reply_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3149   
3150   if (check_col(pinfo->fd, COL_INFO)) {
3151     col_append_fstr(pinfo->fd, COL_INFO, ": %s",
3152                     val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3153
3154   }
3155
3156   if (tree) {
3157     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3158                          "Reply status: %s",
3159                          val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3160
3161   }
3162
3163   /*
3164    * Decode IOP::ServiceContextList
3165    */
3166
3167   decode_ServiceContextList(tvb, pinfo, reply_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3168
3169   /*
3170    * GIOP 1.2 Reply body must fall on an 8 octet alignment.
3171    */
3172
3173   set_new_alignment(&offset, GIOP_HEADER_SIZE, 8);
3174
3175   /*
3176    * Save FN and MFN in complete_reply_hash, only if user is NOT clicking
3177    */
3178   
3179   if (! pinfo->fd->flags.visited) {
3180     mfn = get_mfn_from_fn_and_reqid(pinfo->fd->num,request_id); /* find MFN for this FN */
3181     if (mfn != pinfo->fd->num) { /* if mfn is not fn, good */
3182       insert_in_complete_reply_hash(pinfo->fd->num, mfn);
3183     }
3184   }
3185
3186   /*
3187    * Add header to argument list so sub dissector can get header info.
3188    */
3189
3190   header->req_id = request_id;          /* save for sub dissector */
3191   header->rep_status = reply_status;   /* save for sub dissector */
3192
3193   dissect_reply_body(tvb, offset, pinfo, reply_tree, stream_is_big_endian,
3194                      reply_status,header,tree);
3195
3196 }
3197
3198
3199
3200 static void dissect_giop_cancel_request (tvbuff_t * tvb, packet_info * pinfo,
3201                         proto_tree * tree, proto_tree * clnp_tree,
3202                         MessageHeader * header, gboolean stream_is_big_endian) {
3203
3204   u_int offset = 0;
3205   guint32 request_id;
3206   proto_tree *cancel_request_tree = NULL;
3207   proto_item *tf;
3208
3209   if (tree) {
3210     tf = proto_tree_add_text (tree, tvb, offset,
3211                               tvb_length (tvb),
3212                               "General Inter-ORB Protocol CancelRequest");
3213     cancel_request_tree = proto_item_add_subtree (tf, ett_giop_cancel_request);
3214   }
3215
3216   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3217   
3218   if (check_col(pinfo->fd, COL_INFO)) {
3219     col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3220   }
3221
3222   if (tree) {
3223     proto_tree_add_text (cancel_request_tree, tvb, offset-4, 4,
3224                          "Request id: %u", request_id);
3225   }
3226
3227   
3228 }
3229
3230 /**  The formats for GIOP 1.0 and 1.1 Request messages are defined
3231  *   in section 15.4.2.1 of the CORBA 2.4 specification.
3232  *
3233  *   struct RequestHeader{
3234  *          IOP::ServiceContextList   service_context;
3235  *          unsigned long             request_id;
3236  *          boolean                   response_expected;
3237  *          octet                     reserved[3];  // Only in GIOP 1.1
3238  *          sequence<octet>           object_key;
3239  *          string                    operation;
3240  *          CORBA::OctetSeq           requesting_principal;
3241  *   }
3242  */
3243 static void
3244 dissect_giop_request_1_1 (tvbuff_t * tvb, packet_info * pinfo,
3245                         proto_tree * tree, proto_tree * clnp_tree,
3246                         MessageHeader * header, gboolean stream_is_big_endian)
3247 {
3248   guint32 offset = 0;
3249   guint32 request_id;
3250   guint32 len = 0;
3251
3252   guint32 objkey_len = 0;       /* object key length */
3253   gchar *objkey = NULL;         /* object key sequence */
3254   gchar *print_objkey = NULL;   /* printable object key sequence */
3255   gboolean exres = FALSE;               /* result of trying explicit dissectors */
3256
3257   gchar *operation = NULL;
3258   gchar *requesting_principal = NULL;
3259   gchar *print_requesting_principal = NULL;
3260   guint8 response_expected;
3261   gchar *reserved = NULL;
3262   proto_tree *request_tree = NULL;
3263   proto_item *tf;
3264
3265   gchar *repoid = NULL;         /* from object key lookup in objkey hash */
3266
3267
3268   if (tree)
3269     {
3270       tf = proto_tree_add_text (tree, tvb, offset,
3271                                 tvb_length (tvb),
3272                                 "General Inter-ORB Protocol Request");
3273       if (request_tree == NULL)
3274         {
3275           request_tree = proto_item_add_subtree (tf, ett_giop_request);
3276
3277         }
3278     }
3279
3280
3281
3282
3283   /*
3284    * Decode IOP::ServiceContextList
3285    */
3286   
3287   decode_ServiceContextList(tvb, pinfo, request_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3288
3289
3290   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3291   if (check_col(pinfo->fd, COL_INFO))
3292     {
3293       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3294     }
3295   if (tree)
3296     {
3297       proto_tree_add_text (request_tree, tvb, offset-4, 4,
3298                            "Request id: %u", request_id);
3299     }
3300
3301   response_expected = tvb_get_guint8( tvb, offset );
3302   offset += 1;
3303   if (check_col(pinfo->fd, COL_INFO))
3304     {
3305       col_append_fstr(pinfo->fd, COL_INFO, " (%s)",
3306                 response_expected ? "two-way" : "one-way");
3307     }
3308   if (tree)
3309     {
3310       proto_tree_add_text (request_tree, tvb, offset-1, 1,
3311                            "Response expected: %u", response_expected);
3312     }
3313
3314   if( header->GIOP_version.minor > 0)
3315   {
3316      get_CDR_octet_seq( tvb, &reserved, &offset, 3);
3317      if (tree)
3318        {
3319          proto_tree_add_text (request_tree, tvb, offset-3, 3,
3320                            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
3321        }
3322   }
3323
3324
3325
3326   /* Length of object_key sequence */
3327   objkey_len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3328
3329
3330   if(tree)
3331   {
3332          proto_tree_add_text (request_tree, tvb, offset-4, 4,
3333          /**/                 "Object Key length: %u", objkey_len);
3334   } 
3335
3336   if (objkey_len > 0)
3337   {
3338        get_CDR_octet_seq(tvb, &objkey, &offset, objkey_len);
3339
3340        print_objkey = make_printable_string(objkey, objkey_len);
3341
3342        if(tree)
3343        {
3344          proto_tree_add_text (request_tree, tvb, offset - objkey_len, objkey_len,
3345          /**/                 "Object Key: %s", print_objkey);
3346
3347        }
3348   } 
3349
3350   /* length of operation string and string */ 
3351   len = get_CDR_string(tvb, &operation, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3352   if(tree)
3353   {
3354          proto_tree_add_text (request_tree, tvb, offset - 4 - len, 4,
3355          /**/                 "Operation length: %u", len);
3356   } 
3357
3358   if( len > 0)
3359   {
3360        if (check_col(pinfo->fd, COL_INFO))
3361        {
3362          col_append_fstr(pinfo->fd, COL_INFO, ": %s", operation);
3363        }
3364        if(tree)
3365        {
3366          proto_tree_add_text (request_tree, tvb, offset - len, len,
3367          /**/                 "Operation: %s", operation);
3368
3369        }
3370   }
3371
3372   /* length of requesting_principal string */ 
3373   len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3374   if(tree)
3375   {
3376          proto_tree_add_text (request_tree, tvb, offset-4, 4,
3377          /**/                 "Requesting Principal Length: %u", len);
3378   } 
3379
3380   if( len > 0)
3381   {
3382        get_CDR_octet_seq(tvb, &requesting_principal, &offset, len);
3383
3384        print_requesting_principal = make_printable_string(requesting_principal, len);
3385
3386        if(tree)
3387        {
3388          proto_tree_add_text (request_tree, tvb, offset - len, len, 
3389          /**/                 "Requesting Principal: %s", print_requesting_principal);
3390
3391        }
3392   }
3393
3394
3395   /*
3396    * Save FN,reqid,and operation for later. Add sub_handle later.
3397    * But only if user is NOT clicking.
3398    */
3399
3400   if (! pinfo->fd->flags.visited)
3401     giop_complete_request_list = insert_in_comp_req_list(giop_complete_request_list,pinfo->fd->num,
3402                                                          request_id,operation,NULL);
3403
3404   
3405   /*
3406    * Call subdissector here before freeing "operation" and "key"
3407    * pass request_id also. 
3408    * First try an find an explicit sub_dissector, then if that
3409    * fails, try the heuristic method.
3410    *
3411    */
3412
3413
3414   header->req_id = request_id;          /* save for sub dissector */
3415   repoid = get_repoid_from_objkey(giop_objkey_hash,objkey,objkey_len);
3416
3417
3418   if(repoid) {    
3419     exres = try_explicit_giop_dissector(tvb,pinfo,tree,&offset,header,operation,repoid);
3420   }
3421
3422   /* Only call heuristic if no explicit dissector was found */
3423
3424   if (! exres) {
3425     try_heuristic_giop_dissector(tvb,pinfo,tree,&offset,header,operation);
3426   }
3427   
3428
3429   g_free( print_objkey );  
3430   g_free( objkey );
3431   g_free( operation );
3432   g_free( requesting_principal );
3433   g_free( print_requesting_principal );
3434
3435 }
3436
3437 /**  The format of a GIOP 1.2 RequestHeader message is 
3438  *   (CORBA 2.4, sec. 15.4.2):
3439  *
3440  *   struct RequestHeader_1_2 {
3441  *       unsigned long request_id;
3442  *       octet response_flags;
3443  *       octet reserved[3];
3444  *       TargetAddress target;
3445  *       string operation;
3446  *       IOP::ServiceContextList service_context;
3447  *       // requesting_principal not in GIOP 1.2
3448  *   };
3449  */
3450 static void
3451 dissect_giop_request_1_2 (tvbuff_t * tvb, packet_info * pinfo,
3452                         proto_tree * tree, proto_tree * clnp_tree,
3453                         MessageHeader * header, gboolean stream_is_big_endian)
3454 {
3455   guint32 offset = 0;
3456   guint32 request_id;
3457   guint32 len = 0;
3458   guint8 response_flags;
3459   gchar *reserved = NULL;
3460   gchar *operation = NULL;
3461   proto_tree *request_tree = NULL;
3462   proto_item *tf;
3463   gboolean exres = FALSE;               /* result of trying explicit dissectors */
3464
3465   gchar *repoid = NULL;
3466
3467
3468   if (tree)
3469     {
3470       tf = proto_tree_add_text (tree, tvb, offset,
3471                                 tvb_length (tvb),
3472                                 "General Inter-ORB Protocol Request");
3473       request_tree = proto_item_add_subtree (tf, ett_giop_reply);
3474     }
3475
3476   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3477   if (check_col(pinfo->fd, COL_INFO))
3478     {
3479       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3480     }
3481   if (request_tree)
3482     {
3483       proto_tree_add_text (request_tree, tvb, offset-4, 4,
3484                            "Request id: %u", request_id);
3485     }
3486
3487   response_flags = tvb_get_guint8( tvb, offset );
3488   offset += 1;
3489   if (request_tree)
3490     {
3491       proto_tree_add_text (request_tree, tvb, offset-1, 1,
3492                            "Response flags: %s (%u)",
3493                                 match_strval(response_flags, sync_scope),  
3494                                 response_flags);
3495     }
3496
3497   get_CDR_octet_seq( tvb, &reserved, &offset, 3);
3498   if (request_tree)
3499    {
3500      proto_tree_add_text (request_tree, tvb, offset-3, 3,
3501            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
3502    }
3503
3504   dissect_target_address(tvb, pinfo, &offset, request_tree, header, stream_is_big_endian);
3505
3506   /* length of operation string */ 
3507   len = get_CDR_string(tvb, &operation, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3508   if(tree)
3509   {
3510          proto_tree_add_text (request_tree, tvb, offset - len - 4, 4,
3511          /**/                 "Operation length: %u", len);
3512   } 
3513
3514   if( len > 0)
3515   {
3516        if (check_col(pinfo->fd, COL_INFO))
3517        {
3518          col_append_fstr(pinfo->fd, COL_INFO, ": %s", operation);
3519        }
3520        if(request_tree)
3521        {
3522          proto_tree_add_text (request_tree, tvb, offset - len, len,
3523          /**/                 "Operation: %s", operation);
3524
3525        }
3526
3527   }
3528
3529   /*
3530    * Decode IOP::ServiceContextList
3531    */
3532
3533   decode_ServiceContextList(tvb, pinfo, request_tree, &offset,  stream_is_big_endian, GIOP_HEADER_SIZE);
3534
3535   /*
3536    * GIOP 1.2 Request body must fall on an 8 octet alignment, taking into
3537    * account we are in a new tvbuff, GIOP_HEADER_SIZE octets from the
3538    * GIOP octet stream start.
3539    */
3540
3541   set_new_alignment(&offset, GIOP_HEADER_SIZE, 8);
3542
3543   /*
3544    * Save FN,reqid,and operation for later. Add sub_handle later.
3545    * But only if user is NOT clicking.
3546    */
3547   
3548   if (! pinfo->fd->flags.visited)
3549     giop_complete_request_list = insert_in_comp_req_list(giop_complete_request_list,pinfo->fd->num,
3550                                                          request_id,operation,NULL);
3551
3552   /*
3553    *
3554    * Call sub dissector.
3555    * First try an find a explicit sub_dissector, then if that
3556    * fails, try the heuristic method.
3557    */
3558   
3559
3560   if(repoid) {    
3561     exres = try_explicit_giop_dissector(tvb,pinfo,tree,&offset,header,operation,repoid);
3562   }
3563
3564   /* Only call heuristic if no explicit dissector was found */
3565
3566   if (! exres) {
3567     try_heuristic_giop_dissector(tvb,pinfo,tree,&offset,header,operation);
3568   }
3569   
3570
3571
3572   g_free(operation);
3573   g_free(reserved);
3574 }
3575
3576 static void
3577 dissect_giop_locate_request( tvbuff_t * tvb, packet_info * pinfo,
3578                         proto_tree * tree, MessageHeader * header,
3579                         gboolean stream_is_big_endian)
3580 {
3581   guint32 offset = 0;
3582   guint32 request_id;
3583   guint32 len = 0;
3584   gchar *object_key = NULL;
3585   gchar *p_object_key = NULL;
3586   proto_tree *locate_request_tree = NULL;
3587   proto_item *tf;
3588
3589   if (tree)
3590     {
3591       tf = proto_tree_add_text (tree, tvb, offset,
3592                                 tvb_length (tvb),
3593                                 "General Inter-ORB Locate Request");
3594       if (locate_request_tree == NULL)
3595         {
3596           locate_request_tree = proto_item_add_subtree (tf, ett_giop_locate_request);
3597
3598         }
3599     }
3600
3601   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3602   if (check_col(pinfo->fd, COL_INFO))
3603     {
3604       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3605     }
3606   if (locate_request_tree)
3607     {
3608       proto_tree_add_text (locate_request_tree, tvb, offset-4, 4,
3609                            "Request id: %u", request_id);
3610     }
3611
3612   if(header->GIOP_version.minor < 2)
3613   {
3614         len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3615         if (locate_request_tree)
3616           {
3617             proto_tree_add_text (locate_request_tree, tvb, offset-4, 4,
3618                                  "Object Key length: %u", len);
3619           }
3620
3621         if (len > 0) {
3622           get_CDR_octet_seq(tvb, &object_key, &offset, len);
3623
3624           p_object_key = make_printable_string(object_key, len);
3625   
3626           if(locate_request_tree)
3627             {
3628
3629               proto_tree_add_text (locate_request_tree, tvb, offset-len, len,
3630                                    "Object Key: %s", p_object_key);
3631             }
3632         }
3633   }
3634   else     /* GIOP 1.2 and higher */
3635   {
3636       dissect_target_address(tvb, pinfo, &offset, locate_request_tree, header,
3637                              stream_is_big_endian);
3638
3639   }
3640   g_free(object_key);  
3641   g_free(p_object_key);  
3642 }
3643
3644 static void
3645 dissect_giop_locate_reply( tvbuff_t * tvb, packet_info * pinfo,
3646                         proto_tree * tree, MessageHeader * header,
3647                         gboolean stream_is_big_endian)
3648 {
3649   guint32 offset = 0;
3650   guint32 request_id;
3651   guint32 locate_status;
3652   guint16 addr_disp;
3653
3654   proto_tree *locate_reply_tree = NULL;
3655   proto_item *tf;
3656
3657   if (tree)
3658     {
3659       tf = proto_tree_add_text (tree, tvb, offset,
3660                                 tvb_length (tvb),
3661                                 "General Inter-ORB Locate Reply");
3662       if (locate_reply_tree == NULL)
3663         {
3664           locate_reply_tree = proto_item_add_subtree (tf, ett_giop_locate_reply);
3665
3666         }
3667     }
3668
3669   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3670   if (check_col(pinfo->fd, COL_INFO))
3671     {
3672       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3673     }
3674   if (locate_reply_tree)
3675     {
3676       proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
3677                            "Request id: %u", request_id);
3678     }
3679
3680   locate_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3681   if (locate_reply_tree)
3682     {
3683       proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
3684                            "Locate status: %s", 
3685                            match_strval(locate_status, giop_locate_status_types)
3686                            );
3687     }
3688
3689   /* Decode the LocateReply body.
3690    *
3691    * For GIOP 1.0 and 1.1 body immediately follows header.
3692    * For GIOP 1.2 it is aligned on 8 octet boundary so need to
3693    * spin up.
3694    */
3695
3696   if (header->GIOP_version.minor > 1) {
3697     while( ( (offset + GIOP_HEADER_SIZE) % 8) != 0)
3698       ++(offset);
3699   }
3700
3701   switch(locate_status) {
3702   case OBJECT_FORWARD: /* fall through to OBJECT_FORWARD_PERM */
3703   case OBJECT_FORWARD_PERM:
3704     decode_IOR(tvb, pinfo, locate_reply_tree, &offset, GIOP_HEADER_SIZE, stream_is_big_endian);
3705     break;
3706   case LOC_SYSTEM_EXCEPTION:
3707     decode_SystemExceptionReplyBody (tvb, tree, &offset, stream_is_big_endian, GIOP_HEADER_SIZE);
3708     break;
3709   case LOC_NEEDS_ADDRESSING_MODE:
3710     addr_disp = get_CDR_ushort(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3711     if(locate_reply_tree) {
3712       proto_tree_add_text (tree, tvb, offset -2, 2,
3713                            "AddressingDisposition: %u", addr_disp);
3714     }
3715     break;
3716   default: /* others have no reply body */
3717     break;
3718   }
3719
3720 }
3721
3722 static void
3723 dissect_giop_fragment( tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
3724                         MessageHeader * header, gboolean stream_is_big_endian)
3725 {
3726   guint32 offset = 0;
3727   guint32 request_id;
3728   proto_tree *fragment_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 Fragment");
3736       if (fragment_tree == NULL)
3737         {
3738           fragment_tree = proto_item_add_subtree (tf, ett_giop_fragment);
3739
3740         }
3741     }
3742
3743   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3744   if (check_col(pinfo->fd, COL_INFO))
3745     {
3746       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3747     }
3748   if (fragment_tree )
3749     {
3750       proto_tree_add_text (fragment_tree, tvb, offset-4, 4,
3751                            "Request id: %u", request_id);
3752     }
3753                                    
3754 }
3755
3756
3757 /* Main entry point */
3758
3759 gboolean dissect_giop (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) {
3760   u_int offset = 0;
3761   MessageHeader header;
3762   tvbuff_t *giop_header_tvb;
3763   tvbuff_t *payload_tvb;
3764
3765   proto_tree *clnp_tree = NULL;
3766   proto_item *ti;
3767   u_int message_size;
3768   u_int minor_version;
3769   gboolean stream_is_big_endian;
3770
3771
3772   /* DEBUG */
3773   
3774 #if DEBUG
3775   giop_dump_collection(cd_module_hash);
3776   giop_dump_collection(cd_objkey_hash);
3777   giop_dump_collection(cd_heuristic_users);
3778   giop_dump_collection(cd_complete_reply_hash);
3779   giop_dump_collection(cd_complete_request_list);
3780 #endif
3781
3782   header.exception_id = NULL;
3783
3784   /* check magic number and version */
3785
3786
3787   /*define END_OF_GIOP_MESSAGE (offset - first_offset - GIOP_HEADER_SIZE) */
3788
3789   if (tvb_length_remaining(tvb, 0) < GIOP_HEADER_SIZE)
3790     {
3791       /* Not enough data captured to hold the GIOP header; don't try
3792          to interpret it as GIOP. */
3793       return FALSE;
3794     }
3795
3796   giop_header_tvb = tvb_new_subset (tvb, 0, GIOP_HEADER_SIZE, -1);
3797   payload_tvb = tvb_new_subset (tvb, GIOP_HEADER_SIZE, -1, -1);
3798   
3799   /*
3800    * because I have added extra elements in MessageHeader struct
3801    * for sub dissectors. -- FS
3802    */
3803
3804   tvb_memcpy (giop_header_tvb, (guint8 *)&header, 0, GIOP_HEADER_SIZE );
3805
3806   if (memcmp (header.magic, GIOP_MAGIC, sizeof (header.magic)) != 0)
3807     {
3808       /* Not a GIOP message. */
3809
3810       return FALSE;
3811     }
3812
3813   if (check_col (pinfo->fd, COL_PROTOCOL))
3814     {
3815       col_set_str (pinfo->fd, COL_PROTOCOL, "GIOP");
3816     }
3817
3818   if (header.GIOP_version.major != GIOP_MAJOR ||
3819       ((minor_version = header.GIOP_version.minor) > GIOP_MINOR))
3820     {
3821       /* Bad version number; should we note that and dissect the rest
3822          as data, or should we return FALSE on the theory that it
3823          might have been some other packet that happened to begin with
3824          "GIOP"?  We shouldn't do *both*, so we return TRUE, for now.
3825          If we should return FALSE, we should do so *without* setting
3826          the "Info" column, *without* setting the "Protocol" column,
3827          and *without* adding anything to the protocol tree. */
3828
3829       if (check_col (pinfo->fd, COL_INFO))
3830         {
3831           col_add_fstr (pinfo->fd, COL_INFO, "Version %u.%u",
3832                         header.GIOP_version.major, header.GIOP_version.minor);
3833         }
3834       if (tree)
3835         {
3836           ti = proto_tree_add_item (tree, proto_giop, tvb, 0,
3837                                     tvb_length (tvb), FALSE);
3838           clnp_tree = proto_item_add_subtree (ti, ett_giop);
3839           proto_tree_add_text (clnp_tree, giop_header_tvb, 0,
3840                                tvb_length (giop_header_tvb),
3841                                "Version %u.%u not supported",
3842                                header.GIOP_version.major,
3843                                header.GIOP_version.minor);
3844         }
3845       dissect_data (payload_tvb, 0, pinfo, tree);
3846       return TRUE;
3847     }
3848
3849   if (check_col (pinfo->fd, COL_INFO)) 
3850   { 
3851       col_add_fstr (pinfo->fd, COL_INFO, "GIOP %u.%u %s",
3852                     header.GIOP_version.major, header.GIOP_version.minor,
3853                     val_to_str(header.message_type, giop_message_types,
3854                                "Unknown message type (0x%02x)"));
3855   }
3856
3857   stream_is_big_endian = is_big_endian (&header);
3858
3859   if (stream_is_big_endian)
3860     message_size = pntohl (&header.message_size);
3861   else
3862     message_size = pletohl (&header.message_size);
3863
3864   if (tree)
3865     {
3866       ti = proto_tree_add_item (tree, proto_giop, tvb, 0, 12, FALSE);
3867       clnp_tree = proto_item_add_subtree (ti, ett_giop);
3868       proto_tree_add_text (clnp_tree, giop_header_tvb, offset, 4,
3869                            "Magic number: %s", GIOP_MAGIC);
3870       proto_tree_add_text (clnp_tree, giop_header_tvb, 4, 2,
3871                            "Version: %u.%u",
3872                            header.GIOP_version.major,
3873                            header.GIOP_version.minor);
3874       switch (minor_version)
3875         {
3876         case 2:
3877         case 1:
3878           proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
3879                                "Flags: 0x%02x (%s %s)",
3880                                header.flags,
3881                                (stream_is_big_endian) ? "big-endian" : "little-endian",
3882                                (header.flags & 0x02) ? " fragment" : "");
3883           break;
3884         case 0:
3885           proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
3886                                "Byte ordering: %s-endian",
3887                                (stream_is_big_endian) ? "big" : "little");
3888           break;
3889         default:
3890           break;
3891         }                       /* minor_version */
3892
3893       proto_tree_add_uint_format (clnp_tree,
3894                                   hf_giop_message_type,
3895                                   giop_header_tvb, 7, 1,
3896                                   header.message_type,
3897                                   "Message type: %s", match_strval(header.message_type, giop_message_types));
3898
3899       proto_tree_add_uint (clnp_tree,
3900                            hf_giop_message_size,
3901                            giop_header_tvb, 8, 4, message_size);
3902
3903     }                           /* tree */
3904
3905 #if 0
3906   if (check_col (pinfo->fd, COL_INFO)) 
3907   { 
3908       col_add_fstr (pinfo->fd, COL_INFO, "GIOP %u.%u %s",
3909                     header.GIOP_version.major, header.GIOP_version.minor,
3910                     match_strval(header.message_type, giop_message_types));
3911   }
3912 #endif
3913
3914   switch (header.message_type)
3915     {
3916
3917     case Request:
3918       if(header.GIOP_version.minor < 2)
3919       {
3920            dissect_giop_request_1_1 (payload_tvb, pinfo, tree, clnp_tree,
3921                                      &header, stream_is_big_endian);
3922       }
3923       else
3924       {    
3925            dissect_giop_request_1_2 (payload_tvb, pinfo, tree, clnp_tree,
3926                                      &header, stream_is_big_endian);
3927       }
3928       
3929       break;
3930
3931
3932     case Reply:
3933       if(header.GIOP_version.minor < 2)
3934         {
3935            dissect_giop_reply (payload_tvb, pinfo, tree, clnp_tree, &header,
3936                                stream_is_big_endian);
3937         }
3938       else
3939         {
3940            dissect_giop_reply_1_2 (payload_tvb, pinfo, tree, clnp_tree,
3941                                    &header, stream_is_big_endian);
3942         }
3943       break;
3944     case CancelRequest:
3945         dissect_giop_cancel_request(payload_tvb, pinfo, tree, clnp_tree,
3946                                     &header, stream_is_big_endian);
3947         break;
3948     case LocateRequest:
3949         dissect_giop_locate_request(payload_tvb, pinfo, tree, &header,
3950                                     stream_is_big_endian);
3951         break;
3952     case LocateReply:
3953         dissect_giop_locate_reply(payload_tvb, pinfo, tree, &header,
3954                                   stream_is_big_endian);
3955         break;
3956     case Fragment:
3957         dissect_giop_fragment(payload_tvb, pinfo, tree, &header,
3958                               stream_is_big_endian);
3959         break;  
3960     default:
3961       break;
3962
3963     }                           /* switch message_type */
3964
3965
3966
3967
3968     return TRUE;
3969 }
3970
3971 void
3972 proto_register_giop (void)
3973 {
3974   static hf_register_info hf[] = {
3975     { &hf_giop_message_type,
3976      { "Message type", "giop.type",
3977        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
3978     },
3979     
3980     { &hf_giop_message_size,
3981       { "Message size", "giop.len",
3982         FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
3983     },
3984
3985     { &hf_giop_repoid,
3986      { "Repository ID", "giop.repoid",
3987        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
3988     },
3989
3990     { &hf_giop_string_length,
3991      { "String Length", "giop.strlen",
3992        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
3993     },
3994
3995     { &hf_giop_sequence_length,
3996      { "Sequence Length", "giop.seqlen",
3997        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
3998     },
3999
4000     { &hf_giop_profile_id,
4001      { "Profile ID", "giop.profid",
4002        FT_UINT32, BASE_DEC, VALS(profile_id_vals), 0x0, "", HFILL }
4003     },
4004
4005
4006     { &hf_giop_type_id,
4007      { "IOR::type_id", "giop.typeid",
4008        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4009     },
4010
4011     { &hf_giop_iiop_v_maj,
4012      { "IIOP Major Version", "giop.iiop_vmaj",
4013        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4014     }
4015     ,
4016     { &hf_giop_iiop_v_min,
4017      { "IIOP Minor Version", "giop.iiop_vmin",
4018        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4019     },
4020
4021     { &hf_giop_endianess,
4022      { "Endianess", "giop.endianess",
4023        FT_UINT8, BASE_DEC, VALS(giop_endianess_vals), 0x0, "", HFILL }
4024     },
4025
4026     { &hf_giop_IIOP_tag,
4027      { "IIOP Component TAG", "giop.iioptag",
4028        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4029     },
4030
4031     { &hf_giop_IOR_tag,
4032      { "IOR Profile TAG", "giop.iortag",
4033        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4034     },
4035
4036     { &hf_giop_TCKind,
4037      { "TypeCode enum", "giop.TCKind",
4038        FT_UINT32, BASE_DEC, VALS(tckind_vals), 0x0, "", HFILL }
4039     },
4040
4041     { &hf_giop_typecode_count,
4042      { "TypeCode count", "giop.tccount",
4043        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4044     },
4045
4046     { &hf_giop_typecode_default_used,
4047      { "default_used", "giop.tcdefault_used",
4048        FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL }
4049     },
4050
4051     { &hf_giop_typecode_digits,
4052      { "Digits", "giop.tcdigits",
4053        FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
4054     },
4055
4056
4057     { &hf_giop_typecode_length,
4058      { "Length", "giop.tclength",
4059        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4060     },
4061
4062     { &hf_giop_typecode_max_length,
4063      { "Maximum length", "giop.tcmaxlen",
4064        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4065     },
4066
4067     { &hf_giop_typecode_member_name,
4068      { "TypeCode member name", "giop.tcmemname",
4069        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4070     },
4071
4072     { &hf_giop_typecode_name,
4073      { "TypeCode name", "giop.tcname",
4074        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4075     },
4076
4077     { &hf_giop_typecode_scale,
4078      { "Scale", "giop.tcscale",
4079        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4080     },
4081
4082     { &hf_giop_typecode_ValueModifier,
4083      { "ValueModifier", "giop.tcValueModifier",
4084        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4085     },
4086
4087     { &hf_giop_typecode_Visibility,
4088      { "Visibility", "giop.tcVisibility",
4089        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4090     },
4091
4092
4093
4094     { &hf_giop_type_boolean,
4095       { "TypeCode boolean data", "giop.tcboolean",
4096         FT_BOOLEAN, BASE_DEC,  NULL, 0x0, "", HFILL }
4097     },
4098
4099     { &hf_giop_type_char,
4100       { "TypeCode char data", "giop.tcchar",
4101         FT_UINT8, BASE_DEC,  NULL, 0x0, "", HFILL }
4102     },
4103
4104     { &hf_giop_type_double,
4105       { "TypeCode double data", "giop.tcdouble",
4106         FT_DOUBLE, BASE_DEC,  NULL, 0x0, "", HFILL }
4107     },
4108
4109     { &hf_giop_type_enum,
4110      { "TypeCode enum data", "giop.tcenumdata",
4111        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4112     },
4113
4114     /*
4115      * float as double ?? -- FIX
4116      */
4117
4118     { &hf_giop_type_float,
4119       { "TypeCode float data", "giop.tcfloat",
4120         FT_DOUBLE, BASE_DEC,  NULL, 0x0, "", HFILL }
4121     },
4122
4123     { &hf_giop_type_long,
4124      { "TypeCode long data", "giop.tclongdata",
4125        FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL }
4126     },
4127
4128     { &hf_giop_type_octet,
4129       { "TypeCode octet data", "giop.tcoctet",
4130         FT_UINT8, BASE_DEC,  NULL, 0x0, "", HFILL }
4131     },
4132
4133     { &hf_giop_type_short,
4134      { "TypeCode short data", "giop.tcshortdata",
4135        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4136     },
4137
4138     { &hf_giop_type_string,
4139       { "TypeCode string data", "giop.tcstring",
4140         FT_STRING, BASE_DEC,  NULL, 0x0, "", HFILL }
4141     },
4142
4143     { &hf_giop_type_ulong,
4144      { "TypeCode ulong data", "giop.tculongdata",
4145        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4146     },
4147
4148     { &hf_giop_type_ushort,
4149      { "TypeCode ushort data", "giop.tcushortdata",
4150        FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
4151     },
4152
4153     /*
4154      * IIOP Module - Chapter 15.10.2
4155      */
4156
4157     { &hf_giop_iiop_host,
4158      { "IIOP::Profile_host", "giop.iiop.host",
4159        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4160     }
4161     ,
4162
4163     { &hf_giop_iiop_port,
4164      { "IIOP::Profile_port", "giop.iiop.port",
4165        FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
4166     }
4167     ,
4168
4169     /*
4170      * IIOP ServiceContext
4171      */
4172
4173     { &hf_giop_iop_vscid,
4174      { "VSCID", "giop.iiop.vscid",
4175        FT_UINT32, BASE_HEX, NULL, 0xfffff000, "", HFILL }
4176     }
4177     ,
4178
4179     { &hf_giop_iop_scid,
4180      { "SCID", "giop.iiop.scid",
4181        FT_UINT32, BASE_HEX, NULL, 0x00000fff, "", HFILL }
4182     }
4183     ,
4184
4185
4186   };
4187
4188   static gint *ett[] = {
4189     &ett_giop,
4190     &ett_giop_reply,
4191     &ett_giop_request,
4192     &ett_giop_cancel_request,
4193     &ett_giop_locate_request,
4194     &ett_giop_locate_reply,
4195     &ett_giop_fragment,
4196     &ett_giop_scl,
4197     &ett_giop_ior
4198
4199   };
4200   proto_giop = proto_register_protocol("General Inter-ORB Protocol", "GIOP",
4201                                        "giop");
4202   proto_register_field_array (proto_giop, hf, array_length (hf));
4203   proto_register_subtree_array (ett, array_length (ett));
4204
4205
4206   /* register init routine */
4207
4208   register_init_routine( &giop_init); /* any init stuff */
4209
4210   /*
4211    * Init the giop user module hash tables here, as giop users
4212    * will populate it via register_giop_user_module BEFORE my
4213    * own giop_init() is called.
4214    */
4215
4216   giop_module_hash = g_hash_table_new(giop_hash_module_hash, giop_hash_module_equal);
4217   
4218   giop_module_keys = g_mem_chunk_new("giop_module_keys",
4219                                      sizeof(struct giop_module_key),
4220                                      giop_module_init_count * sizeof(struct giop_module_key), 
4221                                      G_ALLOC_AND_FREE);
4222   
4223   giop_module_vals = g_mem_chunk_new("giop_module_vals", 
4224                                      sizeof(struct giop_module_val),
4225                                      giop_module_init_count * sizeof(struct giop_module_val), 
4226                                      G_ALLOC_AND_FREE);
4227   
4228 }
4229
4230
4231
4232 void proto_reg_handoff_giop (void) {
4233   heur_dissector_add("tcp", dissect_giop, proto_giop);
4234 }
4235
4236
4237
4238
4239 /*
4240  * Decode IOR
4241  *
4242  * Ref Corba v2.4.2 Chapter 13
4243  *
4244  */
4245
4246 /*
4247
4248 module IOP{ 
4249
4250     typedef unsigned long ProfileId;
4251
4252     const ProfileId TAG_INTERNET_IOP = 0;
4253     const ProfileId TAG_MULTIPLE_COMPONENTS = 1;
4254
4255     struct TaggedProfile {
4256       ProfileId tag;
4257       sequence <octet> profile_data;
4258     };
4259
4260     struct IOR {
4261       string type_id;
4262       sequence <TaggedProfile> profiles;
4263     };
4264
4265     typedef unsigned long ComponentId;
4266
4267     struct TaggedComponent {
4268       ComponentId tag;
4269       sequence <octet> component_data;
4270     };
4271
4272     typedef sequence <TaggedComponent> MultipleComponentProfile;
4273
4274 };
4275
4276 */
4277
4278 void decode_IOR(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ptree, int *offset,
4279                 guint32 boundary, gboolean stream_is_big_endian) {
4280
4281
4282   guint32 seqlen_p;             /* sequence length of profiles */
4283   guint32 u_octet4;
4284
4285   proto_tree *tree = NULL;      /* IOR tree */
4286   proto_item *tf;
4287
4288   gchar *repobuf = NULL;        /* for repository ID */
4289
4290   guint32 i;