aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-per.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-per.c')
-rw-r--r--epan/dissectors/packet-per.c1544
1 files changed, 1544 insertions, 0 deletions
diff --git a/epan/dissectors/packet-per.c b/epan/dissectors/packet-per.c
new file mode 100644
index 0000000000..a18355ee4a
--- /dev/null
+++ b/epan/dissectors/packet-per.c
@@ -0,0 +1,1544 @@
+/*
+XXX all this offset>>3 and calculations of bytes in the tvb everytime
+we put something in the tree is just silly. should be replaced with some
+proper helper routines
+*/
+/* packet-per.c
+ * Routines for dissection of ASN.1 Aligned PER
+ * 2003 Ronnie Sahlberg
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <epan/packet.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "prefs.h"
+#include "packet-per.h"
+
+
+static int proto_per = -1;
+static int hf_per_GeneralString_length = -1;
+static int hf_per_extension_bit = -1;
+static int hf_per_extension_present_bit = -1;
+static int hf_per_choice_extension = -1;
+static int hf_per_num_sequence_extensions = -1;
+static int hf_per_small_number_bit = -1;
+static int hf_per_optional_field_bit = -1;
+static int hf_per_sequence_of_length = -1;
+static int hf_per_object_identifier_length = -1;
+static int hf_per_open_type_length = -1;
+static int hf_per_octet_string_length = -1;
+static int hf_per_bit_string_length = -1;
+
+static gint ett_per_sequence_of_item = -1;
+
+
+/*
+#define DEBUG_ENTRY(x) \
+printf("#%d %s tvb:0x%08x\n",pinfo->fd->num,x,(int)tvb);
+*/
+#define DEBUG_ENTRY(x) \
+ ;
+
+
+
+/* whether the PER helpers should put the internal PER fields into the tree
+ or not.
+*/
+static guint display_internal_per_fields = FALSE;
+
+
+
+static const true_false_string tfs_extension_present_bit = {
+ "",
+ ""
+};
+static const true_false_string tfs_extension_bit = {
+ "Extension bit is set",
+ "Extension bit is clear"
+};
+static const true_false_string tfs_small_number_bit = {
+ "The number is small, 0-63",
+ "The number is large, >63"
+};
+static const true_false_string tfs_optional_field_bit = {
+ "",
+ ""
+};
+
+
+
+
+/* 10.9 */
+/* this decodes and returns a length determinant according to 10.9 */
+guint32
+dissect_per_length_determinant(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index, guint32 *length)
+{
+ guint8 byte;
+ guint32 len;
+
+ if(!length){
+ length=&len;
+ }
+
+ /* byte aligned */
+ if(offset&0x07){
+ offset=(offset&0xfffffff8)+8;
+ }
+ byte=tvb_get_guint8(tvb, offset>>3);
+ offset+=8;
+
+ if((byte&0x80)==0){
+ *length=byte;
+ if(hf_index!=-1){
+ proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-1, 1, *length);
+ }
+ return offset;
+ }
+ if((byte&0xc0)==0x80){
+ *length=(byte&0x3f);
+ *length=((*length)<<8)+tvb_get_guint8(tvb, offset>>3);
+ offset+=8;
+ if(hf_index!=-1){
+ proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-2, 2, *length);
+ }
+ return offset;
+ }
+ PER_NOT_DECODED_YET("10.9.3.8.1");
+ return offset;
+}
+
+/* 10.6 normally small non-negative whole number */
+static guint32
+dissect_per_normally_small_nonnegative_whole_number(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, guint32 *length)
+{
+ gboolean small_number;
+ guint32 len;
+
+DEBUG_ENTRY("dissect_per_normally_small_nonnegative_whole_number");
+ if(!length){
+ length=&len;
+ }
+
+ offset=dissect_per_boolean(tvb, offset, pinfo, tree, hf_per_small_number_bit, &small_number, NULL);
+ if(!small_number){
+ int i;
+ /* 10.6.1 */
+ *length=0;
+ for(i=0;i<6;i++){
+ offset=dissect_per_boolean(tvb, offset, pinfo, tree, -1, &small_number, NULL);
+ *length<<=1;
+ if(small_number){
+ *length|=1;
+ }
+ }
+ if(hf_index!=-1){
+ if((offset&0x07)<7){
+ proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-1, 1, *length);
+ } else {
+ proto_tree_add_uint(tree, hf_index, tvb, (offset>>3), 1, *length);
+ }
+ }
+ return offset;
+ }
+
+ /* 10.6.2 */
+ offset=dissect_per_length_determinant(tvb, offset, pinfo, tree, hf_index, length);
+
+ return offset;
+}
+
+
+
+/* this function reads a GeneralString */
+/* currently based on pure guesswork since RFC2833 didnt tell me much
+ i guess that the PER encoding for this is a normally-small-whole-number
+ followed by a ascii string.
+
+ based on pure guesswork. it looks ok in the only capture i have where
+ there is a 1 byte general string encoded
+*/
+guint32
+dissect_per_GeneralString(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index)
+{
+ proto_tree *etr=NULL;
+ guint32 length;
+
+ if(display_internal_per_fields){
+ etr=tree;
+ }
+
+ offset=dissect_per_length_determinant(tvb, offset, pinfo, etr, hf_per_GeneralString_length, &length);
+
+
+ proto_tree_add_item(tree, hf_index, tvb, offset>>3, length, FALSE);
+
+ offset+=length*8;
+
+ return offset;
+}
+
+/* 19 this function dissects a sequence of */
+static guint32
+dissect_per_sequence_of_helper(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int (*func)(tvbuff_t *, int , packet_info *, proto_tree *), guint32 length)
+{
+ guint32 i;
+
+DEBUG_ENTRY("dissect_per_sequence_of_helper");
+ for(i=0;i<length;i++){
+ guint32 lold_offset=offset;
+ proto_item *litem;
+ proto_tree *ltree;
+
+ litem=proto_tree_add_text(tree, tvb, offset>>3, 0, "Item %d", i);
+ ltree=proto_item_add_subtree(litem, ett_per_sequence_of_item);
+
+ offset=(*func)(tvb, offset, pinfo, ltree);
+ proto_item_set_len(litem, (offset>>3)!=(lold_offset>>3)?(offset>>3)-(lold_offset>>3):1);
+ }
+
+ return offset;
+}
+guint32
+dissect_per_sequence_of(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *parent_tree, int hf_index, gint ett_index, int (*func)(tvbuff_t *, int , packet_info *, proto_tree *))
+{
+ proto_item *item;
+ proto_tree *tree;
+ guint32 old_offset=offset;
+ guint32 length;
+ proto_tree *etr = NULL;
+
+DEBUG_ENTRY("dissect_per_sequence_of");
+
+ item=proto_tree_add_item(parent_tree, hf_index, tvb, offset>>3, 0, FALSE);
+ tree=proto_item_add_subtree(item, ett_index);
+
+ /* semi-constrained whole number for number of elements */
+ /* each element encoded as 10.9 */
+
+ if(display_internal_per_fields){
+ etr=tree;
+ }
+ offset=dissect_per_length_determinant(tvb, offset, pinfo, etr, hf_per_sequence_of_length, &length);
+
+ offset=dissect_per_sequence_of_helper(tvb, offset, pinfo, tree, func, length);
+
+
+ proto_item_set_len(item, (offset>>3)!=(old_offset>>3)?(offset>>3)-(old_offset>>3):1);
+ return offset;
+}
+
+
+/* dissect a constrained IA5String that consists of the full ASCII set,
+ i.e. no FROM stuff limiting the alphabet
+*/
+guint32
+dissect_per_IA5String(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len)
+{
+ offset=dissect_per_octet_string(tvb, offset, pinfo, tree, hf_index, min_len, max_len, NULL, NULL);
+
+ return offset;
+}
+
+/* XXX we dont do >64k length strings yet */
+guint32
+dissect_per_restricted_character_string(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len, char *alphabet, int alphabet_length)
+{
+ guint32 length;
+ gboolean byte_aligned;
+ static char str[1024];
+ guint char_pos;
+ int bits_per_char;
+ guint32 old_offset;
+
+DEBUG_ENTRY("dissect_per_restricted_character_string");
+ /* xx.x if the length is 0 bytes there will be no encoding */
+ if(max_len==0){
+ return offset;
+ }
+
+
+ if(min_len==-1){
+ min_len=0;
+ }
+
+
+ /* xx.x */
+ length=max_len;
+ if(min_len!=max_len){
+ proto_tree *etr = NULL;
+
+ if(display_internal_per_fields){
+ etr=tree;
+ }
+ offset=dissect_per_constrained_integer(tvb, offset, pinfo,
+ etr, hf_per_octet_string_length, min_len, max_len,
+ &length, NULL, FALSE);
+ }
+
+
+ /* xx.x if length is fixed or constrained to be less than or equal to
+ two bytes, then it will not be byte aligned. */
+ byte_aligned=TRUE;
+ if((min_len==max_len)&&(max_len<=2)){
+ byte_aligned=FALSE;
+ }
+ if(max_len<2){
+ byte_aligned=FALSE;
+ }
+ if(!length){
+ /* there is no string at all, so dont do any byte alignment */
+ byte_aligned=FALSE;
+ }
+
+ if(byte_aligned){
+ if(offset&0x07){
+ offset=(offset&0xfffffff8)+8;
+ }
+ }
+
+
+ if(length>=1024){
+ PER_NOT_DECODED_YET("restricted char string too long");
+ length=1024;
+ }
+
+ /* 27.5.2 depending of the alphabet length, find how many bits
+ are used to encode each character */
+/* unaligned PER
+ if(alphabet_length<=2){
+ bits_per_char=1;
+ } else if(alphabet_length<=4){
+ bits_per_char=2;
+ } else if(alphabet_length<=8){
+ bits_per_char=3;
+ } else if(alphabet_length<=16){
+ bits_per_char=4;
+ } else if(alphabet_length<=32){
+ bits_per_char=5;
+ } else if(alphabet_length<=64){
+ bits_per_char=6;
+ } else if(alphabet_length<=128){
+ bits_per_char=7;
+ } else {
+ bits_per_char=8;
+ }
+*/
+ if(alphabet_length<=2){
+ bits_per_char=1;
+ } else if(alphabet_length<=4){
+ bits_per_char=2;
+ } else if(alphabet_length<=16){
+ bits_per_char=4;
+ } else {
+ bits_per_char=8;
+ }
+
+ old_offset=offset;
+ for(char_pos=0;char_pos<length;char_pos++){
+ guchar val;
+ int i;
+ gboolean bit;
+
+ val=0;
+ for(i=0;i<bits_per_char;i++){
+ offset=dissect_per_boolean(tvb, offset, pinfo, tree, -1, &bit, NULL);
+ val=(val<<1)|bit;
+ }
+ if (val >= alphabet_length)
+ str[char_pos] = '?'; /* XXX - how to mark this? */
+ else
+ str[char_pos]=alphabet[val];
+ }
+ str[char_pos]=0;
+ proto_tree_add_string(tree, hf_index, tvb, (old_offset>>3), (offset>>3)-(old_offset>>3), str);
+
+ return offset;
+}
+guint32
+dissect_per_NumericString(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len)
+{
+ offset=dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, min_len, max_len, " 0123456789", 11);
+
+ return offset;
+}
+guint32
+dissect_per_PrintableString(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len)
+{
+ offset=dissect_per_restricted_character_string(tvb, offset, pinfo, tree, hf_index, min_len, max_len, " '()+,-.*0123456789:=?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 74);
+ return offset;
+}
+guint32
+dissect_per_BMPString(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len)
+{
+ guint32 length;
+ static char *str;
+
+ /* xx.x if the length is 0 bytes there will be no encoding */
+ if(max_len==0){
+ return offset;
+ }
+
+
+ if(min_len==-1){
+ min_len=0;
+ }
+
+
+ /* xx.x */
+ length=max_len;
+ if(min_len!=max_len){
+ proto_tree *etr = NULL;
+
+ if(display_internal_per_fields){
+ etr=tree;
+ }
+ offset=dissect_per_constrained_integer(tvb, offset, pinfo,
+ etr, hf_per_octet_string_length, min_len, max_len,
+ &length, NULL, FALSE);
+ }
+
+
+ /* align to byte boundary */
+ if(offset&0x07){
+ offset=(offset&0xfffffff8)+8;
+ }
+
+ if(length>=1024){
+ PER_NOT_DECODED_YET("BMPString too long");
+ length=1024;
+ }
+
+ str = tvb_fake_unicode(tvb, offset>>3, length, FALSE);
+
+ proto_tree_add_string(tree, hf_index, tvb, offset>>3, length*2, str);
+
+ offset+=(length<<3)*2;
+
+ return offset;
+}
+
+
+/* this function dissects a constrained sequence of */
+guint32
+dissect_per_constrained_sequence_of(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *parent_tree, int hf_index, gint ett_index, int (*func)(tvbuff_t *, int , packet_info *, proto_tree *), int min_len, int max_len)
+{
+ proto_item *item;
+ proto_tree *tree;
+ guint32 old_offset=offset;
+ guint32 length;
+
+
+DEBUG_ENTRY("dissect_per_constrained_sequence_of");
+ item=proto_tree_add_item(parent_tree, hf_index, tvb, offset>>3, 0, FALSE);
+ tree=proto_item_add_subtree(item, ett_index);
+
+ /* 19.5 if min==max and min,max<64k ==> no length determinant */
+ if((min_len==max_len) && (min_len<65536)){
+ length=min_len;
+ goto call_sohelper;
+ }
+
+ /* 19.6 ub>=64k or unset */
+ if(max_len>=65536){
+ guint32 old_offset=offset;
+ /* semi-constrained whole number for number of elements */
+ /* each element encoded as 10.9 */
+ offset=dissect_per_length_determinant(tvb, offset, pinfo, tree, -1, &length);
+ length+=min_len;
+ proto_tree_add_uint(tree, hf_per_sequence_of_length, tvb, old_offset>>3, (offset>>3)!=(old_offset>>3)?(offset>>3)-(old_offset>>3):1, length);
+ goto call_sohelper;
+ }
+
+ /* constrained whole number for number of elements */
+ offset=dissect_per_constrained_integer(tvb, offset, pinfo,
+ tree, hf_per_sequence_of_length, min_len, max_len,
+ &length, NULL, FALSE);
+
+
+
+call_sohelper:
+ offset=dissect_per_sequence_of_helper(tvb, offset, pinfo, tree, func, length);
+
+
+ proto_item_set_len(item, (offset>>3)!=(old_offset>>3)?(offset>>3)-(old_offset>>3):1);
+ return offset;
+}
+
+/* this function dissects a constrained set of */
+guint32
+dissect_per_constrained_set_of(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *parent_tree, int hf_index, gint ett_index, int (*func)(tvbuff_t *, int , packet_info *, proto_tree *), int min_len, int max_len)
+{
+ /* for basic-per a set-of is encoded in the same way as a sequence-of */
+DEBUG_ENTRY("dissect_per_constrained_set_of");
+ offset=dissect_per_constrained_sequence_of(tvb, offset, pinfo, parent_tree, hf_index, ett_index, func, min_len, max_len);
+ return offset;
+}
+
+
+
+
+
+
+/* this function dissects a set of */
+guint32
+dissect_per_set_of(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *parent_tree, int hf_index, gint ett_index, int (*func)(tvbuff_t *, int , packet_info *, proto_tree *))
+{
+ /* for basic-per a set-of is encoded in the same way as a sequence-of */
+DEBUG_ENTRY("dissect_per_set_of");
+ offset=dissect_per_sequence_of(tvb, offset, pinfo, parent_tree, hf_index, ett_index, func);
+ return offset;
+}
+
+
+
+
+/* this function reads a OBJECT IDENTIFIER */
+guint32
+dissect_per_object_identifier(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index, char *value_string)
+{
+ int i,count;
+ char str[256],*strp;
+ guint8 byte;
+ guint32 value;
+ proto_tree *etr=NULL;
+
+DEBUG_ENTRY("dissect_per_object_identifier");
+
+ if(display_internal_per_fields){
+ etr=tree;
+ }
+
+ /* first byte is the count and it is byte aligned */
+ if(offset&0x07){
+ offset=(offset&0xfffffff8)+8;
+ }
+ count=tvb_get_guint8(tvb, offset>>3);
+
+
+ proto_tree_add_uint(etr, hf_per_object_identifier_length, tvb, offset>>3, 1, count);
+ offset+=8;
+
+ value=0;
+ for(i=0,strp=str;i<count;i++){
+ byte=tvb_get_guint8(tvb,offset>>3);
+ offset+=8;
+
+ if((strp-str)>200){
+PER_NOT_DECODED_YET("too long octet_string");
+ /*XXX assert here */
+ return offset;
+ }
+
+ if(i==0){
+ /* the first byte contains the first two object identifier components */
+ if(byte<40){
+ strp+=sprintf(strp,"0.%d",byte);
+ } else if (byte<80){
+ strp+=sprintf(strp,"1.%d",byte-40);
+ } else {
+ strp+=sprintf(strp,"2.%d",byte-80);
+ }
+ continue;
+ }
+
+ value=(value<<7)|(byte&0x7f);
+ if(byte&0x80){
+ continue;
+ }
+
+ strp+=sprintf(strp,".%d",value);
+ value=0;
+ }
+ *strp=0;
+
+ proto_tree_add_string(tree, hf_index, tvb, (offset>>3)-count, count, str);
+
+ if (value_string) {
+ strcpy(value_string, str);
+ }
+
+ return offset;
+}
+
+
+
+
+/* this function reads a single bit */
+guint32
+dissect_per_boolean(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index, gboolean *bool, proto_item **item)
+{
+ guint8 ch, mask;
+ gboolean value;
+ header_field_info *hfi;
+ proto_item *it;
+
+DEBUG_ENTRY("dissect_per_boolean");
+
+ ch=tvb_get_guint8(tvb, offset>>3);
+ mask=1<<(7-(offset&0x07));
+ if(ch&mask){
+ value=1;
+ } else {
+ value=0;
+ }
+ if(hf_index!=-1){
+ char str[256];
+ hfi = proto_registrar_get_nth(hf_index);
+ sprintf(str,"%s: %c%c%c%c %c%c%c%c %s",
+ hfi->name,
+ mask&0x80?'0'+value:'.',
+ mask&0x40?'0'+value:'.',
+ mask&0x20?'0'+value:'.',
+ mask&0x10?'0'+value:'.',
+ mask&0x08?'0'+value:'.',
+ mask&0x04?'0'+value:'.',
+ mask&0x02?'0'+value:'.',
+ mask&0x01?'0'+value:'.',
+ value?"True":"False"
+ );
+ it=proto_tree_add_boolean_format(tree, hf_index, tvb, offset>>3, 1, value, str);
+ if(item){
+ *item=it;
+ }
+ }
+
+ if(bool){
+ *bool=value;
+ }
+ return offset+1;
+}
+
+
+
+
+/* we currently only handle integers up to 32 bits in length. */
+guint32
+dissect_per_integer(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, gint32 *value, proto_item **item)
+{
+ guint32 i, length;
+ gint32 val;
+ proto_item *it=NULL;
+
+ /* 12.2.6 b */
+ offset=dissect_per_length_determinant(tvb, offset, pinfo, tree, -1, &length);
+ /* gassert here? */
+ if(length>4){
+PER_NOT_DECODED_YET("too long integer");
+ length=4;
+ }
+
+ val=0;
+ for(i=0;i<length;i++){
+ if(i==0){
+ if(tvb_get_guint8(tvb, offset>>3)&0x80){
+ /* negative number */
+ val=0xffffffff;
+ } else {
+ /* positive number */
+ val=0;
+ }
+ }
+ val=(val<<8)|tvb_get_guint8(tvb,offset>>3);
+ offset+=8;
+ }
+ it=proto_tree_add_int(tree, hf_index, tvb, (offset>>3)-(length+1), length+1, val);
+
+ if(item){
+ *item=it;
+ }
+ if(value){
+ *value=val;
+ }
+
+ return offset;
+}
+
+
+/* this function reads a constrained integer with or without a
+ PER visible extension marker present
+
+ has_extension==TRUE would map to asn constructs such as:
+ rfc-number INTEGER (1..32768, ...)
+ while has_extension==FALSE would map to:
+ t35CountryCode INTEGER (0..255)
+
+ it only handles integers that fit inside a 32 bit integer
+10.5.1 info only
+10.5.2 info only
+10.5.3 range=ub-lb+1
+10.5.4 empty range
+10.5.5 info only
+ 10.5.6 unaligned version
+10.5.7 aligned version
+10.5.7.1 decoding of 0-255 1-8 bits
+10.5.7.2 decoding og 0-256 8 bits
+10.5.7.3 decoding of 0-65535 16 bits
+ 10.5.7.4
+*/
+guint32
+dissect_per_constrained_integer(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, guint32 min, guint32 max, guint32 *value, proto_item **item, gboolean has_extension)
+{
+ proto_item *it=NULL;
+ guint32 range, val;
+ gint val_start, val_length;
+ nstime_t timeval;
+ header_field_info *hfi;
+ int num_bits;
+ int pad;
+ guint32 tmp;
+
+DEBUG_ENTRY("dissect_per_constrained_integer");
+ if(has_extension){
+ gboolean extension_present;
+ offset=dissect_per_boolean(tvb, offset, pinfo, tree, -1, &extension_present, NULL);
+ if(extension_present){
+ offset=dissect_per_integer(tvb, offset, pinfo, tree,
+ hf_index,
+ NULL, NULL);
+ return offset;
+ }
+ }
+
+ hfi = proto_registrar_get_nth(hf_index);
+
+ /* 10.5.3 */
+ if((max-min)>65536){
+ /* just set range really big so it will fall through
+ to the bottom of the encoding */
+ range=1000000;
+ } else {
+ range=max-min+1;
+ }
+
+ num_bits=0;
+ pad=0;
+ val=0;
+ timeval.secs=val; timeval.nsecs=0;
+ /* 10.5.4 */
+ if(range==1){
+ val_start = offset>>3; val_length = 0;
+ val = min;
+ } else if(range<=255) {
+ /* 10.5.7.1 */
+ char str[256];
+ int i, bit, length;
+
+ length=1;
+ if(range<=2){
+ num_bits=1;
+ } else if(range<=4){
+ num_bits=2;
+ } else if(range<=8){
+ num_bits=3;
+ } else if(range<=16){
+ num_bits=4;
+ } else if(range<=32){
+ num_bits=5;
+ } else if(range<=64){
+ num_bits=6;
+ } else if(range<=128){
+ num_bits=7;
+ } else if(range<=256){
+ num_bits=8;
+ }
+ /* prepare the string */
+ sprintf(str, "%s: ", hfi->name);
+ for(bit=0;bit<((int)(offset&0x07));bit++){
+ if(bit&&(!(bit%4))){
+ strcat(str, " ");
+ }
+ strcat(str,".");
+ }
+ /* read the bits for the int */
+ for(i=0;i<num_bits;i++){
+ if(bit&&(!(bit%4))){
+ strcat(str, " ");
+ }
+ if(bit&&(!(bit%8))){
+ length+=1;
+ strcat(str, " ");
+ }
+ bit++;
+ offset=dissect_per_boolean(tvb, offset, pinfo, tree, -1, &tmp, NULL);
+ val<<=1;
+ if(tmp){
+ val|=tmp;
+ strcat(str, "1");
+ } else {
+ strcat(str, "0");
+ }
+ }
+ for(;bit%8;bit++){
+ if(bit&&(!(bit%4))){
+ strcat(str, " ");
+ }
+ strcat(str,".");
+ }
+ val_start = (offset-num_bits)>>3; val_length = length;
+ val+=min;
+ } else if(range==256){
+ /* 10.5.7.2 */
+ num_bits=8;
+ pad=7-(offset&0x07);
+
+ /* in the aligned case, align to byte boundary */
+ if(offset&0x07){
+ offset=(offset&0xfffffff8)+8;
+ }
+ val=tvb_get_guint8(tvb, offset>>3);
+ offset+=8;
+
+ val_start = (offset>>3)-1; val_length = 1;
+ val+=min;
+ } else if(range<=65536){
+ /* 10.5.7.3 */
+ num_bits=16;
+ pad=7-(offset&0x07);
+
+ /* in the aligned case, align to byte boundary */
+ if(offset&0x07){
+ offset=(offset&0xfffffff8)+8;
+ }
+ val=tvb_get_guint8(tvb, offset>>3);
+ val<<=8;
+ offset+=8;
+ val|=tvb_get_guint8(tvb, offset>>3);
+ offset+=8;
+
+ val_start = (offset>>3)-2; val_length = 2;
+ val+=min;
+ } else {
+ int i,num_bytes;
+ gboolean bit;
+
+ /* 10.5.7.4 */
+ /* 12.2.6 */
+ offset=dissect_per_boolean(tvb, offset, pinfo, tree, -1, &bit, NULL);
+ num_bytes=bit;
+ offset=dissect_per_boolean(tvb, offset, pinfo, tree, -1, &bit, NULL);
+ num_bytes=(num_bytes<<1)|bit;
+
+ num_bytes++; /* lower bound for length determinant is 1 */
+
+ /* byte aligned */
+ if(offset&0x07){
+ offset=(offset&0xfffffff8)+8;
+ }
+ val=0;
+ for(i=0;i<num_bytes;i++){
+ val=(val<<8)|tvb_get_guint8(tvb,offset>>3);
+ offset+=8;
+ }
+ val_start = (offset>>3)-(num_bytes+1); val_length = num_bytes+1;
+ val+=min;
+ }
+
+ timeval.secs = val;
+ if (IS_FT_UINT(hfi->type)) {
+ it = proto_tree_add_uint(tree, hf_index, tvb, val_start, val_length, val);
+ } else if (IS_FT_INT(hfi->type)) {
+ it = proto_tree_add_int(tree, hf_index, tvb, val_start, val_length, val);
+ } else if (IS_FT_TIME(hfi->type)) {
+ it = proto_tree_add_time(tree, hf_index, tvb, val_start, val_length, &timeval);
+ } else {
+ g_assert_not_reached();
+ }
+ if (item) *item = it;
+ if (value) *value = val;
+ return offset;}
+
+/* this functions decodes a CHOICE
+ it can only handle CHOICE INDEX values that fits inside a 32 bit integer.
+ 22.1
+ 22.2
+ 22.3
+ 22.4
+ 22.5
+22.6 no extensions
+22.7 extension marker == 0
+ 22.8 extension marker == 1
+*/
+guint32
+dissect_per_choice(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, gint ett_index, per_choice_t *choice, char *name, guint32 *value)
+{
+ gboolean extension_present, extension_flag;
+ int extension_root_entries;
+ guint32 choice_index;
+ int i;
+ proto_item *it=NULL;
+ proto_tree *tr=NULL;
+ guint32 old_offset=offset;
+ int min_choice=INT_MAX;
+ int max_choice=-1;
+
+DEBUG_ENTRY("dissect_per_choice");
+
+ it=proto_tree_add_text(tree, tvb, offset>>3, 0, name);
+ tr=proto_item_add_subtree(it, ett_index);
+
+
+ /* first check if there should be an extension bit for this CHOICE.
+ we do this by just checking the first choice arm
+ */
+ if(choice[0].extension==ASN1_NO_EXTENSIONS){
+ extension_present=0;
+ } else {
+ proto_tree *etr=NULL;
+
+ if(display_internal_per_fields){
+ etr=tr;
+ }
+ extension_present=1;
+ /* will be placed called again below to place it in the tree */
+ offset=dissect_per_boolean(tvb, offset, pinfo, etr, hf_per_extension_bit, &extension_flag, NULL);
+ }
+
+ /* count the number of entries in the extension_root */
+ extension_root_entries=0;
+ for(i=0;choice[i].name;i++){
+ switch(choice[i].extension){
+ case ASN1_NO_EXTENSIONS:
+ case ASN1_EXTENSION_ROOT:
+ if(choice[i].value<min_choice){
+ min_choice=choice[i].value;
+ }
+ if(choice[i].value>max_choice){
+ max_choice=choice[i].value;
+ }
+ extension_root_entries++;
+ break;
+ }
+ }
+
+ if( (!extension_present)
+ || (extension_present && (extension_flag==0)) ){
+ guint32 choice_offset=offset;
+ proto_tree *choicetree;
+ proto_item *choiceitem;
+ proto_tree *etr=NULL;
+
+ /* 22.6 */
+ /* 22.7 */
+/*qqq make it similar to the section below instead */
+ offset=dissect_per_constrained_integer(tvb, offset, pinfo,
+ tr, hf_index, min_choice, max_choice,
+ &choice_index, &choiceitem, FALSE);
+ if(value){
+ *value=choice_index;
+ }
+
+ choicetree=proto_item_add_subtree(choiceitem, ett_index);
+
+ if(display_internal_per_fields){
+ etr=choicetree;
+ }
+
+ /* find and call the appropriate callback */
+ for(i=0;choice[i].name;i++){
+ if(choice[i].value==(int)choice_index){
+ if(choice[i].func){
+ offset=choice[i].func(tvb, offset, pinfo, choicetree);
+ break;
+ } else {
+ PER_NOT_DECODED_YET(choice[i].name);
+ break;
+ }
+ }
+ }
+ proto_item_set_len(choiceitem, (offset>>3)!=(choice_offset>>3)?(offset>>3)-(choice_offset>>3):1);
+ } else {
+ guint32 length;
+ int i, index;
+ guint32 choice_offset;
+ proto_tree *choicetree;
+ proto_item *choiceitem;
+ proto_tree *etr=NULL;
+
+ if(display_internal_per_fields){
+ etr=tr;
+ }
+
+ /* 22.8 */
+ offset=dissect_per_normally_small_nonnegative_whole_number(tvb, offset, pinfo, etr, hf_per_choice_extension, &choice_index);
+ offset=dissect_per_length_determinant(tvb, offset, pinfo, etr, hf_per_open_type_length, &length);
+
+
+ choice_offset=offset;
+ choiceitem=proto_tree_add_text(tr, tvb, offset>>3, 0, "Choice");
+ choicetree=proto_item_add_subtree(choiceitem, ett_index);
+
+ index=-1;
+ for(i=0;choice[i].name;i++){
+ if(choice[i].extension==ASN1_NOT_EXTENSION_ROOT){
+ if(!choice_index){
+ index=i;
+ break;
+ }
+ choice_index--;
+ }
+ }
+
+ if(index!=-1){
+ if(value){
+ *value=index;
+ }
+ }
+
+ if(index==-1){
+ /* if we dont know how to decode this one, just step offset to the next structure */
+ offset+=length*8;
+ PER_NOT_DECODED_YET("unknown choice extension");
+ } else {
+ guint32 new_offset;
+
+ proto_item_set_text(choiceitem, choice[index].name);
+ new_offset=choice[index].func(tvb, offset, pinfo, choicetree);
+
+ if((new_offset>(offset+(length*8)))||((new_offset+8)<(offset+length*8))){
+printf("new_offset:%d offset:%d length*8:%d\n",new_offset,offset,length*8);
+/* g_assert_not_reached();*/
+ }
+
+ offset+=length*8;
+ }
+ proto_item_set_len(choiceitem, (offset>>3)!=(choice_offset>>3)?(offset>>3)-(choice_offset>>3):1);
+ }
+
+ proto_item_set_len(it, (offset>>3)!=(old_offset>>3)?(offset>>3)-(old_offset>>3):1);
+ return offset;
+}
+
+
+static char *
+index_get_optional_name(per_sequence_t *sequence, int index)
+{
+ int i;
+
+ for(i=0;sequence[i].name;i++){
+ if((sequence[i].extension!=ASN1_NOT_EXTENSION_ROOT)&&(sequence[i].optional==ASN1_OPTIONAL)){
+ if(index==0){
+ return sequence[i].name;
+ }
+ index--;
+ }
+ }
+ return "<unknown type>";
+}
+
+static char *
+index_get_extension_name(per_sequence_t *sequence, int index)
+{
+ int i;
+
+ for(i=0;sequence[i].name;i++){
+ if(sequence[i].extension==ASN1_NOT_EXTENSION_ROOT){
+ if(index==0){
+ return sequence[i].name;
+ }
+ index--;
+ }
+ }
+ return "<unknown type>";
+}
+
+/* this functions decodes a SEQUENCE
+ it can only handle SEQUENCES with at most 32 DEFAULT or OPTIONAL fields
+18.1 extension bit
+18.2 optinal/default items in root
+18.3 we ignore the case where n>64K
+18.4 the root sequence
+ 18.5
+ 18.6
+ 18.7
+ 18.8
+ 18.9
+*/
+guint32
+dissect_per_sequence(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *parent_tree, int hf_index, gint ett_index, per_sequence_t *sequence)
+{
+ gboolean extension_present, extension_flag, optional_field_flag;
+ proto_item *item;
+ proto_tree *tree;
+ guint32 old_offset=offset;
+ guint32 i, num_opts;
+ guint32 optional_mask;
+
+
+DEBUG_ENTRY("dissect_per_sequence");
+
+ item=proto_tree_add_item(parent_tree, hf_index, tvb, offset>>3, 0, FALSE);
+ tree=proto_item_add_subtree(item, ett_index);
+
+
+ /* first check if there should be an extension bit for this CHOICE.
+ we do this by just checking the first choice arm
+ */
+ /* 18.1 */
+ extension_flag=0;
+ if(sequence[0].extension==ASN1_NO_EXTENSIONS){
+ extension_present=0;
+ } else {
+ proto_tree *etr=NULL;
+
+ if(display_internal_per_fields){
+ etr=tree;
+ }
+ extension_present=1;
+ offset=dissect_per_boolean(tvb, offset, pinfo, etr, hf_per_extension_bit, &extension_flag, NULL);
+ }
+ /* 18.2 */
+ num_opts=0;
+ for(i=0;sequence[i].name;i++){
+ if((sequence[i].extension!=ASN1_NOT_EXTENSION_ROOT)&&(sequence[i].optional==ASN1_OPTIONAL)){
+ num_opts++;
+ }
+ }
+
+ optional_mask=0;
+ for(i=0;i<num_opts;i++){
+ proto_item *it=NULL;
+ proto_tree *etr=NULL;
+ if(display_internal_per_fields){
+ etr=tree;
+ }
+ offset=dissect_per_boolean(tvb, offset, pinfo, etr, hf_per_optional_field_bit, &optional_field_flag, &it);
+ optional_mask<<=1;
+ if(optional_field_flag){
+ optional_mask|=0x01;
+ }
+ if(it){
+ proto_item_append_text(it, " (%s %s present)",
+ index_get_optional_name(sequence, i),
+ optional_field_flag?"is":"is NOT"
+ );
+ }
+ }
+
+
+ /* 18.4 */
+ for(i=0;sequence[i].name;i++){
+ if( (sequence[i].extension==ASN1_NO_EXTENSIONS)
+ || (sequence[i].extension==ASN1_EXTENSION_ROOT) ){
+ if(sequence[i].optional==ASN1_OPTIONAL){
+ gboolean is_present;
+ is_present=(1<<(num_opts-1))&optional_mask;
+ num_opts--;
+ if(!is_present){
+ continue;
+ }
+ }
+ if(sequence[i].func){
+ offset=sequence[i].func(tvb, offset, pinfo, tree);
+ } else {
+ PER_NOT_DECODED_YET(sequence[i].name);
+ }
+ }
+ }
+
+
+ if(extension_flag){
+ gboolean extension_bit;
+ guint32 num_known_extensions;
+ guint32 num_extensions;
+ guint32 extension_mask;
+ proto_tree *etr=NULL;
+ proto_item *it=NULL;
+
+ if(display_internal_per_fields){
+ etr=tree;
+ }
+
+ offset=dissect_per_normally_small_nonnegative_whole_number(tvb, offset, pinfo, etr, hf_per_num_sequence_extensions, &num_extensions);
+ /* the X.691 standard is VERY unclear here.
+ there is no mention that the lower bound lb for this
+ (apparently) semiconstrained value is 1,
+ apart from the NOTE: comment in 18.8 that this value can
+ not be 0.
+ In my book, there is a semantic difference between having
+ a comment that says that the value can not be zero
+ and stating that the lb is 1.
+ I dont know if this is right or not but it makes
+ some of the very few captures I have decode properly.
+
+ It could also be that the captures I have are generated by
+ a broken implementation.
+ If this is wrong and you dont report it as a bug
+ then it wont get fixed!
+ */
+ num_extensions+=1;
+
+ extension_mask=0;
+ for(i=0;i<num_extensions;i++){
+ offset=dissect_per_boolean(tvb, offset, pinfo, etr, hf_per_extension_present_bit, &extension_bit, &it);
+ extension_mask=(extension_mask<<1)|extension_bit;
+ if(it){
+ proto_item_append_text(it, " (%s %s present)",
+ index_get_extension_name(sequence, i),
+ extension_bit?"is":"is NOT"
+ );
+ }
+
+ }
+
+ /* find how many extensions we know about */
+ num_known_extensions=0;
+ for(i=0;sequence[i].name;i++){
+ if(sequence[i].extension==ASN1_NOT_EXTENSION_ROOT){
+ num_known_extensions++;
+ }
+ }
+
+ /* decode the extensions one by one */
+ for(i=0;i<num_extensions;i++){
+ guint32 length;
+ guint32 new_offset;
+ guint32 extension_index;
+ guint32 j,k;
+
+ if(!((1L<<(num_extensions-1-i))&extension_mask)){
+ /* this extension is not encoded in this PDU */
+ continue;
+ }
+
+ offset=dissect_per_length_determinant(tvb, offset, pinfo, etr, hf_per_open_type_length, &length);
+
+ if(i>=num_known_extensions){
+ /* we dont know how to decode this extension */
+ offset+=length*8;
+ PER_NOT_DECODED_YET("unknown sequence extension");
+ continue;
+ }
+
+ extension_index=0;
+ for(j=0,k=0;sequence[j].name;j++){
+ if(sequence[j].extension==ASN1_NOT_EXTENSION_ROOT){
+ if(k==i){
+ extension_index=j;
+ break;
+ }
+ k++;
+ }
+ }
+
+ if(sequence[extension_index].func){
+ new_offset=sequence[extension_index].func(tvb, offset, pinfo, tree);
+ } else {
+ PER_NOT_DECODED_YET(sequence[extension_index].name);
+ }
+ offset+=length*8;
+
+ }
+ }
+
+
+ proto_item_set_len(item, (offset>>3)!=(old_offset>>3)?(offset>>3)-(old_offset>>3):1);
+ return offset;
+}
+
+
+
+/* 15 Encoding the bitstring type
+
+ max_len or min_len == -1 means there is no lower/upper constraint
+
+*/
+guint32
+dissect_per_bit_string(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len)
+{
+ guint32 length;
+ header_field_info *hfi;
+
+ hfi = (hf_index==-1) ? NULL : proto_registrar_get_nth(hf_index);
+
+DEBUG_ENTRY("dissect_per_bit_string");
+ /* 15.8 if the length is 0 bytes there will be no encoding */
+ if(max_len==0) {
+ return offset;
+ }
+
+ if(min_len==-1) {
+ min_len=0;
+ }
+
+ /* 15.9 if length is fixed and less than or equal to sixteen bits*/
+ if((min_len==max_len)&&(max_len<=16)){
+ static char bytes[4];
+ int i;
+ guint32 old_offset=offset;
+ gboolean bit;
+
+ bytes[0]=bytes[1]=bytes[2]=0;
+ for(i=0;i<min_len;i++){
+ offset=dissect_per_boolean(tvb, offset, pinfo, tree, -1, &bit, NULL);
+ bytes[0]=(bytes[0]<<1)|bit;
+ }
+ if(min_len>8){
+ for(i=8;i<min_len;i++){
+ offset=dissect_per_boolean(tvb, offset, pinfo, tree, -1, &bit, NULL);
+ bytes[1]=(bytes[1]<<1)|bit;
+ }
+ if(min_len<16){
+ bytes[1]|=bytes[0]<<(min_len-8);
+ bytes[0]>>=16-min_len;
+ }
+ }
+ if (hfi) {
+ proto_tree_add_bytes(tree, hf_index, tvb, old_offset>>3, (min_len+7)/8+(offset&0x07)?1:0, bytes);
+ }
+ return offset;
+ }
+
+
+ /* 15.10 if length is fixed and less than to 64kbits*/
+ if((min_len==max_len)&&(min_len<65536)){
+ /* align to byte */
+ if(offset&0x07){
+ offset=(offset&0xfffffff8)+8;
+ }
+ if (hfi) {
+ proto_tree_add_item(tree, hf_index, tvb, offset>>3, (min_len+7)/8, FALSE);
+ }
+ offset+=min_len;
+ return offset;
+ }
+
+ /* 15.11 */
+ if(max_len>0){
+ proto_tree *etr = NULL;
+
+ if(display_internal_per_fields){
+ etr=tree;
+ }
+ offset=dissect_per_constrained_integer(tvb, offset, pinfo,
+ etr, hf_per_bit_string_length, min_len, max_len,
+ &length, NULL, FALSE);
+ } else {
+ offset=dissect_per_length_determinant(tvb, offset, pinfo, tree, hf_per_bit_string_length, &length);
+ }
+ if(length){
+ /* align to byte */
+ if(offset&0x07){
+ offset=(offset&0xfffffff8)+8;
+ }
+ if (hfi) {
+ proto_tree_add_item(tree, hf_index, tvb, offset>>3, (length+7)/8, FALSE);
+ }
+ }
+ offset+=length;
+
+ return offset;
+}
+
+
+/* this fucntion dissects an OCTET STRING
+ 16.1
+ 16.2
+ 16.3
+ 16.4
+ 16.5
+ 16.6
+ 16.7
+ 16.8
+
+ max_len or min_len == -1 means there is no lower/upper constraint
+
+ hf_index can either be a FT_BYTES or an FT_STRING
+*/
+guint32
+dissect_per_octet_string(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len, guint32 *value_offset, guint32 *value_len)
+{
+ proto_tree *etr = NULL;
+ proto_item *it = NULL;
+ gint val_start, val_length;
+ guint32 length;
+ header_field_info *hfi;
+ static char bytes[4];
+ char *pbytes = NULL;
+
+ hfi = (hf_index==-1) ? NULL : proto_registrar_get_nth(hf_index);
+ if (display_internal_per_fields) {
+ etr = tree;
+ }
+
+DEBUG_ENTRY("dissect_per_octet_string");
+
+ if(min_len==-1){
+ min_len=0;
+ }
+
+ if (max_len==0) { /* 16.5 if the length is 0 bytes there will be no encoding */
+ val_start = offset>>3;
+ val_length = 0;
+
+ } else if((min_len==max_len)&&(max_len<=2)) { /* 16.6 if length is fixed and less than or equal to two bytes*/
+ guint32 i, old_offset=offset;
+ gboolean bit;
+
+ for(i=0;i<8;i++){
+ offset=dissect_per_boolean(tvb, offset, pinfo, tree, -1, &bit, NULL);
+ bytes[0]=(bytes[0]<<1)|bit;
+ }
+ if(min_len==2){
+ for(i=0;i<8;i++){
+ offset=dissect_per_boolean(tvb, offset, pinfo, tree, -1, &bit, NULL);
+ bytes[1]=(bytes[1]<<1)|bit;
+ }
+ }
+ bytes[min_len]=0;
+ pbytes = bytes;
+ val_start = old_offset>>3;
+ val_length = min_len+(offset&0x07)?1:0;
+
+ } else if ((min_len==max_len)&&(min_len<65536)) { /* 16.7 if length is fixed and less than to 64k*/
+ /* align to byte */
+ if(offset&0x07){
+ offset=(offset&0xfffffff8)+8;
+ }
+ val_start = offset>>3;
+ val_length = min_len;
+ offset+=min_len*8;
+
+ } else { /* 16.8 */
+ if(max_len>0) {
+ offset = dissect_per_constrained_integer(tvb, offset, pinfo, etr,
+ hf_per_octet_string_length, min_len, max_len,
+ &length, NULL, FALSE);
+ } else {
+ offset = dissect_per_length_determinant(tvb, offset, pinfo, etr,
+ hf_per_octet_string_length, &length);
+ }
+
+ if(length){
+ /* align to byte */
+ if(offset&0x07){
+ offset=(offset&0xfffffff8)+8;
+ }
+ }
+ val_start = offset>>3;
+ val_length = length;
+ offset+=length*8;
+ }
+
+ if (hfi) {
+ if (IS_FT_UINT(hfi->type)||IS_FT_INT(hfi->type)) {
+ if (IS_FT_UINT(hfi->type))
+ it = proto_tree_add_uint(tree, hf_index, tvb, val_start, val_length, val_length);
+ else
+ it = proto_tree_add_int(tree, hf_index, tvb, val_start, val_length, val_length);
+ proto_item_append_text(it, (val_length == 1) ? " octet" : " octets");
+ } else {
+ if (pbytes) {
+ if(IS_FT_STRING(hfi->type)){
+ proto_tree_add_string(tree, hf_index, tvb, val_start, val_length, pbytes);
+ } else if (hfi->type==FT_BYTES) {
+ proto_tree_add_bytes(tree, hf_index, tvb, val_start, val_length, pbytes);
+ } else {
+ g_assert_not_reached();
+ }
+ } else {
+ proto_tree_add_item(tree, hf_index, tvb, val_start, val_length, FALSE);
+ }
+ }
+ }
+ if (value_offset) *value_offset = val_start;
+ if (value_len) *value_len = val_length;
+ return offset;
+}
+
+
+
+void
+proto_register_per(void)
+{
+ static hf_register_info hf[] =
+ {
+ { &hf_per_num_sequence_extensions,
+ { "Number of Sequence Extensions", "per.num_sequence_extensions", FT_UINT32, BASE_DEC,
+ NULL, 0, "Number of extensions encoded in this sequence", HFILL }},
+ { &hf_per_choice_extension,
+ { "Choice Extension", "per.choice_extension", FT_UINT32, BASE_DEC,
+ NULL, 0, "Which extension of the Choice is encoded", HFILL }},
+ { &hf_per_GeneralString_length,
+ { "GeneralString Length", "per.generalstring_length", FT_UINT32, BASE_DEC,
+ NULL, 0, "Length of the GeneralString", HFILL }},
+ { &hf_per_extension_bit,
+ { "Extension Bit", "per.extension_bit", FT_BOOLEAN, 8,
+ TFS(&tfs_extension_bit), 0x01, "The extension bit of an aggregate", HFILL }},
+ { &hf_per_extension_present_bit,
+ { "Extension Present Bit", "per.extension_present_bit", FT_BOOLEAN, 8,
+ TFS(&tfs_extension_present_bit), 0x01, "Whether this optional extension is present or not", HFILL }},
+ { &hf_per_small_number_bit,
+ { "Small Number Bit", "per.small_number_bit", FT_BOOLEAN, 8,
+ TFS(&tfs_small_number_bit), 0x01, "The small number bit for a section 10.6 integer", HFILL }},
+ { &hf_per_optional_field_bit,
+ { "Optional Field Bit", "per.optional_field_bit", FT_BOOLEAN, 8,
+ TFS(&tfs_optional_field_bit), 0x01, "This bit specifies the presence/absence of an optional field", HFILL }},
+ { &hf_per_sequence_of_length,
+ { "Sequence-Of Length", "per.sequence_of_length", FT_UINT32, BASE_DEC,
+ NULL, 0, "Number of items in the Sequence Of", HFILL }},
+ { &hf_per_object_identifier_length,
+ { "Object Length", "per.object_length", FT_UINT32, BASE_DEC,
+ NULL, 0, "Length of the object identifier", HFILL }},
+ { &hf_per_open_type_length,
+ { "Open Type Length", "per.open_type_length", FT_UINT32, BASE_DEC,
+ NULL, 0, "Length of an open type encoding", HFILL }},
+ { &hf_per_octet_string_length,
+ { "Octet String Length", "per.octet_string_length", FT_UINT32, BASE_DEC,
+ NULL, 0, "Number of bytes in the Octet String", HFILL }},
+ { &hf_per_bit_string_length,
+ { "Bit String Length", "per.bit_string_length", FT_UINT32, BASE_DEC,
+ NULL, 0, "Number of bits in the Bit String", HFILL }},
+ };
+
+ static gint *ett[] =
+ {
+ &ett_per_sequence_of_item
+ };
+ module_t *per_module;
+
+ proto_per = proto_register_protocol("Packed Encoding Rules (ASN.1 X.691)", "PER", "per");
+ proto_register_field_array(proto_per, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ proto_set_cant_toggle(proto_per);
+
+ per_module = prefs_register_protocol(proto_per, NULL);
+ prefs_register_bool_preference(per_module, "display_internal_per_fields",
+ "Display the internal PER fields in the tree",
+ "Whether the dissector should put the internal PER data in the tree or if it should hide it",
+ &display_internal_per_fields);
+
+}
+
+void
+proto_reg_handoff_per(void)
+{
+}
+