From Graeme Lunt
[obnox/wireshark/wip.git] / epan / dissectors / packet-ber.c
1 /*#define DEBUG_BER 1 */
2 /* TODO: change #.REGISTER signature to new_dissector_t and
3  * update call_ber_oid_callback() accordingly.
4  *
5  * Since we dont pass the TAG/LENGTH from the CHOICE/SEQUENCE/SEQUENCE OF/
6  * SET OF helpers through the callbacks to the next pabket-ber helper
7  * when the tags are IMPLICIT, this causes a problem when we also have
8  * indefinite length at the same time as the tags are implicit.
9  * While the proper fix is to change the signatures for packet-ber.c helpers
10  * as well as the signatures for the callbacks to include the indefinite length
11  * indication that would be a major job.
12  * For the time being, kludge, set a global variable in the 
13  * CHOICE/SEQUENCE [OF]/SET [OF] helpers to indicate to the next helper
14  * whether the length is indefinite or not.
15  * This has currently only been implemented for {SEQUENCE|SET} [OF] but not yet
16  * CHOICE.
17  *
18  * This version attacks the problem(s) in a different way, if we see indefinit length
19  * the get_ber_length traverses the tags within the compound value and then we return the 
20  * true length of the compound value including the EOC. Thus the tvb length is now always correct
21  * even for indefinite length, then if we get implicit tags they can be handled as if they were definite 
22  * length.
23  */
24
25 /* packet-ber.c
26  * Helpers for ASN.1/BER dissection
27  * Ronnie Sahlberg (C) 2004
28  *
29  * $Id$
30  *
31  * Ethereal - Network traffic analyzer
32  * By Gerald Combs <gerald@ethereal.com>
33  * Copyright 1998 Gerald Combs
34  *
35  * This program is free software; you can redistribute it and/or
36  * modify it under the terms of the GNU General Public License
37  * as published by the Free Software Foundation; either version 2
38  * of the License, or (at your option) any later version.
39  *
40  * This program is distributed in the hope that it will be useful,
41  * but WITHOUT ANY WARRANTY; without even the implied warranty of
42  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
43  * GNU General Public License for more details.
44  *
45  * You should have received a copy of the GNU General Public License
46  * along with this program; if not, write to the Free Software
47  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
48  */
49
50 /* 
51  * ITU-T Recommendation X.690 (07/2002),
52  *   Information technology ASN.1 encoding rules:
53  *     Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER)
54  * 
55  */ 
56
57 #ifdef HAVE_CONFIG_H
58 # include "config.h"
59 #endif
60
61 #include <stdio.h>
62 #include <string.h>
63 #include <ctype.h>
64
65 #include <glib.h>
66
67 #include <epan/packet.h>
68
69 #include <epan/strutil.h>
70 #include <epan/to_str.h>
71 #include <epan/prefs.h>
72 #include <epan/reassemble.h>
73 #include <epan/emem.h>
74 #include "packet-ber.h"
75
76 #ifndef MIN
77 #define MIN(x,y) ((x)<(y))?(x):(y)
78 #endif
79
80 static gint proto_ber = -1;
81 static gint hf_ber_id_class = -1;
82 static gint hf_ber_id_pc = -1;
83 static gint hf_ber_id_uni_tag = -1;
84 static gint hf_ber_id_uni_tag_ext = -1;
85 static gint hf_ber_id_tag = -1;
86 static gint hf_ber_id_tag_ext = -1;
87 static gint hf_ber_length = -1;
88 static gint hf_ber_bitstring_padding = -1;
89 static gint hf_ber_unknown_OID = -1;
90 static gint hf_ber_unknown_OCTETSTRING = -1;
91 static gint hf_ber_unknown_GraphicString = -1;
92 static gint hf_ber_unknown_NumericString = -1;
93 static gint hf_ber_unknown_PrintableString = -1;
94 static gint hf_ber_unknown_IA5String = -1;
95 static gint hf_ber_unknown_INTEGER = -1;
96 static gint hf_ber_unknown_ENUMERATED = -1;
97
98 static gint ett_ber_octet_string = -1;
99 static gint ett_ber_unknown = -1;
100 static gint ett_ber_SEQUENCE = -1;
101
102 static gboolean show_internal_ber_fields = FALSE;
103
104 proto_item *ber_last_created_item=NULL;
105
106 /* kludge to pass indefinite length indications from structure helpers
107    to the next helper.  Or else implicite tag + indefinite length wont work.
108
109 static gboolean length_is_indefinite=FALSE;
110  not used anymore as the length from get_ber_length should be correct for indefinite length also.
111  */
112 static dissector_table_t ber_oid_dissector_table=NULL;
113
114 static const value_string ber_class_codes[] = {
115         { BER_CLASS_UNI,        "Universal" },
116         { BER_CLASS_APP,        "Application" },
117         { BER_CLASS_CON,        "Context Specific" },
118         { BER_CLASS_PRI,        "Private" },
119         { 0, NULL }
120 };
121
122 static const true_false_string ber_pc_codes = {
123         "Constructed Encoding",
124         "Primitive Encoding"
125 };
126
127 static const value_string ber_uni_tag_codes[] = {
128         { BER_UNI_TAG_EOC                               , "'end-of-content'" },
129         { BER_UNI_TAG_BOOLEAN                   , "BOOLEAN" },
130         { BER_UNI_TAG_INTEGER                   , "INTEGER" },
131         { BER_UNI_TAG_BITSTRING         , "BIT STRING" },
132         { BER_UNI_TAG_OCTETSTRING               , "OCTET STRING" },
133         { BER_UNI_TAG_NULL                      , "NULL" },
134         { BER_UNI_TAG_OID                               , "OBJECT IDENTIFIER" },
135         { BER_UNI_TAG_ObjectDescriptor, "ObjectDescriptor" },
136         { BER_UNI_TAG_REAL                      , "REAL" },
137         { BER_UNI_TAG_ENUMERATED                , "ENUMERATED" },
138         { BER_UNI_TAG_EMBEDDED_PDV      , "EMBEDDED PDV" },
139         { BER_UNI_TAG_UTF8String                , "UTF8String" },
140         { BER_UNI_TAG_RELATIVE_OID      , "RELATIVE-OID" },
141         { BER_UNI_TAG_SEQUENCE          , "SEQUENCE, SEQUENCE OF" },
142         { BER_UNI_TAG_SET                               , "SET, SET OF" },
143         { BER_UNI_TAG_NumericString     , "NumericString" },
144         { BER_UNI_TAG_PrintableString   , "PrintableString" },
145         { BER_UNI_TAG_TeletexString     , "TeletexString, T61String" },
146         { BER_UNI_TAG_VideotexString    , "VideotexString" },
147         { BER_UNI_TAG_IA5String         , "IA5String" },
148         { BER_UNI_TAG_UTCTime           , "UTCTime" },
149         { BER_UNI_TAG_GeneralizedTime   , "GeneralizedTime" },
150         { BER_UNI_TAG_GraphicString     , "GraphicString" },
151         { BER_UNI_TAG_VisibleString     , "VisibleString, ISO64String" },
152         { BER_UNI_TAG_GeneralString     , "GeneralString" },
153         { BER_UNI_TAG_UniversalString   , "UniversalString" },
154         { BER_UNI_TAG_CHARACTERSTRING   , "CHARACTER STRING" },
155         { BER_UNI_TAG_BMPString         , "BMPString" },
156         { 31                            , "Continued" },
157         { 0, NULL }
158 };
159
160
161 proto_item *get_ber_last_created_item(void) {
162   return ber_last_created_item;
163 }
164
165
166 static GHashTable *oid_table=NULL;
167
168 void
169 dissect_ber_oid_NULL_callback(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_)
170 {
171         return;
172 }
173
174
175 void
176 register_ber_oid_dissector_handle(const char *oid, dissector_handle_t dissector, int proto _U_, const char *name)
177 {
178         dissector_add_string("ber.oid", oid, dissector);
179         g_hash_table_insert(oid_table, (gpointer)oid, (gpointer)name);
180 }
181
182 void
183 register_ber_oid_dissector(const char *oid, dissector_t dissector, int proto, const char *name)
184 {
185         dissector_handle_t dissector_handle;
186
187         dissector_handle=create_dissector_handle(dissector, proto);
188         dissector_add_string("ber.oid", oid, dissector_handle);
189         g_hash_table_insert(oid_table, (gpointer)oid, (gpointer)name);
190 }
191
192 /* Register the oid name to get translation in proto dissection */
193 void
194 register_ber_oid_name(const char *oid, const char *name)
195 {
196         g_hash_table_insert(oid_table, (gpointer)oid, (gpointer)name);
197 }
198
199 /* Get oid name from hash table to get translation in proto dissection(packet-per.c) */
200 char *
201 get_ber_oid_name(char *oid)
202 {
203         return g_hash_table_lookup(oid_table, oid);
204 }
205
206
207 /* this function tries to dissect an unknown blob as much as possible.
208  * everytime this function is called it is a failure to implement a proper
209  * dissector in ethereal.
210  * something is missing, so dont become too comfy with this one,
211  * when it is called it is a BAD thing  not a good thing.
212  * It can not handle IMPLICIT tags nor indefinite length.
213  */
214 int dissect_unknown_ber(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree)
215 {
216         int start_offset;
217         gint8 class;
218         gboolean pc, ind;
219         gint32 tag;
220         guint32 len;
221         proto_item *item=NULL;
222         proto_tree *next_tree=NULL;
223
224         start_offset=offset;
225
226         offset=dissect_ber_identifier(pinfo, NULL, tvb, offset, &class, &pc, &tag);
227         offset=dissect_ber_length(pinfo, NULL, tvb, offset, &len, &ind);
228
229         if(len>(guint32)tvb_length_remaining(tvb, offset)){
230                 /* hmm   maybe something bad happened or the frame is short,
231                    since these are not vital outputs just return instead of 
232                    throwing en exception.
233                  */
234                 proto_tree_add_text(tree, tvb, offset, len, "BER: Error length:%u longer than tvb_length_ramaining:%d",len, tvb_length_remaining(tvb, offset));
235                 return tvb_length(tvb);
236         }
237 /* we dont care about the class only on the constructor flag */
238         switch(pc){
239         case FALSE:
240                 switch(tag){
241                 case BER_UNI_TAG_INTEGER:
242                         offset = dissect_ber_integer(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_INTEGER, NULL);
243                         break;
244                 case BER_UNI_TAG_ENUMERATED:
245                         offset = dissect_ber_integer(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_ENUMERATED, NULL);
246                         break;
247                 case BER_UNI_TAG_GraphicString:
248                         offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_GraphicString, NULL);
249                         break;
250                 case BER_UNI_TAG_OCTETSTRING:
251                         offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_OCTETSTRING, NULL);
252                         break;
253                 case BER_UNI_TAG_OID:
254                         offset=dissect_ber_object_identifier(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_OID, NULL);
255                         break;
256                 case BER_UNI_TAG_SEQUENCE:
257                         item=proto_tree_add_text(tree, tvb, offset, len, "SEQUENCE  (len:%d bytes)   tvb_remaining:%d", len, tvb_length_remaining(tvb, offset));
258                         if(item){
259                                 next_tree=proto_item_add_subtree(item, ett_ber_SEQUENCE);
260                         }
261                         offset=dissect_unknown_ber(pinfo, tvb, offset, next_tree);
262                         break;
263                 case BER_UNI_TAG_NumericString:
264                         offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_NumericString, NULL);
265                         break;
266                 case BER_UNI_TAG_PrintableString:
267                         offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_PrintableString, NULL);
268                         break;
269                 case BER_UNI_TAG_IA5String:
270                         offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, start_offset, hf_ber_unknown_IA5String, NULL);
271                         break;
272                 default:
273                         proto_tree_add_text(tree, tvb, offset, len, "BER: Error can not handle universal tag:%d",tag);
274                         offset += len;
275                 }
276                 break;
277         case TRUE:
278                 item=proto_tree_add_text(tree, tvb, offset, len, "[%d]  (len:%d bytes) ",tag,len);
279                 if(item){
280                         next_tree=proto_item_add_subtree(item, ett_ber_SEQUENCE);
281                 }
282                 offset=dissect_unknown_ber(pinfo, tvb, offset, next_tree);
283                 break;
284         default:
285                 proto_tree_add_text(tree, tvb, offset, len, "BER: Error can not handle class:%d (0x%02x)",class,tvb_get_guint8(tvb, start_offset));
286                 /* some printout here? aborting dissection */
287                 return tvb_length(tvb);
288         }
289
290         /* were there more data to eat? */
291         if(offset<(int)tvb_length(tvb)){
292                 offset=dissect_unknown_ber(pinfo, tvb, offset, tree);
293         }
294
295         return offset;
296 }
297
298
299 int
300 call_ber_oid_callback(const char *oid, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
301 {
302         tvbuff_t *next_tvb;
303
304         next_tvb = tvb_new_subset(tvb, offset, -1, -1);
305         if(!dissector_try_string(ber_oid_dissector_table, oid, next_tvb, pinfo, tree)){
306                 proto_item *item=NULL;
307                 proto_tree *next_tree=NULL;
308
309                 item=proto_tree_add_text(tree, next_tvb, 0, tvb_length_remaining(tvb, offset), "BER: Dissector for OID:%s not implemented. Contact Ethereal developers if you want this supported", oid);
310                 if(item){
311                         next_tree=proto_item_add_subtree(item, ett_ber_unknown);
312                 }
313                 dissect_unknown_ber(pinfo, next_tvb, 0, next_tree);
314         }
315
316         /*XXX until we change the #.REGISTER signature for _PDU()s 
317          * into new_dissector_t   we have to do this kludge with
318          * manually step past the content in the ANY type.
319          */
320         offset+=tvb_length_remaining(tvb, offset);
321
322         return offset;
323 }
324
325
326 static int dissect_ber_sq_of(gboolean implicit_tag, gint32 type, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_sequence_t *seq, gint hf_id, gint ett_id);
327
328 /* 8.1 General rules for encoding */
329
330 /*  8.1.2 Identifier octets */
331 int get_ber_identifier(tvbuff_t *tvb, int offset, gint8 *class, gboolean *pc, gint32 *tag) {
332         guint8 id, t;
333         gint8 tmp_class;
334         gboolean tmp_pc;
335         gint32 tmp_tag;
336
337         id = tvb_get_guint8(tvb, offset);
338         offset += 1;
339 #ifdef DEBUG_BER
340 printf ("BER ID=%02x", id);
341 #endif
342         /* 8.1.2.2 */
343         tmp_class = (id>>6) & 0x03;
344         tmp_pc = (id>>5) & 0x01;
345         tmp_tag = id&0x1F;
346         /* 8.1.2.4 */
347         if (tmp_tag == 0x1F) {
348                 tmp_tag = 0;
349                 while (tvb_length_remaining(tvb, offset) > 0) {
350                         t = tvb_get_guint8(tvb, offset);
351 #ifdef DEBUG_BER
352 printf (" %02x", t);
353 #endif
354                         offset += 1;
355                         tmp_tag <<= 7;       
356                         tmp_tag |= t & 0x7F;
357                         if (!(t & 0x80)) break;
358                 }
359         }
360
361 #ifdef DEBUG_BER
362 printf ("\n");
363 #endif
364         if (class)
365                 *class = tmp_class;
366         if (pc)
367                 *pc = tmp_pc;
368         if (tag)
369                 *tag = tmp_tag;
370
371         return offset;
372 }
373
374 int dissect_ber_identifier(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gint8 *class, gboolean *pc, gint32 *tag) 
375 {
376         int old_offset = offset;
377         gint8 tmp_class;
378         gboolean tmp_pc;
379         gint32 tmp_tag;
380
381         offset = get_ber_identifier(tvb, offset, &tmp_class, &tmp_pc, &tmp_tag);
382         
383         if(show_internal_ber_fields){
384                 proto_tree_add_uint(tree, hf_ber_id_class, tvb, old_offset, 1, tmp_class<<6);
385                 proto_tree_add_boolean(tree, hf_ber_id_pc, tvb, old_offset, 1, (tmp_pc)?0x20:0x00);
386                 if(tmp_tag==0x1F){
387                         proto_tree_add_uint(tree, hf_ber_id_uni_tag, tvb, old_offset, 1, tmp_tag);
388                         if(tmp_class==BER_CLASS_UNI){
389                                 proto_tree_add_uint(tree, hf_ber_id_uni_tag_ext, tvb, old_offset + 1, offset - (old_offset + 1), tmp_tag);
390                         } else {
391                                 proto_tree_add_uint(tree, hf_ber_id_tag_ext, tvb, old_offset + 1, offset - (old_offset + 1), tmp_tag);
392                         }
393                 } else {
394                         if(tmp_class==BER_CLASS_UNI){
395                                 proto_tree_add_uint(tree, hf_ber_id_uni_tag, tvb, old_offset, 1, tmp_tag);
396                         } else {
397                                 proto_tree_add_uint(tree, hf_ber_id_tag, tvb, old_offset, 1, tmp_tag);
398                         }
399                 }
400         }
401
402         if(class)
403                 *class = tmp_class;
404         if(pc)
405                 *pc = tmp_pc;
406         if(tag)
407                 *tag = tmp_tag;
408
409         return offset;
410 }
411
412 /* this function gets the length octets of the BER TLV.
413  * We only handle (TAGs and) LENGTHs that fit inside 32 bit integers.
414  */
415 /* 8.1.3 Length octets */
416 int
417 get_ber_length(proto_tree *tree, tvbuff_t *tvb, int offset, guint32 *length, gboolean *ind) {
418         guint8 oct, len;
419         guint32 tmp_len;
420         guint32 tmp_length;
421         gboolean tmp_ind;
422         int old_offset=offset;
423         int tmp_offset,s_offset;
424         gint8 tclass;
425         gboolean tpc;
426         gint32 ttag;
427         tmp_length = 0;
428         tmp_ind = FALSE;
429
430         oct = tvb_get_guint8(tvb, offset);
431         offset += 1;
432         
433         if(!(oct&0x80)) {
434                 /* 8.1.3.4 */
435                 tmp_length = oct;
436         } else {
437                 len = oct & 0x7F;
438                 if(len) {
439                         /* 8.1.3.5 */
440                         while (len--) {
441                                 oct = tvb_get_guint8(tvb, offset);
442                                 offset++;
443                                 tmp_length = (tmp_length<<8) + oct;
444                         }
445                 } else {
446                         /* 8.1.3.6 */
447                 
448                         tmp_offset = offset;
449                         /* ok in here we can traverse the BER to find the length, this will fix most indefinite length issues */
450                         /* Assumption here is that indefinite length is always used on constructed types*/ 
451                         /* check for EOC */
452                         while ((tvb_reported_length_remaining(tvb,offset)>0) && ( tvb_get_guint8(tvb, offset) || tvb_get_guint8(tvb,offset+1)))
453                                 {
454                                 /* not an EOC at offset */
455                                 s_offset=offset;
456                                 offset= get_ber_identifier(tvb, offset, &tclass, &tpc, &ttag);
457                                 offset= get_ber_length(tree,tvb,offset, &tmp_len, NULL);
458                                 tmp_length += tmp_len+(offset-s_offset); /* length + tag and length */
459                                 offset += tmp_len;
460                                 }
461                         tmp_length += 2; 
462                         tmp_ind = TRUE;
463                         offset = tmp_offset;
464                 }
465         }
466
467         /* check that the length is sane */
468         if(tmp_length>(guint32)tvb_reported_length_remaining(tvb,offset)){
469                 proto_tree_add_text(tree, tvb, old_offset, offset-old_offset, "BER: Error length:%u longer than tvb_reported_length_remaining:%d",tmp_length, tvb_reported_length_remaining(tvb, offset));
470                 /* force the appropriate exception */
471                 tvb_ensure_bytes_exist(tvb, offset, tmp_length);
472                 /*tmp_length = (guint32)tvb_reported_length_remaining(tvb,offset);*/
473         }
474
475         if (length)
476                 *length = tmp_length;
477         if (ind)
478                 *ind = tmp_ind;
479
480         return offset;
481 }
482
483 /* this function dissects the length octets of the BER TLV.
484  * We only handle (TAGs and) LENGTHs that fit inside 32 bit integers.
485  */
486 int
487 dissect_ber_length(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 *length, gboolean *ind)
488 {
489         int old_offset = offset;
490         guint32 tmp_length;
491         gboolean tmp_ind;
492
493         offset = get_ber_length(tree, tvb, offset, &tmp_length, &tmp_ind);
494         
495         if(show_internal_ber_fields){
496                 if(tmp_ind){
497                         proto_tree_add_text(tree, tvb, old_offset, 1, "Length: Indefinite length %d", tmp_length);
498                 } else {
499                         proto_tree_add_uint(tree, hf_ber_length, tvb, old_offset, offset - old_offset, tmp_length);
500                 }
501         }
502         if(length)
503                 *length = tmp_length;
504         if(ind)
505                 *ind = tmp_ind;
506         return offset;
507 }
508 static int 
509 reassemble_octet_string(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, guint32 con_len, gboolean ind, tvbuff_t **out_tvb) 
510 {
511   static GHashTable *octet_segment_table = NULL;
512   static GHashTable *octet_reassembled_table = NULL;
513   fragment_data *fd_head = NULL;
514   tvbuff_t *next_tvb = NULL;
515   tvbuff_t *reassembled_tvb = NULL;
516   guint16 dst_ref = 0;
517   int start_offset = offset;
518   gboolean fragment = TRUE;
519   gboolean firstFragment = TRUE;
520
521   if(octet_segment_table == NULL) {
522     /* I assume I can take this late binding approach */
523     fragment_table_init(&octet_segment_table);
524     reassembled_table_init(&octet_reassembled_table);
525
526   }
527
528   /* so we need to consume octet strings for the given length */
529
530   /* not sure we need this */
531   pinfo->fragmented = TRUE;
532
533   while(!fd_head) {
534
535     offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, offset, hf_ber_unknown_OCTETSTRING, &next_tvb);
536
537     if (next_tvb == NULL) {
538       /* Assume that we have a malformed packet. */
539       THROW(ReportedBoundsError);
540     }
541
542     if(ind) {
543       /* this was indefinite length - so check for EOC */
544       
545       if((tvb_get_guint8(tvb, offset)==0)&&(tvb_get_guint8(tvb, offset+1)==0)) {
546         fragment = FALSE;
547         /* skip past EOC */
548         offset +=2;
549       }
550     } else {
551       
552     if((guint32)(offset - start_offset) >= con_len)
553         fragment = FALSE;
554     }
555
556     if(!fragment && firstFragment) {
557       /* there is only one fragment (I'm sure there's a reason it was constructed) */
558       /* anyway, we can get out of here */
559       reassembled_tvb = next_tvb;
560       break;
561     }
562
563
564     if (tvb_length(next_tvb) < 1) {
565       /* Don't cause an assertion in the reassembly code. */
566       THROW(ReportedBoundsError);
567     }
568     fd_head = fragment_add_seq_next(next_tvb, 0, pinfo, dst_ref,
569                                     octet_segment_table,
570                                     octet_reassembled_table,
571                                     tvb_length(next_tvb),
572                                     fragment);
573
574     firstFragment = FALSE;
575   }
576
577   if(fd_head) {
578     if(fd_head->next) {
579       reassembled_tvb = tvb_new_real_data(fd_head->data,
580                                           fd_head->len,
581                                           fd_head->len);
582
583       tvb_set_child_real_data_tvbuff(next_tvb, reassembled_tvb);
584
585       /* not sure I really want to do this here - should be nearer the application where we can give it a better name*/
586       add_new_data_source(pinfo, reassembled_tvb, "Reassembled OCTET STRING");
587
588     }
589   }
590
591   if(out_tvb)
592     *out_tvb = reassembled_tvb;
593
594   /* again - not sure we need this */
595   pinfo->fragmented = FALSE;
596   
597   return offset;
598
599 }
600
601 /* 8.7 Encoding of an octetstring value */
602 int 
603 dissect_ber_octet_string(gboolean implicit_tag, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, tvbuff_t **out_tvb) {
604         gint8 class;
605         gboolean pc, ind;
606         gint32 tag;
607         guint32 len;
608         int end_offset;
609         proto_item *it;
610   guint32 i;
611
612 #ifdef DEBUG_BER
613 {
614 char *name;
615 header_field_info *hfinfo;
616 if(hf_id>=0){
617 hfinfo = proto_registrar_get_nth(hf_id);
618 name=hfinfo->name;
619 } else {
620 name="unnamed";
621 }
622 if(tvb_length_remaining(tvb,offset)>3){
623 printf("OCTET STRING dissect_ber_octet string(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x\n",name,implicit_tag,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
624 }else{
625 printf("OCTET STRING dissect_ber_octet_string(%s) entered\n",name);
626 }
627 }
628 #endif
629
630         if (!implicit_tag) {
631                 /* read header and len for the octet string */
632                 offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
633                 offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, &ind);
634                 end_offset=offset+len;
635
636                 /* sanity check: we only handle Constructed Universal Sequences */
637                 if ((class!=BER_CLASS_APP)&&(class!=BER_CLASS_PRI))
638
639                 if( (class!=BER_CLASS_UNI) 
640                   ||((tag<BER_UNI_TAG_NumericString)&&(tag!=BER_UNI_TAG_OCTETSTRING)&&(tag!=BER_UNI_TAG_UTF8String)) ){
641                     tvb_ensure_bytes_exist(tvb, offset-2, 2);
642                     proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: OctetString expected but Class:%d PC:%d Tag:%d was unexpected", class, pc, tag);
643                         if(out_tvb)
644                                 *out_tvb=NULL;
645                         return end_offset;
646                 }
647         } else {
648                 /* implicit tag so just trust the length of the tvb */
649                 pc=FALSE;
650                 len=tvb_length_remaining(tvb,offset);
651                 end_offset=offset+len;
652         }               
653
654         ber_last_created_item = NULL;
655         if (pc) {
656                 /* constructed */
657                 end_offset = reassemble_octet_string(pinfo, tree, tvb, offset, len, ind, out_tvb);
658         } else {
659                 /* primitive */
660                 gint length_remaining = tvb_length_remaining(tvb, offset);
661
662                 if(len<=(guint32)length_remaining){
663                         length_remaining=len;
664                 }
665                 if(hf_id >= 0) {
666                         it = proto_tree_add_item(tree, hf_id, tvb, offset, length_remaining, FALSE);
667                         ber_last_created_item = it;
668                 } else {
669                         proto_item *pi;
670       
671                         pi=proto_tree_add_text(tree, tvb, offset, len, "Unknown OctetString: Length: 0x%02x, Value: 0x", len);
672                         if(pi){
673                                 for(i=0;i<len;i++){
674                                         proto_item_append_text(pi,"%02x",tvb_get_guint8(tvb, offset));
675                                         offset++;
676                                 }
677                         }
678                 }
679
680                 if(out_tvb) {
681                         *out_tvb = tvb_new_subset(tvb, offset, length_remaining, len);
682                 }
683         }
684         return end_offset;
685 }
686
687 int dissect_ber_octet_string_wcb(gboolean implicit_tag, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, ber_callback func)
688 {
689         tvbuff_t *out_tvb = NULL;
690
691         offset = dissect_ber_octet_string(implicit_tag, pinfo, tree, tvb, offset, hf_id, (func)?&out_tvb:NULL);
692         if (func && out_tvb && (tvb_length(out_tvb)>0)) {
693                 if (hf_id >= 0)
694                         tree = proto_item_add_subtree(ber_last_created_item, ett_ber_octet_string);
695                 func(pinfo, tree, out_tvb, 0);
696         }
697         return offset;
698 }
699
700 /* 8.8 Encoding of a null value */
701 int 
702 dissect_ber_null(gboolean implicit_tag, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id) {
703   gint8 class;
704   gboolean pc;
705   gint32 tag;
706   guint32 len;
707   int offset_old;
708 if (!implicit_tag)
709 {
710   offset_old = offset;  
711   offset = dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
712   if((pc) ||
713       (!implicit_tag && ((class != BER_CLASS_UNI) || (tag != BER_UNI_TAG_NULL)))) {
714     proto_tree_add_text(tree, tvb, offset_old, offset - offset_old, "BER Error: NULL expected but Class:%d(%s) PC:%d Tag:%d was unexpected", class,val_to_str(class,ber_class_codes,"Unknown"), pc, tag);
715   }
716
717   offset_old = offset;  
718   offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
719   if(len) {
720     proto_tree_add_text(tree, tvb, offset_old, offset - offset_old, "BER Error: NULL expect zero length but Length=%d", len);
721     proto_tree_add_text(tree, tvb, offset, len, "BER Error: unexpected data in NULL type");
722     offset += len;
723   }
724 }
725   if (hf_id >= 0)
726           proto_tree_add_item(tree, hf_id, tvb, offset, 0, FALSE);
727   return offset;
728 }
729
730 int
731 dissect_ber_integer(gboolean implicit_tag, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, guint32 *value)
732 {
733         guint8 class;
734         gboolean pc;
735         guint32 tag;
736         guint32 len;
737         gint32 val;
738         gint64 val64;
739         guint32 i;
740
741 #ifdef DEBUG_BER
742 {
743 char *name;
744 header_field_info *hfinfo;
745 if(hf_id>=0){
746 hfinfo = proto_registrar_get_nth(hf_id);
747 name=hfinfo->name;
748 } else {
749 name="unnamed";
750 }
751 if(tvb_length_remaining(tvb,offset)>3){
752 printf("INTEGERnew dissect_ber_integer(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x\n",name,implicit_tag,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
753 }else{
754 printf("INTEGERnew dissect_ber_integer(%s) entered implicit_tag:%d \n",name,implicit_tag);
755 }
756 }
757 #endif
758
759
760         if(!implicit_tag){
761           offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
762           offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
763         } else {
764           len=tvb_length_remaining(tvb, offset);
765         }
766
767         /* ok,  we cant handle >4 byte integers so lets fake them */
768         /*
769          * XXX - should we handle large integers with a bignum type,
770          * and an FT_BIGNUM field type?  This code currently has trouble
771          * with, for example, INTEGER (0..4294967295), as a value in the
772          * range 2147483648 to 0..4294967295 is represented as 5 bytes.
773          *
774          * There should at least be a way to indicate that the value we
775          * returned didn't fit in a 32-bit signed integer, so our caller
776          * can, if they didn't supply an hf_id, indicate that the value
777          * didn't fit.
778          */
779         if(len>8){
780                 header_field_info *hfinfo;
781                 proto_item *pi = NULL;
782
783                 if (hf_id >= 0) {
784                         hfinfo = proto_registrar_get_nth(hf_id);
785                         pi=proto_tree_add_text(tree, tvb, offset, len, "%s : 0x", hfinfo->name);
786                 }
787                 if(pi){
788                         for(i=0;i<len;i++){
789                                 proto_item_append_text(pi,"%02x",tvb_get_guint8(tvb, offset));
790                                 offset++;
791                         }
792                 } else {
793                         offset += len;
794                 }
795                 return offset;
796         }
797         if(len>4){
798                 header_field_info *hfinfo;
799
800                 val64=0;
801                 if(len > 0) {
802                         /* extend sign bit */
803                         val64 = (gint8)tvb_get_guint8(tvb, offset);
804                         offset++;
805                 }
806                 for(i=1;i<len;i++){
807                         val64=(val64<<8)|tvb_get_guint8(tvb, offset);
808                         offset++;
809                 }
810                 if (hf_id >= 0) {
811                         hfinfo = proto_registrar_get_nth(hf_id);
812                         proto_tree_add_text(tree, tvb, offset-len, len, "%s: %" PRIu64, hfinfo->name, val64);
813                 }
814                 return offset;
815         }
816         
817         val=0;
818         if(len > 0) {
819                 /* extend sign bit */
820                 val = (gint8)tvb_get_guint8(tvb, offset);
821                 offset++;
822         }
823         for(i=1;i<len;i++){
824                 val=(val<<8)|tvb_get_guint8(tvb, offset);
825                 offset++;
826         }
827
828         ber_last_created_item=NULL;
829
830         if(hf_id >= 0){ 
831                 /*  */
832                 if(len < 1 || len > 4) {
833                         proto_tree_add_text(tree, tvb, offset-len, len, "Can't handle integer length: %u", len);
834                 } else {
835                         ber_last_created_item=proto_tree_add_item(tree, hf_id, tvb, offset-len, len, FALSE);
836                 }
837         }
838         if(value){
839                 *value=val;
840         }
841
842         return offset;
843 }
844
845
846 int
847 dissect_ber_boolean(gboolean implicit_tag, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id)
848 {
849         guint8 class;
850         gboolean pc;
851         guint32 tag;
852         guint32 len;
853         guint8 val;
854         header_field_info *hfi;
855
856         if(!implicit_tag){
857                 offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
858                 offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
859                 /*if(class!=BER_CLASS_UNI)*/
860         } else {
861                 /* nothing to do here, yet */
862         }
863         
864         val=tvb_get_guint8(tvb, offset);
865         offset+=1;
866
867         ber_last_created_item=NULL;
868
869         if(hf_id >= 0){
870                 hfi = proto_registrar_get_nth(hf_id);
871                 if(hfi->type == FT_BOOLEAN)
872                         ber_last_created_item=proto_tree_add_boolean(tree, hf_id, tvb, offset-1, 1, val);
873                 else
874                         ber_last_created_item=proto_tree_add_uint(tree, hf_id, tvb, offset-1, 1, val?1:0);
875         }
876
877         return offset;
878 }
879
880
881
882
883
884 /* this function dissects a BER sequence 
885  */
886 int dissect_ber_sequence(gboolean implicit_tag, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_sequence_t *seq, gint hf_id, gint ett_id) {
887         gint8 class;
888         gboolean pc, ind = 0, ind_field;
889         gint32 tag;
890         guint32 len;
891         proto_tree *tree = parent_tree;
892         proto_item *item = NULL;
893         int end_offset, s_offset;
894         gint length_remaining;
895         tvbuff_t *next_tvb;
896 s_offset = offset;
897 #ifdef DEBUG_BER
898 {
899 char *name;
900 header_field_info *hfinfo;
901 if(hf_id>=0){
902 hfinfo = proto_registrar_get_nth(hf_id);
903 name=hfinfo->name;
904 } else {
905 name="unnamed";
906 }
907 if(tvb_length_remaining(tvb,offset)>3){
908 printf("SEQUENCE dissect_ber_sequence(%s) entered offset:%d len:%d %02x:%02x:%02x\n",name,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
909 }else{
910 printf("SEQUENCE dissect_ber_sequence(%s) entered\n",name);
911 }
912 }
913 #endif
914         if(!implicit_tag){
915                 /* first we must read the sequence header */
916                 offset = dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
917                 offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, &ind);
918                 if(ind){
919                 /*  Fixed the length is correctly returned from dissect ber_length
920                   end_offset = tvb_length(tvb);*/
921                   end_offset = offset + len -2; 
922                 } else {
923                   end_offset = offset + len;
924                 }
925
926                 /* sanity check: we only handle Constructed Universal Sequences */
927                 if((class!=BER_CLASS_APP)&&(class!=BER_CLASS_PRI))
928                 if((!pc)
929                 ||(!implicit_tag&&((class!=BER_CLASS_UNI)
930                                                         ||(tag!=BER_UNI_TAG_SEQUENCE)))) {
931                         tvb_ensure_bytes_exist(tvb, offset-2, 2);
932                         proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: Sequence expected but Class:%d(%s) PC:%d Tag:%d was unexpected", class,val_to_str(class,ber_class_codes,"Unknown"), pc, tag);
933                         return end_offset;
934                 }
935         } else {
936                 /* was implicit tag so just use the length of the tvb */
937                 len=tvb_length_remaining(tvb,offset);
938                 end_offset=offset+len;
939         }
940
941         /* create subtree */
942         if(hf_id >= 0) {
943                 if(parent_tree){
944                         item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE);
945                         tree = proto_item_add_subtree(item, ett_id);
946                 }
947         }
948
949         /* loop over all entries until we reach the end of the sequence */
950         while (offset < end_offset){
951                 gint8 class;
952                 gboolean pc;
953                 gint32 tag;
954                 guint32 len;
955                 int hoffset, eoffset, count;
956
957                 /*if(ind){  this sequence was of indefinite length, if this is implicit indefinite impossible maybe
958                                         but tcap dissector uses this to eat the tag length then pass into here... EOC still on there...*/
959                         if((tvb_get_guint8(tvb, offset)==0)&&(tvb_get_guint8(tvb, offset+1)==0)){
960                                 if(show_internal_ber_fields){
961                                         proto_tree_add_text(tree, tvb, s_offset, offset+2, "ERROR WRONG SEQ EOC");
962                                 }
963                                 return end_offset;
964                         }
965                 /*}*/
966                 hoffset = offset;
967                 /* read header and len for next field */
968                 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
969                 offset = get_ber_length(tree, tvb, offset, &len, &ind_field);
970                 eoffset = offset + len;
971
972 ber_sequence_try_again:
973                 /* have we run out of known entries in the sequence ?*/
974                 if(!seq->func) {
975                         /* it was not,  move to the enxt one and try again */
976                         proto_tree_add_text(tree, tvb, offset, len, "BER Error: This field lies beyond the end of the known sequence definition.");
977                         offset = eoffset;
978                         continue;
979                 }
980
981                 /* Verify that this one is the one we want.
982                  * Skip check completely if class==ANY
983                  * of if NOCHKTAG is set
984                  */
985 /* XXX Bug in asn2eth,
986  * for   scope            [7]  Scope OPTIONAL,
987  * it generates         
988  *   { BER_CLASS_CON, 7, BER_FLAGS_OPTIONAL|BER_FLAGS_NOTCHKTAG, dissect_scope },
989  * and there should not be a NOTCHKTAG here
990  */
991                 if( ((seq->class==BER_CLASS_CON)||(seq->class==BER_CLASS_APP)||(seq->class==BER_CLASS_PRI)) && (!(seq->flags&BER_FLAGS_NOOWNTAG)) ){
992                   if( (seq->class!=BER_CLASS_ANY) 
993                   &&  (seq->tag!=-1)  
994                   &&( (seq->class!=class)
995                     ||(seq->tag!=tag) ) ){
996                         /* it was not,  move to the next one and try again */
997                         if(seq->flags&BER_FLAGS_OPTIONAL){
998                                 /* well this one was optional so just skip to the next one and try again. */
999                                 seq++;
1000                                 goto ber_sequence_try_again;
1001                         }
1002                         if( seq->class == BER_CLASS_UNI){
1003                                 proto_tree_add_text(tree, tvb, offset, len,
1004                                     "BER Error: Wrong field in SEQUENCE  expected class:%d (%s) tag:%d (%s) but found class:%d tag:%d",
1005                                     seq->class,val_to_str(seq->class,ber_class_codes,"Unknown"),
1006                                     seq->tag,val_to_str(seq->tag,ber_uni_tag_codes,"Unknown"),
1007                                     class,tag);
1008                         }else{
1009                                 proto_tree_add_text(tree, tvb, offset, len,
1010                                     "BER Error: Wrong field in SEQUENCE  expected class:%d (%s) tag:%d but found class:%d tag:%d",
1011                                     seq->class,val_to_str(seq->class,ber_class_codes,"Unknown"),
1012                                     seq->tag,class,tag);
1013                         }
1014                         seq++;
1015                         offset=eoffset;
1016                         continue;
1017                   }
1018                 } else if(!(seq->flags & BER_FLAGS_NOTCHKTAG)) {
1019                   if( (seq->class!=BER_CLASS_ANY) 
1020                   &&  (seq->tag!=-1)  
1021                   &&( (seq->class!=class)
1022                     ||(seq->tag!=tag) ) ){
1023                         /* it was not,  move to the enxt one and try again */
1024                         if(seq->flags&BER_FLAGS_OPTIONAL){
1025                                 /* well this one was optional so just skip to the next one and try again. */
1026                                 seq++;
1027                                 goto ber_sequence_try_again;
1028                         }
1029
1030                         if( seq->class == BER_CLASS_UNI){
1031                                 proto_tree_add_text(tree, tvb, offset, len, "BER Error: Wrong field in sequence  expected class:%d (%s) tag:%d(%s) but found class:%d(%s) tag:%d",seq->class,val_to_str(seq->class,ber_class_codes,"Unknown"),seq->tag,val_to_str(seq->tag,ber_uni_tag_codes,"Unknown"),class,val_to_str(class,ber_class_codes,"Unknown"),tag);
1032                         }else{
1033                                 proto_tree_add_text(tree, tvb, offset, len, "BER Error: Wrong field in sequence  expected class:%d (%s) tag:%d but found class:%d(%s) tag:%d",seq->class,val_to_str(seq->class,ber_class_codes,"Unknown"),seq->tag,class,val_to_str(class,ber_class_codes,"Unknown"),tag);
1034                         }
1035                         seq++;
1036                         offset=eoffset;
1037                         continue;
1038                   }
1039                 }
1040
1041                 if(!(seq->flags & BER_FLAGS_NOOWNTAG) ) {
1042                         /* dissect header and len for field */
1043                         hoffset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL);
1044                         hoffset = dissect_ber_length(pinfo, tree, tvb, hoffset, NULL, NULL);
1045                         length_remaining=tvb_length_remaining(tvb, hoffset);
1046                         if (length_remaining>eoffset-hoffset-(2*ind_field))
1047                                 length_remaining=eoffset-hoffset-(2*ind_field);
1048                         next_tvb = tvb_new_subset(tvb, hoffset, length_remaining, eoffset-hoffset-(2*ind_field));
1049                 }
1050                 else {
1051                         length_remaining=tvb_length_remaining(tvb, hoffset);
1052                         if (length_remaining>eoffset-hoffset)
1053                                 length_remaining=eoffset-hoffset;
1054                         next_tvb = tvb_new_subset(tvb, hoffset, length_remaining, eoffset-hoffset);
1055                 }
1056                 
1057                 /* call the dissector for this field */
1058                 /*if    ((eoffset-hoffset)>length_remaining) {*/
1059                         /* If the field is indefinite (i.e. we dont know the
1060                          * length) of if the tvb is short, then just
1061                          * give it all of the tvb and hope for the best.
1062                          */
1063                         /*next_tvb = tvb_new_subset(tvb, hoffset, -1, -1);*/
1064                 /*} else {*/
1065                         
1066                 /*}*/
1067
1068 #ifdef DEBUG_BER
1069 {
1070 char *name;
1071 header_field_info *hfinfo;
1072 if(hf_id>=0){
1073 hfinfo = proto_registrar_get_nth(hf_id);
1074 name=hfinfo->name;
1075 } else {
1076 name="unnamed";
1077 }
1078 if(tvb_length_remaining(next_tvb,0)>3){
1079 printf("SEQUENCE dissect_ber_sequence(%s) calling subdissector offset:%d len:%d %02x:%02x:%02x\n",name,offset,tvb_length_remaining(next_tvb,0),tvb_get_guint8(next_tvb,0),tvb_get_guint8(next_tvb,1),tvb_get_guint8(next_tvb,2));
1080 }else{
1081 printf("SEQUENCE dissect_ber_sequence(%s) calling subdissector\n",name);
1082 }
1083 }
1084 #endif
1085                 if (next_tvb == NULL) {
1086                         /* Assume that we have a malformed packet. */
1087                         THROW(ReportedBoundsError);
1088                 }
1089                 count=seq->func(pinfo, tree, next_tvb, 0);
1090                 
1091 #ifdef DEBUG_BER
1092 {
1093 char *name;
1094 header_field_info *hfinfo;
1095 if(hf_id>=0){
1096 hfinfo = proto_registrar_get_nth(hf_id);
1097 name=hfinfo->name;
1098 } else {
1099 name="unnamed";
1100 }
1101 printf("SEQUENCE dissect_ber_sequence(%s) subdissector ate %d bytes\n",name,count);
1102 }
1103 #endif
1104                 /* if it was optional and no bytes were eaten and it was */
1105                 /* supposed to (len<>0), just try again. */
1106                 if((len!=0)&&(count==0)&&(seq->flags&BER_FLAGS_OPTIONAL)){
1107                         seq++;
1108                         goto ber_sequence_try_again;
1109                 /* move the offset to the beginning of the next sequenced item */
1110                 }
1111         offset = eoffset;
1112         seq++;
1113         if(!(seq->flags & BER_FLAGS_NOOWNTAG) ) {
1114                         /* if we stripped the tag and length we should also strip the EOC is ind_len */
1115                         if(ind_field == 1)
1116                         {
1117                                 /* skip over EOC */
1118                                 if(show_internal_ber_fields){
1119                                         proto_tree_add_text(tree, tvb, offset, count, "SEQ FIELD EOC");
1120                                 }
1121                         }
1122                         }
1123
1124         }
1125
1126         /* if we didnt end up at exactly offset, then we ate too many bytes */
1127         if(offset != end_offset) {
1128                 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1129                 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: Sequence ate %d too many bytes", offset-end_offset);
1130         }
1131         if(ind){
1132                 /*  need to eat this EOC
1133                   end_offset = tvb_length(tvb);*/
1134                   end_offset += 2; 
1135                   if(show_internal_ber_fields){
1136                                         proto_tree_add_text(tree, tvb, end_offset-2,2 , "SEQ EOC");
1137                                 }
1138                 }
1139         return end_offset;
1140 }
1141
1142 /* This function dissects a BER set
1143  */
1144 int dissect_ber_set(gboolean implicit_tag, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_sequence_t *set, gint hf_id, gint ett_id) {
1145         gint8 class;
1146         gboolean pc, ind = 0, ind_field;
1147         gint32 tag;
1148         guint32 len;
1149         proto_tree *tree = parent_tree;
1150         proto_item *item = NULL;
1151         int end_offset, s_offset;
1152         gint length_remaining;
1153         tvbuff_t *next_tvb;
1154         const ber_sequence_t *cset = NULL;
1155 # define MAX_SET_ELEMENTS 32
1156         guint32   mandatory_fields = 0;
1157         guint8   set_idx;
1158         gboolean first_pass;
1159         s_offset = offset;
1160 #ifdef DEBUG_BER
1161         {
1162 char *name;
1163 header_field_info *hfinfo;
1164 if(hf_id>=0){
1165 hfinfo = proto_registrar_get_nth(hf_id);
1166 name=hfinfo->name;
1167 } else {
1168 name="unnamed";
1169 }
1170 if(tvb_length_remaining(tvb,offset)>3){
1171 printf("SET dissect_ber_set(%s) entered offset:%d len:%d %02x:%02x:%02x\n",name,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
1172 }else{
1173 printf("SET dissect_ber_set(%s) entered\n",name);
1174 }
1175 }
1176 #endif
1177
1178         if(!implicit_tag){
1179                 /* first we must read the sequence header */
1180                 offset = dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
1181                 offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, &ind);
1182                 if(ind){
1183                 /*  Fixed the length is correctly returned from dissect ber_length
1184                   end_offset = tvb_length(tvb);*/
1185                   end_offset = offset + len -2; 
1186                 } else {
1187                   end_offset = offset + len;
1188                 }
1189
1190                 /* sanity check: we only handle Constructed Universal Sets */
1191                 if ((class!=BER_CLASS_APP)&&(class!=BER_CLASS_PRI))
1192                 if ((!pc)
1193                 ||(!implicit_tag&&((class!=BER_CLASS_UNI)
1194                                                         ||(tag!=BER_UNI_TAG_SET)))) {
1195                   tvb_ensure_bytes_exist(tvb, offset-2, 2);
1196                   proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: SET expected but Class:%d(%s) PC:%d Tag:%d was found", class,val_to_str(class,ber_class_codes,"Unknown"), pc, tag);
1197                   return end_offset;
1198                 }
1199         } else {
1200                 /* was implicit tag so just use the length of the tvb */
1201                 len=tvb_length_remaining(tvb,offset);
1202                 end_offset=offset+len;
1203         }
1204
1205         /* create subtree */
1206         if (hf_id >= 0) {
1207                 if(parent_tree){
1208                         item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE);
1209                         tree = proto_item_add_subtree(item, ett_id);
1210                 }
1211         }
1212
1213         /* record the mandatory elements of the set so we can check we founf everything at the end
1214            we can only record 32 elements for now ... */
1215         for(set_idx = 0; (cset=&set[set_idx])->func && (set_idx < MAX_SET_ELEMENTS); set_idx++) {
1216
1217           if(!(cset->flags & BER_FLAGS_OPTIONAL)) 
1218               mandatory_fields |= 1 << set_idx;
1219
1220         }
1221
1222         /* loop over all entries until we reach the end of the set */
1223         while (offset < end_offset){
1224                 gint8 class;
1225                 gboolean pc;
1226                 gint32 tag;
1227                 guint32 len;
1228                 int hoffset, eoffset, count;
1229
1230                 /*if(ind){  this sequence was of indefinite length, if this is implicit indefinite impossible maybe
1231                   but tcap dissector uses this to eat the tag length then pass into here... EOC still on there...*/
1232
1233                         if((tvb_get_guint8(tvb, offset)==0)&&(tvb_get_guint8(tvb, offset+1)==0)){
1234                                 if(show_internal_ber_fields){
1235                                         proto_tree_add_text(tree, tvb, s_offset, offset+2, "SEQ EOC");
1236                                 }
1237                                 return end_offset;
1238                         }
1239                         /* } */
1240                 hoffset = offset;
1241                 /* read header and len for next field */
1242                 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
1243                 offset = get_ber_length(tree, tvb, offset, &len, &ind_field);
1244                 eoffset = offset + len;
1245
1246                 /* Look through the Set to see if this class/id exists and 
1247                  * hasn't been seen before
1248                  * Skip check completely if class==ANY
1249                  * of if NOCHKTAG is set
1250                  */
1251
1252
1253                 for(first_pass=TRUE, cset = set, set_idx = 0; cset->func || first_pass; cset++, set_idx++) {
1254
1255                   /* we reset for a second pass when we will look for choices */
1256                   if(!cset->func) {
1257                     first_pass = FALSE;
1258
1259                     cset=set; /* reset to the beginning */
1260                     set_idx = 0;
1261                   }
1262                   
1263                   if((first_pass && ((cset->class==class) && (cset->tag==tag))) ||
1264                      (!first_pass && ((cset->class== BER_CLASS_ANY) && (cset->tag == -1))) ) /* choices */
1265                   {
1266
1267                         if (!(cset->flags & BER_FLAGS_NOOWNTAG) ) {
1268                       /* dissect header and len for field */
1269                                 hoffset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL);
1270                                 hoffset = dissect_ber_length(pinfo, tree, tvb, hoffset, NULL, NULL);
1271                                 length_remaining=tvb_length_remaining(tvb, hoffset);
1272                                 if (length_remaining>eoffset-hoffset-(2*ind_field))
1273                                         length_remaining=eoffset-hoffset-(2*ind_field);
1274                                 next_tvb = tvb_new_subset(tvb, hoffset, length_remaining, eoffset-hoffset-(2*ind_field));
1275                     }
1276                         else {
1277                                 length_remaining=tvb_length_remaining(tvb, hoffset);
1278                                 if (length_remaining>eoffset-hoffset)
1279                                         length_remaining=eoffset-hoffset;
1280                                 next_tvb = tvb_new_subset(tvb, hoffset, length_remaining, eoffset-hoffset);
1281                         }
1282
1283                 
1284                         /* call the dissector for this field */
1285                         /*if    ((eoffset-hoffset)>length_remaining) {*/
1286                                 /* If the field is indefinite (i.e. we dont know the
1287                                  * length) of if the tvb is short, then just
1288                                  * give it all of the tvb and hope for the best.
1289                                  */
1290                                 /*next_tvb = tvb_new_subset(tvb, hoffset, -1, -1);*/
1291                         /*} else {*/
1292                         
1293                         /*}*/
1294
1295 #ifdef DEBUG_BER
1296 {
1297 char *name;
1298 header_field_info *hfinfo;
1299 if(hf_id>=0){
1300 hfinfo = proto_registrar_get_nth(hf_id);
1301 name=hfinfo->name;
1302 } else {
1303 name="unnamed";
1304 }
1305 if(tvb_length_remaining(next_tvb,0)>3){
1306 printf("SET dissect_ber_set(%s) calling subdissector offset:%d len:%d %02x:%02x:%02x\n",name,offset,tvb_length_remaining(next_tvb,0),tvb_get_guint8(next_tvb,0),tvb_get_guint8(next_tvb,1),tvb_get_guint8(next_tvb,2));
1307 }else{
1308 printf("SET dissect_ber_set(%s) calling subdissector\n",name);
1309 }
1310 }
1311 #endif
1312                         if (next_tvb == NULL) {
1313                                 /* Assume that we have a malformed packet. */
1314                                 THROW(ReportedBoundsError);
1315                         }
1316                         count=cset->func(pinfo, tree, next_tvb, 0);
1317
1318                         if(count) {
1319                             /* we found it! */
1320                             if(set_idx < MAX_SET_ELEMENTS)
1321                                   mandatory_fields &= ~(1 << set_idx);
1322
1323                                 offset = eoffset;
1324
1325                                 if(!(cset->flags & BER_FLAGS_NOOWNTAG) ) {
1326                                   /* if we stripped the tag and length we should also strip the EOC is ind_len */
1327                                   if(ind_field == 1){
1328                                           /* skip over EOC */
1329                                           if(show_internal_ber_fields){
1330                                                   proto_tree_add_text(tree, tvb, offset, count, "SET FIELD EOC");
1331                                           }
1332                                   }
1333                                 }
1334                                 break;
1335                         }
1336                   }
1337                 }
1338
1339                 if(!cset->func) {
1340                   /* we didn't find a match */
1341                   proto_tree_add_text(tree, tvb, hoffset, len, "BER Error: Unknown field in SET class:%d(%s) tag:%d",class,val_to_str(class,ber_class_codes,"Unknown"),tag);
1342                   offset = eoffset;                     
1343                 } 
1344         }
1345
1346         if(mandatory_fields) {
1347
1348           /* OK - we didn't find some of the elements we expected */
1349
1350           for(set_idx = 0;  (cset = &set[set_idx])->func && (set_idx < MAX_SET_ELEMENTS); set_idx++) {
1351
1352             if(mandatory_fields & (1 << set_idx)) {
1353
1354               /* here is something we should have seen - but didn't! */
1355               proto_tree_add_text(tree, tvb, offset, len,
1356                                   "BER Error: Missing field in SET class:%d (%s) tag:%d expected",
1357                                   cset->class,val_to_str(cset->class,ber_class_codes,"Unknown"),
1358                                   cset->tag);
1359
1360             }
1361
1362           }
1363         }
1364
1365         /* if we didnt end up at exactly offset, then we ate too many bytes */
1366         if (offset != end_offset) {
1367                 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1368                 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: SET ate %d too many bytes", offset-end_offset);
1369         }
1370         
1371         if(ind){
1372                 /*  need to eat this EOC
1373                   end_offset = tvb_length(tvb);*/
1374                   end_offset += 2; 
1375                   if(show_internal_ber_fields){
1376                                         proto_tree_add_text(tree, tvb, end_offset-2,2 , "SET EOC");
1377                   }
1378         }
1379
1380         return end_offset;
1381
1382 }
1383
1384
1385 /* this function dissects a BER choice 
1386  * If we did not find a matching choice,  just return offset unchanged
1387  * in case it was a CHOICE { } OPTIONAL
1388  */
1389 int
1390 dissect_ber_choice(packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_choice_t *choice, gint hf_id, gint ett_id, gint *branch_taken)
1391 {
1392         gint8 class;
1393         gboolean pc, ind;
1394         gint32 tag;
1395         guint32 len;
1396         const ber_choice_t *ch;
1397         proto_tree *tree=parent_tree;
1398         proto_item *item=NULL;
1399         int end_offset, start_offset, count;
1400         int hoffset = offset;
1401         header_field_info       *hfinfo;
1402         gint length, length_remaining;
1403         tvbuff_t *next_tvb;
1404         gboolean first_pass;
1405
1406 #ifdef DEBUG_BER
1407 {
1408 char *name;
1409 header_field_info *hfinfo;
1410 if(hf_id>=0){
1411 hfinfo = proto_registrar_get_nth(hf_id);
1412 name=hfinfo->name;
1413 } else {
1414 name="unnamed";
1415 }
1416 if(tvb_length_remaining(tvb,offset)>3){
1417 printf("CHOICE dissect_ber_choice(%s) entered offset:%d len:%d %02x:%02x:%02x\n",name,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
1418 }else{
1419 printf("CHOICE dissect_ber_choice(%s) entered len:%d\n",name,tvb_length_remaining(tvb,offset));
1420 }
1421 }
1422 #endif
1423         start_offset=offset;
1424
1425         /* read header and len for choice field */
1426         offset=get_ber_identifier(tvb, offset, &class, &pc, &tag);
1427         offset=get_ber_length(parent_tree, tvb, offset, &len, &ind);
1428           end_offset = offset + len ;
1429         
1430         /* Some sanity checks.  
1431          * The hf field passed to us MUST be an integer type 
1432          */
1433         if(hf_id >= 0){
1434                 hfinfo=proto_registrar_get_nth(hf_id);
1435                 switch(hfinfo->type) {
1436                         case FT_UINT8:
1437                         case FT_UINT16:
1438                         case FT_UINT24:
1439                         case FT_UINT32:
1440                                 break;
1441                 default:
1442                         proto_tree_add_text(tree, tvb, offset, len,"dissect_ber_choice(): Was passed a HF field that was not integer type : %s",hfinfo->abbrev);
1443                         fprintf(stderr,"dissect_ber_choice(): frame:%d offset:%d Was passed a HF field that was not integer type : %s\n",pinfo->fd->num,offset,hfinfo->abbrev);
1444                         return end_offset;
1445                 }
1446         }
1447
1448         
1449
1450         /* loop over all entries until we find the right choice or 
1451            run out of entries */
1452         ch = choice;
1453         if(branch_taken){
1454                 *branch_taken=-1;
1455         }
1456         first_pass = TRUE;
1457         while(ch->func || first_pass){
1458                 if(branch_taken){
1459                         (*branch_taken)++;
1460                 }
1461           /* we reset for a second pass when we will look for choices */
1462           if(!ch->func) {
1463             first_pass = FALSE;
1464             ch = choice; /* reset to the beginning */
1465                 if(branch_taken){
1466                         *branch_taken=-1;
1467                 }
1468           }
1469
1470 choice_try_again:
1471 #ifdef DEBUG_BER
1472 printf("CHOICE testing potential subdissector class:%d:(expected)%d  tag:%d:(expected)%d flags:%d\n",class,ch->class,tag,ch->tag,ch->flags);
1473 #endif
1474                 if( (first_pass && (((ch->class==class)&&(ch->tag==tag))
1475                      ||  ((ch->class==class)&&(ch->tag==-1)&&(ch->flags&BER_FLAGS_NOOWNTAG)))) ||
1476                     (!first_pass && (((ch->class == BER_CLASS_ANY) && (ch->tag == -1)))) /* we failed on the first pass so now try any choices */
1477                 ){
1478                         if(!(ch->flags & BER_FLAGS_NOOWNTAG)){
1479                                 /* dissect header and len for field */
1480                                 hoffset = dissect_ber_identifier(pinfo, tree, tvb, start_offset, NULL, NULL, NULL);
1481                                 hoffset = dissect_ber_length(pinfo, tree, tvb, hoffset, NULL, NULL);
1482                                 start_offset=hoffset;
1483                                 if (ind)
1484                                         {
1485                                         length = len-2;
1486                                         }
1487                                 else
1488                                         {
1489                                         length = len;
1490                                         }
1491
1492                         }
1493                         else
1494                                 length = end_offset- hoffset;
1495                         /* create subtree */
1496                         if(hf_id >= 0){
1497                                 if(parent_tree){
1498                                         item = proto_tree_add_uint(parent_tree, hf_id, tvb, hoffset, end_offset - hoffset, ch->value);
1499                                         tree = proto_item_add_subtree(item, ett_id);
1500                                 }
1501                         }
1502                         length_remaining=tvb_length_remaining(tvb, hoffset);
1503                         if(length_remaining>length)
1504                                 length_remaining=length;
1505                         
1506                         if(first_pass)
1507                         next_tvb=tvb_new_subset(tvb, hoffset, length_remaining, length);
1508                         else
1509                           next_tvb = tvb; /* we didn't make selection on this class/tag so pass it on */
1510
1511 #ifdef DEBUG_BER
1512 {
1513 char *name;
1514 header_field_info *hfinfo;
1515 if(hf_id>=0){
1516 hfinfo = proto_registrar_get_nth(hf_id);
1517 name=hfinfo->name;
1518 } else {
1519 name="unnamed";
1520 }
1521 if(tvb_length_remaining(next_tvb,0)>3){
1522 printf("CHOICE dissect_ber_choice(%s) calling subdissector start_offset:%d offset:%d len:%d %02x:%02x:%02x\n",name,start_offset,offset,tvb_length_remaining(next_tvb,0),tvb_get_guint8(next_tvb,0),tvb_get_guint8(next_tvb,1),tvb_get_guint8(next_tvb,2));
1523 }else{
1524 printf("CHOICE dissect_ber_choice(%s) calling subdissector len:%d\n",name,tvb_length(next_tvb));
1525 }
1526 }
1527 #endif
1528                         if (next_tvb == NULL) {
1529                                 /* Assume that we have a malformed packet. */
1530                                 THROW(ReportedBoundsError);
1531                         }
1532                         count=ch->func(pinfo, tree, next_tvb, 0);
1533 #ifdef DEBUG_BER
1534 {
1535 char *name;
1536 header_field_info *hfinfo;
1537 if(hf_id>=0){
1538 hfinfo = proto_registrar_get_nth(hf_id);
1539 name=hfinfo->name;
1540 } else {
1541 name="unnamed";
1542 }
1543 printf("CHOICE dissect_ber_choice(%s) subdissector ate %d bytes\n",name,count);
1544 }
1545 #endif
1546                         if((count==0)&&(((ch->class==class)&&(ch->tag==-1)&&(ch->flags&BER_FLAGS_NOOWNTAG)) || !first_pass)){
1547                                 /* wrong one, break and try again */
1548                                 ch++;
1549                                 goto choice_try_again;
1550                         }
1551                         if(!(ch->flags & BER_FLAGS_NOOWNTAG)){
1552                          if(ind)
1553                                 {
1554                                 /* we are traversing a indfinite length choice where we did not pass the tag length */
1555                                 /* we need to eat the EOC */
1556                                 if(show_internal_ber_fields){
1557                                         proto_tree_add_text(tree, tvb, start_offset, count+2, "CHOICE EOC");
1558                                 }
1559                          }      
1560                         }
1561                         return end_offset;
1562                         break;
1563                 }
1564                 ch++;
1565         }
1566         if(branch_taken){
1567                 /* none of the branches were taken so set the param 
1568                    back to -1 */
1569                 *branch_taken=-1;
1570         }
1571
1572 #ifdef REMOVED
1573         /*XXX here we should have another flag to the CHOICE to distinguish
1574          * between teh case when we know it is a mandatory   or if the CHOICE is optional == no arm matched */
1575
1576         /* oops no more entries and we still havent found
1577          * our guy :-(
1578          */
1579         proto_tree_add_text(tree, tvb, offset, len, "BER Error: This choice field was not found.");
1580
1581         return end_offset;
1582 #endif
1583
1584         return start_offset;
1585 }
1586
1587 #if 0
1588 /* this function dissects a BER GeneralString
1589  */
1590 int
1591 dissect_ber_GeneralString(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, char *name_string, int name_len)
1592 {
1593         gint8 class;
1594         gboolean pc;
1595         gint32 tag;
1596         guint32 len;
1597         int end_offset;
1598         char str_arr[256];
1599         guint32 max_len;
1600         char *str;
1601
1602         str=str_arr;
1603         max_len=255;
1604         if(name_string){
1605                 str=name_string;
1606                 max_len=name_len;
1607         }
1608
1609         /* first we must read the GeneralString header */
1610         offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
1611         offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
1612         end_offset=offset+len;
1613
1614         /* sanity check: we only handle Universal GeneralString*/
1615         if( (class!=BER_CLASS_UNI)
1616           ||(tag!=BER_UNI_TAG_GENSTR) ){
1617                 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1618                 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: GeneralString expected but Class:%d PC:%d Tag:%d was unexpected", class, pc, tag);
1619                 return end_offset;
1620         }
1621
1622         if(len>=(max_len-1)){
1623                 len=max_len-1;
1624         }
1625         
1626         tvb_memcpy(tvb, str, offset, len);
1627         str[len]=0;
1628
1629         if(hf_id >= 0){
1630                 proto_tree_add_string(tree, hf_id, tvb, offset, len, str);
1631         }
1632
1633         return end_offset;
1634 }
1635 #endif
1636 int dissect_ber_restricted_string(gboolean implicit_tag, gint32 type, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, tvbuff_t **out_tvb) {
1637         gint8 class;
1638         gboolean pc;
1639         gint32 tag;
1640         guint32 len;
1641         int eoffset;
1642         int hoffset = offset;
1643
1644 #ifdef DEBUG_BER
1645 {
1646 char *name;
1647 header_field_info *hfinfo;
1648 if(hf_id>=0){
1649 hfinfo = proto_registrar_get_nth(hf_id);
1650 name=hfinfo->name;
1651 } else {
1652 name="unnamed";
1653 }
1654 if(tvb_length_remaining(tvb,offset)>3){
1655 printf("RESTRICTED STRING dissect_ber_octet string(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x\n",name,implicit_tag,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
1656 }else{
1657 printf("RESTRICTED STRING dissect_ber_octet_string(%s) entered\n",name);
1658 }
1659 }
1660 #endif
1661
1662         if(!implicit_tag) {
1663                 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
1664                 offset = get_ber_length(tree, tvb, offset, &len, NULL);
1665                 eoffset = offset + len;
1666
1667                 /* sanity check */
1668                 if( (class!=BER_CLASS_UNI)
1669                   ||(tag != type) ){
1670                     tvb_ensure_bytes_exist(tvb, offset-2, 2);
1671                     proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: String with tag=%d expected but Class:%d PC:%d Tag:%d was unexpected", type, class, pc, tag);
1672                         return eoffset;
1673                 }
1674         }
1675
1676         /* 8.21.3 */
1677         return dissect_ber_octet_string(implicit_tag, pinfo, tree, tvb, hoffset, hf_id, out_tvb);
1678 }
1679
1680 int
1681 dissect_ber_GeneralString(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, char *name_string, guint name_len)
1682 {
1683         tvbuff_t *out_tvb = NULL;
1684
1685         offset = dissect_ber_restricted_string(FALSE, BER_UNI_TAG_GeneralString, pinfo, tree, tvb, offset, hf_id, (name_string)?&out_tvb:NULL);
1686
1687         if(name_string) {
1688                 if(out_tvb && tvb_length(out_tvb) >= name_len) {
1689                         tvb_memcpy(out_tvb, name_string, 0, name_len-1);
1690                         name_string[name_len-1] = '\0';
1691                 } else if(out_tvb) {
1692                         tvb_memcpy(out_tvb, name_string, 0, -1);
1693                         name_string[tvb_length(out_tvb)] = '\0';
1694                 }
1695         }
1696
1697         return offset;
1698 }
1699
1700 /* 8.19 Encoding of an object identifier value */
1701 int dissect_ber_object_identifier(gboolean implicit_tag, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id, char *value_string) {
1702         gint8 class;
1703         gboolean pc;
1704         gint32 tag;
1705         guint32 len;
1706         int eoffset;
1707         char *str, *name;
1708         proto_item *item;
1709
1710         str=ep_alloc(MAX_OID_STR_LEN);
1711 #ifdef DEBUG_BER
1712 {
1713 char *name;
1714 header_field_info *hfinfo;
1715 if(hf_id>=0){
1716 hfinfo = proto_registrar_get_nth(hf_id);
1717 name=hfinfo->name;
1718 } else {
1719 name="unnamed";
1720 }
1721 if(tvb_length_remaining(tvb,offset)>3){
1722 printf("OBJECT IDENTIFIER dissect_ber_object_identifier(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x\n",name,implicit_tag,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
1723 }else{
1724 printf("OBJECT IDENTIFIER dissect_ber_object_identifier(%s) entered\n",name);
1725 }
1726 }
1727 #endif
1728
1729         if(value_string) {
1730                 value_string[0] = '\0';
1731         }
1732
1733         if(!implicit_tag) {
1734                 /* sanity check */
1735                 offset = dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
1736                 offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
1737                 eoffset = offset + len;
1738                 if( (class!=BER_CLASS_UNI)
1739                   ||(tag != BER_UNI_TAG_OID) ){
1740                     tvb_ensure_bytes_exist(tvb, offset-2, 2);
1741                     proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: Object Identifier expected but Class:%d PC:%d Tag:%d was unexpected", class, pc, tag);
1742                         return eoffset;
1743                 }
1744         } else {
1745                 len=tvb_length_remaining(tvb,offset);
1746                 eoffset=offset+len;
1747         }
1748
1749         oid_to_str_buf(tvb_get_ptr(tvb, offset, len), len, str, MAX_OID_STR_LEN);
1750         offset += len;
1751
1752         if(hf_id >= 0) {
1753                 item=proto_tree_add_string(tree, hf_id, tvb, offset - len, len, str);
1754                 /* see if we know the name of this oid */
1755                 if(item){
1756                         name=g_hash_table_lookup(oid_table, str);
1757                         if(name){
1758                                 proto_item_append_text(item, " (%s)", name);
1759                         }
1760                 }
1761         }
1762
1763         if(value_string) {
1764                 strcpy(value_string, str);
1765         }
1766
1767         return eoffset;
1768 }
1769
1770 static int dissect_ber_sq_of(gboolean implicit_tag, gint32 type, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_sequence_t *seq, gint hf_id, gint ett_id) {
1771         gint8 class;
1772         gboolean pc, ind = FALSE, ind_field;
1773         gint32 tag;
1774         guint32 len;
1775
1776         proto_tree *tree = parent_tree;
1777         proto_item *item = NULL;
1778         int cnt, hoffset, end_offset;
1779         header_field_info *hfi;
1780
1781 #ifdef DEBUG_BER
1782 {
1783 char *name;
1784 header_field_info *hfinfo;
1785 if(hf_id>=0){
1786 hfinfo = proto_registrar_get_nth(hf_id);
1787 name=hfinfo->name;
1788 } else {
1789 name="unnamed";
1790 }
1791 if(tvb_length_remaining(tvb,offset)>3){
1792 printf("SQ OF dissect_ber_sq_of(%s) entered implicit_tag:%d offset:%d len:%d %02x:%02x:%02x\n",name,implicit_tag,offset,tvb_length_remaining(tvb,offset),tvb_get_guint8(tvb,offset),tvb_get_guint8(tvb,offset+1),tvb_get_guint8(tvb,offset+2));
1793 }else{
1794 printf("SQ OF dissect_ber_sq_of(%s) entered\n",name);
1795 }
1796 }
1797 #endif
1798
1799         if(!implicit_tag){
1800                 /* first we must read the sequence header */
1801                 offset = dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
1802                 offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, &ind);
1803                 if(ind){
1804                   /* if the length is indefinite we dont really know (yet) where the
1805                    * object ends so assume it spans the rest of the tvb for now.
1806                    */
1807                   end_offset = offset + len;
1808                 } else {
1809                   end_offset = offset + len;
1810                 }
1811
1812                 /* sanity check: we only handle Constructed Universal Sequences */
1813                 if((class!=BER_CLASS_APP)&&(class!=BER_CLASS_PRI))
1814                 if(!pc
1815                         ||(!implicit_tag&&((class!=BER_CLASS_UNI)
1816                                                         ||(tag!=type)))) {
1817                         tvb_ensure_bytes_exist(tvb, offset-2, 2);
1818                         proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: %s Of expected but Class:%d PC:%d Tag:%d was unexpected", 
1819                                                         (type==BER_UNI_TAG_SEQUENCE)?"Set":"Sequence", class, pc, tag);
1820                         return end_offset;
1821                 }
1822         } else {
1823                 /* the tvb length should be correct now nope we could be comming from an implicit choice or sequence, thus we 
1824                 read the items we match and return the length*/
1825                 len=tvb_length_remaining(tvb,offset);
1826                 end_offset = offset + len;
1827         }
1828
1829         /* count number of items */
1830         cnt = 0;
1831         hoffset = offset;
1832         /* only count the number of items IFF we have the full blob,
1833          * else this will just generate a [short frame] before we even start
1834          * dissecting a single item.
1835          */
1836         /* XXX Do we really need to count them at all ?  ronnie */
1837         if(tvb_length_remaining(tvb, offset)==tvb_reported_length_remaining(tvb, offset)){
1838                 while (offset < end_offset){
1839                         guint32 len;
1840         
1841                         if(ind){ /* this sequence of was of indefinite length, so check for EOC */
1842                                 if((tvb_get_guint8(tvb, offset)==0)&&(tvb_get_guint8(tvb, offset+1)==0)){                               
1843                                         break;
1844                                 }
1845                         }
1846
1847                         /* read header and len for next field */
1848                         offset = get_ber_identifier(tvb, offset, NULL, NULL, NULL);
1849                         offset = get_ber_length(tree, tvb, offset, &len, NULL);
1850                         /* best place to get real length of implicit sequence of or set of is here... */
1851                         /* adjust end_offset if we find somthing that doesnt match */
1852                         offset += len;
1853                         cnt++;
1854                 }
1855         }
1856         offset = hoffset;
1857
1858         /* create subtree */
1859         if(hf_id >= 0) {
1860                 hfi = proto_registrar_get_nth(hf_id);
1861                 if(parent_tree){
1862                         if(hfi->type == FT_NONE) {
1863                                 item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE);
1864                                 proto_item_append_text(item, ":");
1865                         } else {
1866                                 item = proto_tree_add_uint(parent_tree, hf_id, tvb, offset, len, cnt);
1867                                 proto_item_append_text(item, (cnt==1)?" item":" items");
1868                         }
1869                         tree = proto_item_add_subtree(item, ett_id);
1870                 }
1871         }
1872
1873         /* loop over all entries until we reach the end of the sequence */
1874         while (offset < end_offset){
1875                 gint8 class;
1876                 gboolean pc;
1877                 gint32 tag;
1878                 guint32 len;
1879                 int eoffset;
1880                 int hoffset, count;
1881
1882                 hoffset = offset;
1883                 if(ind){ /*this sequence of was of indefinite length, so check for EOC */
1884                         if((tvb_get_guint8(tvb, offset)==0)&&(tvb_get_guint8(tvb, offset+1)==0)){
1885                                 if(show_internal_ber_fields){
1886                                         proto_tree_add_text(tree, tvb, hoffset, end_offset-hoffset, "SEQ OF EOC");
1887                                 }
1888                                 return offset+2;
1889                         }
1890                 }
1891                 /* read header and len for next field */
1892                 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
1893                 offset = get_ber_length(tree, tvb, offset, &len, &ind_field);
1894                 if(ind_field){
1895                         /* if the length is indefinite we dont really know (yet) where the
1896                          * object ends so assume it spans the rest of the tvb for now.
1897                          */
1898                         eoffset = offset + len;
1899                 } else {
1900                         eoffset = offset + len;
1901                 }
1902
1903                 /* verify that this one is the one we want */
1904                 /* ahup if we are implicit then we return to the uper layer how much we have used */
1905                 if(seq->class!=BER_CLASS_ANY){
1906                   if((seq->class!=class)
1907                         ||(seq->tag!=tag) ){
1908                         if(!(seq->flags & BER_FLAGS_NOTCHKTAG)) {
1909                                 proto_tree_add_text(tree, tvb, offset, len, "BER Error: Wrong field in SQ OF");
1910                                 offset = eoffset;
1911                                 continue;
1912                                 /* wrong.... */
1913                         }
1914                   }
1915                 }
1916
1917                 if(!(seq->flags & BER_FLAGS_NOOWNTAG) && !(seq->flags & BER_FLAGS_IMPLTAG)) {
1918                         /* dissect header and len for field */
1919                         hoffset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL);
1920                         hoffset = dissect_ber_length(pinfo, tree, tvb, hoffset, NULL, NULL);
1921                 }
1922                 
1923                 /* call the dissector for this field */
1924                 count=seq->func(pinfo, tree, tvb, hoffset)-hoffset;
1925                                 /* hold on if we are implicit and the result is zero, i.e. the item in the sequence of 
1926                                 doesnt match the next item, thus this implicit sequence is over, return the number of bytes
1927                                 we have eaten to allow the possible upper sequence continue... */
1928                 cnt++; /* rubbish*/
1929                 if(ind_field){
1930                         /* previous field was of indefinite length so we have
1931                          * no choice but use whatever the subdissector told us
1932                          * as size for the field.
1933                          * not any more the length should be correct
1934                          */
1935                         offset = eoffset;
1936                 } else {
1937                         offset = eoffset;
1938                 }
1939         }
1940
1941         /* if we didnt end up at exactly offset, then we ate too many bytes */
1942         if(offset != end_offset) {
1943                 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1944                 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: %s Of ate %d too many bytes", 
1945                                                         (type==BER_UNI_TAG_SEQUENCE)?"Set":"Sequence", offset-end_offset);
1946         }
1947
1948         return end_offset;
1949 }
1950
1951 int dissect_ber_sequence_of(gboolean implicit_tag, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_sequence_t *seq, gint hf_id, gint ett_id) {
1952         return dissect_ber_sq_of(implicit_tag, BER_UNI_TAG_SEQUENCE, pinfo, parent_tree, tvb, offset, seq, hf_id, ett_id);
1953 }
1954
1955 int dissect_ber_set_of(gboolean implicit_tag, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const ber_sequence_t *seq, gint hf_id, gint ett_id) {
1956         return dissect_ber_sq_of(implicit_tag, BER_UNI_TAG_SET, pinfo, parent_tree, tvb, offset, seq, hf_id, ett_id);
1957 }
1958
1959 int 
1960 dissect_ber_GeneralizedTime(gboolean implicit_tag, packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_id)
1961 {
1962         char str[32];
1963         const guint8 *tmpstr;
1964         gint8 class;
1965         gboolean pc;
1966         gint32 tag;
1967         guint32 len;
1968         int end_offset;
1969
1970         if(!implicit_tag){
1971           offset=dissect_ber_identifier(pinfo, tree, tvb, offset, &class, &pc, &tag);
1972           offset=dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
1973           end_offset=offset+len;
1974
1975           /* sanity check. we only handle universal/generalized time */
1976           if( (class!=BER_CLASS_UNI)
1977           ||(tag!=BER_UNI_TAG_GeneralizedTime)){
1978                 tvb_ensure_bytes_exist(tvb, offset-2, 2);
1979                 proto_tree_add_text(tree, tvb, offset-2, 2, "BER Error: GeneralizedTime expected but Class:%d PC:%d Tag:%d was unexpected", class, pc, tag);
1980                 return end_offset;
1981                 end_offset=offset+len;
1982           }
1983         } else {
1984           len=tvb_length_remaining(tvb,offset);
1985           end_offset=offset+len;
1986         }
1987           
1988
1989         tmpstr=tvb_get_ptr(tvb, offset, len);
1990         snprintf(str, 31, "%.4s-%.2s-%.2s %.2s:%.2s:%.2s (%.1s)",
1991                 tmpstr, tmpstr+4, tmpstr+6, tmpstr+8,
1992                 tmpstr+10, tmpstr+12, tmpstr+14);
1993         str[31]=0; /* just in case ... */
1994                 
1995         if(hf_id >= 0){
1996                 proto_tree_add_string(tree, hf_id, tvb, offset, len, str);
1997         }
1998
1999         offset+=len;
2000         return offset;
2001 }
2002
2003 /* 8.6 Encoding of a bitstring value */
2004 int dissect_ber_bitstring(gboolean implicit_tag, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, const asn_namedbit *named_bits, gint hf_id, gint ett_id, tvbuff_t **out_tvb) 
2005 {
2006         gint8 class;
2007         gboolean pc, ind;
2008         gint32 tag;
2009         guint32 len;
2010         guint8 pad=0, b0, b1, val;
2011         int end_offset;
2012         proto_item *item = NULL;
2013         proto_tree *tree = NULL;
2014         const asn_namedbit *nb;
2015         char *sep;
2016         gboolean term;
2017
2018         if(!implicit_tag){
2019           /* read header and len for the octet string */
2020           offset = dissect_ber_identifier(pinfo, parent_tree, tvb, offset, &class, &pc, &tag);
2021           offset = dissect_ber_length(pinfo, parent_tree, tvb, offset, &len, &ind);
2022           end_offset = offset + len;
2023
2024           /* sanity check: we only handle Universal BitSrings */
2025           if(!implicit_tag) {
2026                 if( (class!=BER_CLASS_UNI)
2027                   ||(tag!=BER_UNI_TAG_BITSTRING) ){
2028                     tvb_ensure_bytes_exist(tvb, offset-2, 2);
2029                     proto_tree_add_text(parent_tree, tvb, offset-2, 2, "BER Error: BitString expected but Class:%d PC:%d Tag:%d was unexpected", class, pc, tag);
2030                         return end_offset;
2031                 }
2032           }
2033         } else {
2034           pc=0;
2035           len=tvb_length_remaining(tvb,offset);
2036           end_offset=offset+len;
2037         }
2038
2039         ber_last_created_item = NULL;
2040
2041         if(pc) {
2042                 /* constructed */
2043                 /* TO DO */
2044         } else {
2045                 /* primitive */
2046                 /* padding */
2047                 pad = tvb_get_guint8(tvb, offset);
2048                 proto_tree_add_item(parent_tree, hf_ber_bitstring_padding, tvb, offset, 1, FALSE);
2049                 offset++;
2050                 len--;
2051                 if( hf_id >= 0) {
2052                         item = proto_tree_add_item(parent_tree, hf_id, tvb, offset, len, FALSE);
2053                         ber_last_created_item = item;
2054                         if(ett_id != -1) {
2055                                 tree = proto_item_add_subtree(item, ett_id);
2056                         }
2057                 }
2058                 if(out_tvb) {
2059                         if(len<=(guint32)tvb_length_remaining(tvb, offset)){
2060                                 *out_tvb = tvb_new_subset(tvb, offset, len, len);
2061                         } else {
2062                                 *out_tvb = tvb_new_subset(tvb, offset, -1, -1);
2063                         }
2064                 }
2065         }
2066
2067         if(named_bits) {
2068                 sep = " (";
2069                 term = FALSE;
2070                 nb = named_bits;
2071                 while (nb->p_id) {
2072                         if(nb->bit < (8*len-pad)) {
2073                                 val = tvb_get_guint8(tvb, offset + nb->bit/8);
2074                                 val &= 0x80 >> (nb->bit%8);
2075                                 b0 = (nb->gb0 == -1) ? nb->bit/8 :
2076                                                        ((guint32)nb->gb0)/8;
2077                                 b1 = (nb->gb1 == -1) ? nb->bit/8 :
2078                                                        ((guint32)nb->gb1)/8;
2079                                 proto_tree_add_item(tree, *(nb->p_id), tvb, offset + b0, b1 - b0 + 1, FALSE);
2080                         } else {  /* 8.6.2.4 */
2081                                 val = 0;
2082                                 proto_tree_add_boolean(tree, *(nb->p_id), tvb, offset + len, 0, 0x00);
2083                         }
2084                         if(val) {
2085                                 if(item && nb->tstr) {
2086                                         proto_item_append_text(item, "%s%s", sep, nb->tstr);
2087                                         sep = ", ";
2088                                         term = TRUE;
2089                                 }
2090                         } else {
2091                                 if(item && nb->fstr) {
2092                                         proto_item_append_text(item, "%s%s", sep, nb->fstr);
2093                                         sep = ", ";
2094                                         term = TRUE;
2095                                 }
2096                         }
2097                         nb++;
2098                 }
2099                 if(term)
2100                         proto_item_append_text(item, ")");
2101         }
2102
2103         return end_offset;
2104 }
2105
2106 int dissect_ber_bitstring32(gboolean implicit_tag, packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, int **bit_fields, gint hf_id, gint ett_id, tvbuff_t **out_tvb) 
2107 {
2108         tvbuff_t *tmp_tvb = NULL;
2109         proto_tree *tree;
2110         guint32 val;
2111         int **bf;
2112         header_field_info *hfi;
2113         char *sep;
2114         gboolean term;
2115         unsigned int i, tvb_len;
2116
2117         offset = dissect_ber_bitstring(implicit_tag, pinfo, parent_tree, tvb, offset, NULL, hf_id, ett_id, &tmp_tvb);
2118         
2119         tree = proto_item_get_subtree(ber_last_created_item);
2120         if(bit_fields && tree && tmp_tvb) {
2121                 /* tmp_tvb points to the actual bitstring (including any pad bits at the end.
2122                  * note that this bitstring is not neccessarily always encoded as 4 bytes
2123                  * so we have to read it byte by byte.
2124                  */
2125                 val=0;
2126                 tvb_len=tvb_length(tmp_tvb);
2127                 for(i=0;i<4;i++){
2128                         val<<=8;
2129                         if(i<tvb_len){
2130                                 val|=tvb_get_guint8(tmp_tvb,i);
2131                         }
2132                 }
2133                 bf = bit_fields;
2134                 sep = " (";
2135                 term = FALSE;
2136                 while (*bf) {
2137                         proto_tree_add_boolean(tree, **bf, tmp_tvb, 0, tvb_len, val);
2138                         if (**bf >= 0) {
2139                                 hfi = proto_registrar_get_nth(**bf);
2140                                 if(val & hfi->bitmask) {
2141                                         proto_item_append_text(ber_last_created_item, "%s%s", sep, hfi->name);
2142                                         sep = ", ";
2143                                         term = TRUE;
2144                                 }
2145                         }
2146                         bf++;
2147                 }
2148                 if(term)
2149                         proto_item_append_text(ber_last_created_item, ")");
2150         }
2151
2152         if(out_tvb)
2153                 *out_tvb = tmp_tvb;
2154
2155         return offset;
2156 }
2157
2158 void
2159 proto_register_ber(void)
2160 {
2161     static hf_register_info hf[] = {
2162         { &hf_ber_id_class, {
2163             "Class", "ber.id.class", FT_UINT8, BASE_DEC,
2164             VALS(ber_class_codes), 0xc0, "Class of BER TLV Identifier", HFILL }},
2165         { &hf_ber_bitstring_padding, {
2166             "Padding", "ber.bitstring.padding", FT_UINT8, BASE_DEC,
2167             NULL, 0x0, "Number of unsused bits in the last octet of the bitstring", HFILL }},
2168         { &hf_ber_id_pc, {
2169             "P/C", "ber.id.pc", FT_BOOLEAN, 8,
2170             TFS(&ber_pc_codes), 0x20, "Primitive or Constructed BER encoding", HFILL }},
2171         { &hf_ber_id_uni_tag, {
2172             "Tag", "ber.id.uni_tag", FT_UINT8, BASE_DEC,
2173             VALS(ber_uni_tag_codes), 0x1f, "Universal tag type", HFILL }},
2174         { &hf_ber_id_uni_tag_ext, {
2175             "Tag", "ber.id.uni_tag", FT_UINT32, BASE_DEC,
2176             NULL, 0, "Universal tag type", HFILL }},
2177         { &hf_ber_id_tag, {
2178             "Tag", "ber.id.tag", FT_UINT8, BASE_DEC,
2179             NULL, 0x1f, "Tag value for non-Universal classes", HFILL }},
2180         { &hf_ber_id_tag_ext, {
2181             "Tag", "ber.id.tag", FT_UINT32, BASE_DEC,
2182             NULL, 0, "Tag value for non-Universal classes", HFILL }},
2183         { &hf_ber_length, {
2184             "Length", "ber.length", FT_UINT32, BASE_DEC,
2185             NULL, 0, "Length of contents", HFILL }},
2186         { &hf_ber_unknown_OCTETSTRING, {
2187             "OCTETSTRING", "ber.unknown.OCTETSTRING", FT_BYTES, BASE_HEX,
2188             NULL, 0, "This is an unknown OCTETSTRING", HFILL }},
2189         { &hf_ber_unknown_OID, {
2190             "OID", "ber.unknown.OID", FT_STRING, BASE_NONE,
2191             NULL, 0, "This is an unknown Object Identifier", HFILL }},
2192                 { &hf_ber_unknown_GraphicString, {
2193             "GRAPHICSTRING", "ber.unknown.GRAPHICSTRING", FT_STRING, BASE_HEX,
2194             NULL, 0, "This is an unknown GRAPHICSTRING", HFILL }},
2195
2196         { &hf_ber_unknown_NumericString, {
2197             "NumericString", "ber.unknown.NumericString", FT_STRING, BASE_NONE,
2198             NULL, 0, "This is an unknown NumericString", HFILL }},
2199         { &hf_ber_unknown_PrintableString, {
2200             "PrintableString", "ber.unknown.PrintableString", FT_STRING, BASE_NONE,
2201             NULL, 0, "This is an unknown PrintableString", HFILL }},
2202         { &hf_ber_unknown_IA5String, {
2203             "IA5String", "ber.unknown.IA5String", FT_STRING, BASE_NONE,
2204             NULL, 0, "This is an unknown IA5String", HFILL }},
2205         { &hf_ber_unknown_INTEGER, {
2206             "INTEGER", "ber.unknown.INTEGER", FT_UINT32, BASE_DEC,
2207             NULL, 0, "This is an unknown INTEGER", HFILL }},
2208         { &hf_ber_unknown_ENUMERATED, {
2209             "ENUMERATED", "ber.unknown.ENUMERATED", FT_UINT32, BASE_DEC,
2210             NULL, 0, "This is an unknown ENUMERATED", HFILL }},
2211
2212     };
2213
2214     static gint *ett[] = {
2215         &ett_ber_octet_string,
2216         &ett_ber_unknown,
2217         &ett_ber_SEQUENCE,
2218     };
2219     module_t *ber_module;
2220
2221     proto_ber = proto_register_protocol("Basic Encoding Rules (ASN.1 X.690)", "BER", "ber");
2222     proto_register_field_array(proto_ber, hf, array_length(hf));
2223     proto_register_subtree_array(ett, array_length(ett));
2224
2225         proto_set_cant_toggle(proto_ber);
2226
2227     /* Register preferences */
2228     ber_module = prefs_register_protocol(proto_ber, NULL);
2229     prefs_register_bool_preference(ber_module, "show_internals",
2230         "Show internal BER encapsulation tokens",
2231         "Whether the dissector should also display internal"
2232         " ASN.1 BER details such as Identifier and Length fields", &show_internal_ber_fields);
2233
2234     ber_oid_dissector_table = register_dissector_table("ber.oid", "BER OID Dissectors", FT_STRING, BASE_NONE);
2235     oid_table=g_hash_table_new(g_str_hash, g_str_equal);
2236 }
2237
2238 void
2239 proto_reg_handoff_ber(void)
2240 {
2241                 register_ber_oid_name("2.1.1","joint-iso-itu-t(2) asn1(1) basic-encoding(1)");
2242
2243 }
2244