aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--Makefile.nmake3
-rw-r--r--packet-h245.c1200
-rw-r--r--packet-per.c1220
-rw-r--r--packet-per.h86
5 files changed, 1313 insertions, 1199 deletions
diff --git a/Makefile.am b/Makefile.am
index 688c55b89e..f729600313 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
-# $Id: Makefile.am,v 1.597 2003/07/11 09:30:47 guy Exp $
+# $Id: Makefile.am,v 1.598 2003/07/12 22:35:20 sahlberg Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@ethereal.com>
@@ -311,6 +311,7 @@ DISSECTOR_SRC = \
packet-osi-options.c \
packet-ospf.c \
packet-pcnfsd.c \
+ packet-per.c \
packet-pflog.c \
packet-pgm.c \
packet-pim.c \
diff --git a/Makefile.nmake b/Makefile.nmake
index 514c879c2d..735d53ecd6 100644
--- a/Makefile.nmake
+++ b/Makefile.nmake
@@ -1,7 +1,7 @@
## Makefile for building ethereal.exe with Microsoft C and nmake
## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
#
-# $Id: Makefile.nmake,v 1.316 2003/07/07 22:48:54 guy Exp $
+# $Id: Makefile.nmake,v 1.317 2003/07/12 22:35:20 sahlberg Exp $
include config.nmake
include <win32.mak>
@@ -252,6 +252,7 @@ DISSECTOR_SRC = \
packet-osi-options.c \
packet-ospf.c \
packet-pcnfsd.c \
+ packet-per.c \
packet-pflog.c \
packet-pgm.c \
packet-pim.c \
diff --git a/packet-h245.c b/packet-h245.c
index 4febb08afc..d6adbad66b 100644
--- a/packet-h245.c
+++ b/packet-h245.c
@@ -85,9 +85,6 @@ etc etc etc
All in all a lot of work.
-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-h245.c
* Routines for H.245 packet dissection
@@ -95,7 +92,7 @@ proper helper routines
* with great support with testing and providing capturefiles
* from Martin Regner
*
- * $Id: packet-h245.c,v 1.16 2003/07/10 07:31:50 sahlberg Exp $
+ * $Id: packet-h245.c,v 1.17 2003/07/12 22:35:21 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -128,6 +125,7 @@ proper helper routines
#include "prefs.h"
#include "packet-tpkt.h"
+#include "packet-per.h"
static dissector_handle_t h245_handle;
static dissector_handle_t MultimediaSystemControlMessage_handle;
@@ -136,13 +134,6 @@ static int proto_h245 = -1;
static int hf_h245_pdu_type = -1;
static int hf_h245_subAddress = -1;
static int hf_h245_domainBased = -1;
-static int hf_h245_GeneralString_length = -1;
-static int hf_h245_extension_bit = -1;
-static int hf_h245_extension_present_bit = -1;
-static int hf_h245_choice_extension = -1;
-static int hf_h245_num_sequence_extensions = -1;
-static int hf_h245_small_number_bit = -1;
-static int hf_h245_optional_field_bit = -1;
static int hf_h245_IndicationMessage_type = -1;
static int hf_h245_RequestMessage_type = -1;
static int hf_h245_ResponseMessage_type = -1;
@@ -519,9 +510,6 @@ static int hf_h245_FECData = -1;
static int hf_h245_RTPPayloadType_payloadDescriptor = -1;
static int hf_h245_H2250LogicalChannelParameters_mediaPacketization = -1;
static int hf_h245_CRCLength = -1;
-static int hf_h245_open_type_length = -1;
-static int hf_h245_sequence_of_length = -1;
-static int hf_h245_octet_string_length = -1;
static int hf_h245_V76LogicalChannelParameters_mode_eRM_recovery = -1;
static int hf_h245_V76LogicalChannelParameters_mode = -1;
static int hf_h245_V76LogicalChannelParameters_suspendResume = -1;
@@ -972,7 +960,6 @@ static int hf_h245_containedThread = -1;
static int hf_h245_t38FaxMaxBuffer = -1;
static int hf_h245_t38FaxMaxDatagram = -1;
static int hf_h245_expirationTime = -1;
-static int hf_h245_object_identifier_length = -1;
static int hf_h245_object = -1;
static int hf_h245_protocolIdentifier = -1;
static int hf_h245_algorithm = -1;
@@ -1071,7 +1058,6 @@ static int hf_h245_audioTelephoneEvent = -1;
static int hf_h245_alphanumeric = -1;
static gint ett_h245 = -1;
-static gint ett_h245_sequence_of_item = -1;
static gint ett_h245_VCCapability_set_of = -1;
static gint ett_h245_MultimediaSystemControlMessage = -1;
static gint ett_h245_RequestMessage = -1;
@@ -1552,1152 +1538,6 @@ static gint ett_h245_lostPicture = -1;
static gint ett_h245_recoveryReferencePicture = -1;
static gint ett_h245_iPSourceRouteAddress_route = -1;
-#define NOT_DECODED_YET(x) \
-proto_tree_add_text(tree, tvb, offset, 0, "something unknown here"); \
-fprintf(stderr,"Not decoded yet in packet : %d [%s]\n", pinfo->fd->num,x);
-
-/*
-#define DEBUG_ENTRY(x) \
-printf("#%d %s tvb:0x%08x\n",pinfo->fd->num,x,(int)tvb);
-*/
-#define DEBUG_ENTRY(x) \
- ;
-
-
-
-
-/*************************************************************
- ASN.1_PER functions here
-**************************************************************/
-/* whether the PER helpers should put the internal PER fields into the tree
- or not.
-*/
-static guint display_internal_per_fields = TRUE;
-
-
-/* in all functions here, offset is guint32 and is
- byteposition<<3 + bitposition
-*/
-
-/* values for extensions */
-#define NO_EXTENSIONS 0
-#define EXTENSION_ROOT 1
-#define NOT_EXTENSION_ROOT 2
-
-/* value for optional */
-#define NOT_OPTIONAL 0
-#define OPTIONAL 1
-
-typedef struct _per_choice_t {
- int value;
- char *name;
- int extension;
- int (*func)(tvbuff_t *, int, packet_info *, proto_tree *);
-} per_choice_t;
-
-typedef struct _per_sequence_t {
- char *name;
- int extension;
- int optional;
- int (*func)(tvbuff_t *, int, packet_info *, proto_tree *);
-} per_sequence_t;
-
-
-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 = {
- "",
- ""
-};
-
-
-
-guint32 dissect_per_boolean(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index, gboolean *bool, proto_item **item);
-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);
-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);
-
-
-/* 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;
-
-DEBUG_ENTRY("dissect_per_length_determinant");
-
- 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;
- }
- NOT_DECODED_YET("10.9.3.8.1");
- return offset;
-}
-
-/* 10.6 normally small non-negative whole number */
-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_h245_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_h245_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 */
-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_h245_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;
-
-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 */
- offset=dissect_per_length_determinant(tvb, offset, pinfo, tree, hf_h245_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);
-
- 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_h245_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_h245_sequence_of_length, min_len, max_len,
- &length, NULL);
-
-
-
-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)
-{
- 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_h245_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){
-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);
-
- 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?"Bit is set":"Bit is clear"
- );
- 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){
-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
- 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)
-{
- proto_item *it=NULL;
- guint32 range, val;
- header_field_info *hfi;
- int num_bits;
- int pad;
- guint32 tmp;
-
-DEBUG_ENTRY("dissect_per_constrained_integer");
- 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;
- /* 10.5.4 */
- if(range==1){
- it=proto_tree_add_uint_format(tree, hf_index, tvb, offset>>3, 0, min, "%s: %d", hfi->name, min);
- if(item){
- *item=it;
- }
- if(value){
- *value=val;
- }
- return offset;
- }
-
- /* 10.5.7 */
- 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+=min;
- if(hfi->strings){
- it=proto_tree_add_uint_format(tree, hf_index, tvb, (offset-num_bits)>>3, length, val, "%s : %s (%d)", str, val_to_str(val, hfi->strings, "Unknown(%d)"),val);
- } else {
- it=proto_tree_add_uint(tree, hf_index, tvb, (offset-num_bits)>>3, length, val);
- }
- if(item){
- *item=it;
- }
- if(value){
- *value=val;
- }
- return offset;
- } 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+=min;
- it=proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-1, 1, val);
- if(item){
- *item=it;
- }
- if(value){
- *value=val;
- }
- return offset;
- } 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+=min;
- it=proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-2, 2, val);
- if(item){
- *item=it;
- }
- if(value){
- *value=val;
- }
- return offset;
- } 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+=min;
- it=proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-(num_bytes+1), num_bytes+1, val);
- if(item){
- *item=it;
- }
- if(value){
- *value=val;
- }
- return offset;
- }
-
- NOT_DECODED_YET("10.5");
- 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;
-
-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==NO_EXTENSIONS){
- extension_present=0;
- } else {
- extension_present=1;
- /* will be placed called again below to place it in the tree */
- offset=dissect_per_boolean(tvb, offset, pinfo, tr, -1, &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 NO_EXTENSIONS:
- case EXTENSION_ROOT:
- 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, 0, extension_root_entries-1,
- &choice_index, &choiceitem);
- 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 {
- 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_h245_choice_extension, &choice_index);
- offset=dissect_per_length_determinant(tvb, offset, pinfo, etr, hf_h245_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==NOT_EXTENSION_ROOT){
- if(!choice_index){
- index=i;
- break;
- }
- choice_index--;
- }
- }
- if(index!=-1){
- if(value){
- *value=choice_index;
- }
- }
-
- if(index==-1){
- /* if we dont know how to decode this one, just step offset to the next structure */
- offset+=length*8;
- 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!=NOT_EXTENSION_ROOT)&&(sequence[i].optional==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==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;
- int 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==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_h245_extension_bit, &extension_flag, NULL);
- }
-
- /* 18.2 */
- num_opts=0;
- for(i=0;sequence[i].name;i++){
- if((sequence[i].extension!=NOT_EXTENSION_ROOT)&&(sequence[i].optional==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_h245_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==NO_EXTENSIONS)
- || (sequence[i].extension==EXTENSION_ROOT) ){
- if(sequence[i].optional==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 {
- 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_h245_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<(int)num_extensions;i++){
- offset=dissect_per_boolean(tvb, offset, pinfo, etr, hf_h245_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==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;
- int 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_h245_open_type_length, &length);
-
- if(i>=num_known_extensions){
- /* we dont know how to decode this extension */
- offset+=length*8;
- NOT_DECODED_YET("unknown sequence extension");
- continue;
- }
-
- extension_index=0;
- for(j=0,k=0;sequence[j].name;j++){
- if(sequence[j].extension==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 {
- 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;
-}
-
-
-
-
-
-/* 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
-*/
-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 length;
-
-DEBUG_ENTRY("dissect_per_octet_string");
- /* 16.5 if the length is 0 bytes there will be no encoding */
- if(max_len==0){
- return offset;
- }
-
-
- if(min_len==-1){
- min_len=0;
- }
-
- /* 16.6 if length is fixed and less than or equal to two bytes*/
- if((min_len==max_len)&&(min_len<=2)){
- static char bytes[4];
- 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;
- }
- }
-
- proto_tree_add_bytes(tree, hf_index, tvb, old_offset>>3, min_len+(offset&0x07)?1:0, bytes);
- return offset;
- }
-
-
- /* aligne to byte */
- if(offset&0x07){
- offset=(offset&0xfffffff8)+8;
- }
-
- /* 16.7 if length is fixed and less than to 64k*/
- if((min_len==max_len)&&(min_len<65536)){
- proto_tree_add_bytes(tree, hf_index, tvb, offset>>3, min_len, tvb_get_ptr(tvb, offset>>3, min_len));
- offset+=min_len*8;
- return offset;
- }
-
- /* 16.8 */
- if(max_len>0){
- offset=dissect_per_constrained_integer(tvb, offset, pinfo,
- tree, hf_h245_octet_string_length, min_len, max_len,
- &length, NULL);
- } else {
- offset=dissect_per_length_determinant(tvb, offset, pinfo, tree, hf_h245_octet_string_length, &length);
- }
- if(length){
- proto_tree_add_bytes(tree, hf_index, tvb, offset>>3, length, tvb_get_ptr(tvb, offset>>3, length));
- }
- offset+=length*8;
-
- return offset;
-}
-
-
-
-
-
-/*************************************************************
- ASN.1_PER functions ends here
-**************************************************************/
-
-/*******************************************/
-/*yyy finished dissectors below this line */
-/*******************************************/
static int
dissect_h245_NULL(tvbuff_t *tvb _U_, int offset, packet_info *pinfo _U_, proto_tree *tree _U_)
@@ -20142,18 +18982,6 @@ proto_register_h245(void)
{ &hf_h245_pdu_type,
{ "PDU Type", "h245.pdu_type", FT_UINT32, BASE_DEC,
VALS(MultimediaSystemControlMessage_vals), 0, "Type of H.245 PDU", HFILL }},
- { &hf_h245_extension_bit,
- { "Extension Bit", "h245.extension_bit", FT_BOOLEAN, 8,
- TFS(&tfs_extension_bit), 0x01, "The extension bit of an aggregate", HFILL }},
- { &hf_h245_extension_present_bit,
- { "Extension Present Bit", "h245.extension_present_bit", FT_BOOLEAN, 8,
- TFS(&tfs_extension_present_bit), 0x01, "Whether this optional extension is present or not", HFILL }},
- { &hf_h245_small_number_bit,
- { "Small Number Bit", "h245.small_number_bit", FT_BOOLEAN, 8,
- TFS(&tfs_small_number_bit), 0x01, "The small number bit for a section 10.6 integer", HFILL }},
- { &hf_h245_optional_field_bit,
- { "Optional Field Bit", "h245.optional_field_bit", FT_BOOLEAN, 8,
- TFS(&tfs_optional_field_bit), 0x01, "This bit specifies the presence/absence of an optional field", HFILL }},
{ &hf_h245_IndicationMessage_type,
{ "Indication Type", "h245.indication_type", FT_UINT32, BASE_DEC,
VALS(IndicationMessage_vals), 0, "Type of Indication", HFILL }},
@@ -21279,15 +20107,6 @@ proto_register_h245(void)
{ &hf_h245_CRCLength,
{ "CRCLength type", "h245.CRCLength_type", FT_UINT32, BASE_DEC,
VALS(CRCLength_vals), 0, "Type of CRCLength choice", HFILL }},
- { &hf_h245_open_type_length,
- { "Open Type Length", "h245.open_type_length", FT_UINT32, BASE_DEC,
- NULL, 0, "Length of an open type encoding", HFILL }},
- { &hf_h245_sequence_of_length,
- { "Sequence-Of Length", "h245.sequence_of_length", FT_UINT32, BASE_DEC,
- NULL, 0, "Number of items in the Sequence Of", HFILL }},
- { &hf_h245_octet_string_length,
- { "Octet String Length", "h245.octet_string_length", FT_UINT32, BASE_DEC,
- NULL, 0, "Number of bytes in the Octet String", HFILL }},
{ &hf_h245_V76LogicalChannelParameters_mode_eRM_recovery,
{ "V76LogicalChannelParameters_mode_eRM_recovery type", "h245.V76LogicalChannelParameters_mode_eRM_recovery_type", FT_UINT32, BASE_DEC,
VALS(V76LogicalChannelParameters_mode_eRM_recovery_vals), 0, "Type of V76LogicalChannelParameters_mode_eRM_recovery choice", HFILL }},
@@ -22059,12 +20878,6 @@ proto_register_h245(void)
{ &hf_h245_bitRateLockedToNetworkClock,
{ "bitRateLockedToNetworkClock", "h245.bitRateLockedToNetworkClock", FT_BOOLEAN, 8,
TFS(&tfs_bitRateLockedToNetworkClock_bit), 0x01, "The bitRateLockedToNetworkClock bit", HFILL }},
- { &hf_h245_num_sequence_extensions,
- { "Number of Sequence Extensions", "h245.num_sequence_extensions", FT_UINT32, BASE_DEC,
- NULL, 0, "Number of extensions encoded in this sequence", HFILL }},
- { &hf_h245_choice_extension,
- { "Choice Extension", "h245.choice_extension", FT_UINT32, BASE_DEC,
- NULL, 0, "Which extension of the Choice is encoded", HFILL }},
{ &hf_h245_IS11172_BitRate,
{ "BitRate", "h245.IS11172_BitRate", FT_UINT32, BASE_DEC,
NULL, 0, "IS11172 BitRate in kbit/s", HFILL }},
@@ -22644,12 +21457,6 @@ proto_register_h245(void)
{ &hf_h245_expirationTime,
{ "expirationTime", "h245.expirationTime", FT_UINT32, BASE_DEC,
NULL, 0, "expirationTime value", HFILL }},
- { &hf_h245_object_identifier_length,
- { "Object Length", "h245.object_length", FT_UINT32, BASE_DEC,
- NULL, 0, "Length of the object identifier", HFILL }},
- { &hf_h245_GeneralString_length,
- { "GeneralString Length", "h245.generalstring_length", FT_UINT32, BASE_DEC,
- NULL, 0, "Length of the GeneralString", HFILL }},
{ &hf_h245_object,
{ "Object", "h245.object", FT_STRING, BASE_NONE,
NULL, 0, "Object Identifier", HFILL }},
@@ -23428,10 +22235,9 @@ proto_register_h245(void)
&ett_h245_lostPicture,
&ett_h245_recoveryReferencePicture,
&ett_h245_iPSourceRouteAddress_route,
- &ett_h245_sequence_of_item
};
- proto_h245 = proto_register_protocol("altH245", "altH245", "alth245");
+ proto_h245 = proto_register_protocol("H245", "H245", "h245");
proto_register_field_array(proto_h245, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
}
diff --git a/packet-per.c b/packet-per.c
new file mode 100644
index 0000000000..8e931ee8c8
--- /dev/null
+++ b/packet-per.c
@@ -0,0 +1,1220 @@
+/*
+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: packet-per.c,v 1.1 2003/07/12 22:35:20 sahlberg Exp $
+ *
+ * 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 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 = TRUE;
+
+
+
+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;
+ }
+ NOT_DECODED_YET("10.9.3.8.1");
+ return offset;
+}
+
+/* 10.6 normally small non-negative whole number */
+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;
+
+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 */
+ offset=dissect_per_length_determinant(tvb, offset, pinfo, tree, 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);
+
+ 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);
+
+
+
+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)
+{
+ 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){
+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);
+
+ 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?"Bit is set":"Bit is clear"
+ );
+ 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){
+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
+ 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)
+{
+ proto_item *it=NULL;
+ guint32 range, val;
+ header_field_info *hfi;
+ int num_bits;
+ int pad;
+ guint32 tmp;
+
+DEBUG_ENTRY("dissect_per_constrained_integer");
+ 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;
+ /* 10.5.4 */
+ if(range==1){
+ it=proto_tree_add_uint_format(tree, hf_index, tvb, offset>>3, 0, min, "%s: %d", hfi->name, min);
+ if(item){
+ *item=it;
+ }
+ if(value){
+ *value=val;
+ }
+ return offset;
+ }
+
+ /* 10.5.7 */
+ 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+=min;
+ if(hfi->strings){
+ it=proto_tree_add_uint_format(tree, hf_index, tvb, (offset-num_bits)>>3, length, val, "%s : %s (%d)", str, val_to_str(val, hfi->strings, "Unknown(%d)"),val);
+ } else {
+ it=proto_tree_add_uint(tree, hf_index, tvb, (offset-num_bits)>>3, length, val);
+ }
+ if(item){
+ *item=it;
+ }
+ if(value){
+ *value=val;
+ }
+ return offset;
+ } 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+=min;
+ it=proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-1, 1, val);
+ if(item){
+ *item=it;
+ }
+ if(value){
+ *value=val;
+ }
+ return offset;
+ } 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+=min;
+ it=proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-2, 2, val);
+ if(item){
+ *item=it;
+ }
+ if(value){
+ *value=val;
+ }
+ return offset;
+ } 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+=min;
+ it=proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-(num_bytes+1), num_bytes+1, val);
+ if(item){
+ *item=it;
+ }
+ if(value){
+ *value=val;
+ }
+ return offset;
+ }
+
+ NOT_DECODED_YET("10.5");
+ 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;
+
+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==NO_EXTENSIONS){
+ extension_present=0;
+ } else {
+ extension_present=1;
+ /* will be placed called again below to place it in the tree */
+ offset=dissect_per_boolean(tvb, offset, pinfo, tr, -1, &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 NO_EXTENSIONS:
+ case EXTENSION_ROOT:
+ 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, 0, extension_root_entries-1,
+ &choice_index, &choiceitem);
+ 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 {
+ 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==NOT_EXTENSION_ROOT){
+ if(!choice_index){
+ index=i;
+ break;
+ }
+ choice_index--;
+ }
+ }
+ if(index!=-1){
+ if(value){
+ *value=choice_index;
+ }
+ }
+
+ if(index==-1){
+ /* if we dont know how to decode this one, just step offset to the next structure */
+ offset+=length*8;
+ 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!=NOT_EXTENSION_ROOT)&&(sequence[i].optional==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==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;
+ int 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==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!=NOT_EXTENSION_ROOT)&&(sequence[i].optional==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==NO_EXTENSIONS)
+ || (sequence[i].extension==EXTENSION_ROOT) ){
+ if(sequence[i].optional==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 {
+ 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<(int)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==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;
+ int 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;
+ NOT_DECODED_YET("unknown sequence extension");
+ continue;
+ }
+
+ extension_index=0;
+ for(j=0,k=0;sequence[j].name;j++){
+ if(sequence[j].extension==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 {
+ 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;
+}
+
+
+
+
+
+/* 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
+*/
+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 length;
+
+DEBUG_ENTRY("dissect_per_octet_string");
+ /* 16.5 if the length is 0 bytes there will be no encoding */
+ if(max_len==0){
+ return offset;
+ }
+
+
+ if(min_len==-1){
+ min_len=0;
+ }
+
+ /* 16.6 if length is fixed and less than or equal to two bytes*/
+ if((min_len==max_len)&&(min_len<=2)){
+ static char bytes[4];
+ 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;
+ }
+ }
+
+ proto_tree_add_bytes(tree, hf_index, tvb, old_offset>>3, min_len+(offset&0x07)?1:0, bytes);
+ return offset;
+ }
+
+
+ /* aligne to byte */
+ if(offset&0x07){
+ offset=(offset&0xfffffff8)+8;
+ }
+
+ /* 16.7 if length is fixed and less than to 64k*/
+ if((min_len==max_len)&&(min_len<65536)){
+ proto_tree_add_bytes(tree, hf_index, tvb, offset>>3, min_len, tvb_get_ptr(tvb, offset>>3, min_len));
+ offset+=min_len*8;
+ return offset;
+ }
+
+ /* 16.8 */
+ if(max_len>0){
+ offset=dissect_per_constrained_integer(tvb, offset, pinfo,
+ tree, hf_per_octet_string_length, min_len, max_len,
+ &length, NULL);
+ } else {
+ offset=dissect_per_length_determinant(tvb, offset, pinfo, tree, hf_per_octet_string_length, &length);
+ }
+ if(length){
+ proto_tree_add_bytes(tree, hf_index, tvb, offset>>3, length, tvb_get_ptr(tvb, offset>>3, length));
+ }
+ offset+=length*8;
+
+ 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 }},
+ };
+
+ static gint *ett[] =
+ {
+ &ett_per_sequence_of_item
+ };
+ module_t *per_module;
+
+ proto_per = proto_register_protocol("Packet 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));
+
+ 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)
+{
+}
+
diff --git a/packet-per.h b/packet-per.h
new file mode 100644
index 0000000000..b730078889
--- /dev/null
+++ b/packet-per.h
@@ -0,0 +1,86 @@
+/* packet-per.h
+ * Routines for dissection of ASN.1 Aligned PER
+ * 2003 Ronnie Sahlberg
+ *
+ * $Id: packet-per.h,v 1.1 2003/07/12 22:35:21 sahlberg Exp $
+ *
+ * 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.
+ */
+
+#define NOT_DECODED_YET(x) \
+proto_tree_add_text(tree, tvb, offset, 0, "something unknown here"); \
+fprintf(stderr,"Not decoded yet in packet : %d [%s]\n", pinfo->fd->num,x);
+
+/* in all functions here, offset is guint32 and is
+ byteposition<<3 + bitposition
+*/
+
+/* values for extensions */
+#define NO_EXTENSIONS 0
+#define EXTENSION_ROOT 1
+#define NOT_EXTENSION_ROOT 2
+
+/* value for optional */
+#define NOT_OPTIONAL 0
+#define OPTIONAL 1
+
+typedef struct _per_choice_t {
+ int value;
+ char *name;
+ int extension;
+ int (*func)(tvbuff_t *, int, packet_info *, proto_tree *);
+} per_choice_t;
+
+typedef struct _per_sequence_t {
+ char *name;
+ int extension;
+ int optional;
+ int (*func)(tvbuff_t *, int, packet_info *, proto_tree *);
+} per_sequence_t;
+
+
+guint32 dissect_per_length_determinant(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, guint32 *length);
+
+guint32 dissect_per_normally_small_nonnegative_whole_number(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, guint32 *length);
+
+guint32 dissect_per_GeneralString(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index);
+
+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 *));
+
+guint32 dissect_per_IA5String(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, int min_len, int max_len);
+
+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);
+
+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);
+
+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 *));
+
+guint32 dissect_per_object_identifier(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index);
+
+guint32 dissect_per_boolean(tvbuff_t *tvb, guint32 offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index, gboolean *bool, proto_item **item);
+
+guint32 dissect_per_integer(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *tree, int hf_index, gint32 *value, proto_item **item);
+
+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);
+
+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);
+
+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);
+
+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);