summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-per.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-per.c
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-per.c')
-rw-r--r--epan/dissectors/packet-per.c3005
1 files changed, 3005 insertions, 0 deletions
diff --git a/epan/dissectors/packet-per.c b/epan/dissectors/packet-per.c
new file mode 100644
index 00000000..4a4ac7c8
--- /dev/null
+++ b/epan/dissectors/packet-per.c
@@ -0,0 +1,3005 @@
+/*
+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
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <math.h>
+
+#include <epan/packet.h>
+#include <epan/exceptions.h>
+#include <epan/oids.h>
+#include <epan/to_str.h>
+#include <epan/asn1.h>
+#include <epan/expert.h>
+#include <wsutil/str_util.h>
+#include "packet-per.h"
+
+void proto_register_per(void);
+
+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_index = -1;
+static int hf_per_choice_extension_index = -1;
+static int hf_per_enum_index = -1;
+static int hf_per_enum_extension_index = -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_real_length = -1;
+static int hf_per_octet_string_length = -1;
+static int hf_per_bit_string_length = -1;
+static int hf_per_normally_small_nonnegative_whole_number_length = -1;
+static int hf_per_const_int_len = -1;
+static int hf_per_direct_reference = -1; /* T_direct_reference */
+static int hf_per_indirect_reference = -1; /* T_indirect_reference */
+static int hf_per_data_value_descriptor = -1; /* T_data_value_descriptor */
+static int hf_per_encoding = -1; /* External_encoding */
+static int hf_per_single_ASN1_type = -1; /* T_single_ASN1_type */
+static int hf_per_octet_aligned = -1; /* T_octet_aligned */
+static int hf_per_arbitrary = -1; /* T_arbitrary */
+static int hf_per_integer_length = -1; /* Show integer length if "show internal per fields" */
+/* static int hf_per_debug_pos = -1; */
+static int hf_per_internal_range = -1;
+static int hf_per_internal_num_bits = -1;
+static int hf_per_internal_min = -1;
+static int hf_per_internal_value = -1;
+static int hf_per_encoding_boiler_plate = -1;
+
+static gint ett_per_open_type = -1;
+static gint ett_per_containing = -1;
+static gint ett_per_sequence_of_item = -1;
+static gint ett_per_External = -1;
+static gint ett_per_External_encoding = -1;
+static gint ett_per_named_bits = -1;
+
+static expert_field ei_per_size_constraint_value = EI_INIT;
+static expert_field ei_per_size_constraint_too_few = EI_INIT;
+static expert_field ei_per_size_constraint_too_many = EI_INIT;
+static expert_field ei_per_choice_extension_unknown = EI_INIT;
+static expert_field ei_per_sequence_extension_unknown = EI_INIT;
+static expert_field ei_per_encoding_error = EI_INIT;
+static expert_field ei_per_oid_not_implemented = EI_INIT;
+static expert_field ei_per_undecoded = EI_INIT;
+static expert_field ei_per_field_not_integer = EI_INIT;
+static expert_field ei_per_external_type = EI_INIT;
+static expert_field ei_per_open_type = EI_INIT;
+static expert_field ei_per_open_type_len = EI_INIT;
+
+static dissector_table_t per_oid_dissector_table = NULL;
+
+/*
+#define DEBUG_ENTRY(x) \
+printf("#%u %s tvb:0x%08x\n",actx->pinfo->num,x,(int)tvb);
+*/
+#define DEBUG_ENTRY(x) \
+ ;
+
+#define BLEN(old_offset, offset) (((offset)>>3)!=((old_offset)>>3)?((offset)>>3)-((old_offset)>>3):1)
+
+/* whether the PER helpers should put the internal PER fields into the tree
+ or not.
+*/
+static gboolean display_internal_per_fields = FALSE;
+
+
+
+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"
+};
+
+void
+add_per_encoded_label(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree* tree)
+{
+ proto_item* ti;
+
+ ti = proto_tree_add_item(tree, hf_per_encoding_boiler_plate, tvb, 0, -1, ENC_NA);
+ proto_item_set_generated(ti);
+
+}
+
+#define BYTE_ALIGN_OFFSET(offset) if(offset&0x07){offset=(offset&0xfffffff8)+8;}
+
+#define SEQ_MAX_COMPONENTS 128
+
+static void per_check_value(guint32 value, guint32 min_len, guint32 max_len, asn1_ctx_t *actx, proto_item *item, gboolean is_signed)
+{
+ if ((is_signed == FALSE) && (value > max_len)) {
+ expert_add_info_format(actx->pinfo, item, &ei_per_size_constraint_value, "Size constraint: value too big: %u (%u .. %u)", value, min_len, max_len);
+ } else if ((is_signed == TRUE) && ((gint32)value > (gint32)max_len)) {
+ expert_add_info_format(actx->pinfo, item, &ei_per_size_constraint_value, "Size constraint: value too big: %d (%d .. %d)", (gint32)value, (gint32)min_len, (gint32)max_len);
+ }
+}
+
+static void per_check_value64(guint64 value, guint64 min_len, guint64 max_len, asn1_ctx_t *actx, proto_item *item, gboolean is_signed)
+{
+ if ((is_signed == FALSE) && (value > max_len)) {
+ expert_add_info_format(actx->pinfo, item, &ei_per_size_constraint_value, "Size constraint: value too big: %" PRIu64 " (%" PRIu64 " .. %" PRIu64 ")", value, min_len, max_len);
+ } else if ((is_signed == TRUE) && ((gint64)value > (gint64)max_len)) {
+ expert_add_info_format(actx->pinfo, item, &ei_per_size_constraint_value, "Size constraint: value too big: %" PRId64 " (%" PRId64 " .. %" PRId64 ")", (gint64)value, (gint64)min_len, (gint64)max_len);
+ }
+}
+
+static void per_check_items(guint32 cnt, int min_len, int max_len, asn1_ctx_t *actx, proto_item *item)
+{
+ if (min_len != NO_BOUND && cnt < (guint32)min_len) {
+ expert_add_info_format(actx->pinfo, item, &ei_per_size_constraint_too_few, "Size constraint: too few items: %d (%d .. %d)", cnt, min_len, max_len);
+ } else if (max_len != NO_BOUND && cnt > (guint32)max_len) {
+ expert_add_info_format(actx->pinfo, item, &ei_per_size_constraint_too_many, "Size constraint: too many items: %d (%d .. %d)", cnt, min_len, max_len);
+ }
+}
+
+
+void dissect_per_not_decoded_yet(proto_tree* tree, packet_info* pinfo, tvbuff_t *tvb, const char* reason)
+{
+ proto_tree_add_expert_format(tree, pinfo, &ei_per_undecoded, tvb, 0, 0, "something unknown here [%s]",reason);
+ col_append_fstr(pinfo->cinfo, COL_INFO, "[UNKNOWN PER: %s]", reason);
+ THROW(ReportedBoundsError);
+}
+
+/* 10 Encoding procedures -------------------------------------------------- */
+
+/* 10.2 Open type fields --------------------------------------------------- */
+static guint32
+dissect_per_open_type_internal(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, void* type_cb, asn1_cb_variant variant)
+{
+ int type_length, start_offset, end_offset, fragmented_length = 0, pdu_length, pdu_offset;
+ tvbuff_t *val_tvb = NULL, *pdu_tvb = NULL, *fragment_tvb = NULL;
+ header_field_info *hfi;
+ proto_tree *subtree = tree;
+ gboolean is_fragmented;
+ int captured_pdu_length;
+
+ hfi = (hf_index == -1) ? NULL : proto_registrar_get_nth(hf_index);
+
+ start_offset = offset;
+ do {
+ offset = dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_open_type_length, &type_length, &is_fragmented);
+ if (actx->aligned) BYTE_ALIGN_OFFSET(offset);
+ if (is_fragmented) {
+ fragment_tvb = tvb_new_octet_aligned(tvb, offset, 8*type_length);
+ if (fragmented_length == 0) {
+ pdu_tvb = tvb_new_composite();
+ }
+ tvb_composite_append(pdu_tvb, fragment_tvb);
+ offset += 8*type_length;
+ fragmented_length += type_length;
+ }
+ } while (is_fragmented);
+ if (fragmented_length) {
+ if (type_length) {
+ tvb_composite_append(pdu_tvb, tvb_new_octet_aligned(tvb, offset, 8*type_length));
+ fragmented_length += type_length;
+ }
+ tvb_composite_finalize(pdu_tvb);
+ add_new_data_source(actx->pinfo, pdu_tvb, "Fragmented OCTET STRING");
+ pdu_offset = 0;
+ pdu_length = fragmented_length;
+ } else {
+ pdu_tvb = tvb;
+ pdu_offset = offset;
+ pdu_length = type_length;
+ }
+ end_offset = offset + type_length * 8;
+
+ if (variant==CB_NEW_DISSECTOR) {
+ if (fragmented_length) {
+ val_tvb = pdu_tvb;
+ } else {
+ if (!pdu_length) {
+ return end_offset;
+ }
+ /* Check if we have a tvb that holds the whole PDU */
+ captured_pdu_length = tvb_captured_length(pdu_tvb) - (pdu_offset>>3);
+ if(captured_pdu_length < pdu_length){
+ val_tvb = tvb_new_octet_aligned(pdu_tvb, pdu_offset, captured_pdu_length * 8);
+ actx->created_item = proto_tree_add_expert_format(tree, actx->pinfo, &ei_per_open_type_len, tvb, pdu_offset >> 3,
+ captured_pdu_length,"Open type length(%i) > available data(%i)", pdu_length, captured_pdu_length);
+ pdu_length = captured_pdu_length;
+ } else {
+ val_tvb = tvb_new_octet_aligned(pdu_tvb, pdu_offset, pdu_length * 8);
+ }
+ /* Add new data source if the offet was unaligned */
+ if ((pdu_offset & 7) != 0) {
+ add_new_data_source(actx->pinfo, val_tvb, "Unaligned OCTET STRING");
+ }
+ }
+ if (hfi) {
+ if (FT_IS_UINT(hfi->type)||FT_IS_INT(hfi->type)) {
+ if (FT_IS_UINT(hfi->type))
+ actx->created_item = proto_tree_add_uint(tree, hf_index, val_tvb, 0, pdu_length, pdu_length);
+ else
+ actx->created_item = proto_tree_add_int(tree, hf_index, val_tvb, 0, pdu_length, pdu_length);
+ proto_item_append_text(actx->created_item, plurality(pdu_length, " octet", " octets"));
+ } else {
+ actx->created_item = proto_tree_add_item(tree, hf_index, val_tvb, 0, pdu_length, ENC_BIG_ENDIAN);
+ }
+ subtree = proto_item_add_subtree(actx->created_item, ett_per_open_type);
+ }
+ }
+
+ if (type_cb) {
+ switch (variant) {
+ case CB_ASN1_ENC:
+ ((per_type_fn)type_cb)(pdu_tvb, pdu_offset, actx, tree, hf_index);
+ break;
+ case CB_NEW_DISSECTOR:
+ /* Pas actx->private_data as "data" to the called function */
+ ((dissector_t)type_cb)(val_tvb, actx->pinfo, subtree, actx->private_data);
+ break;
+ case CB_DISSECTOR_HANDLE:
+ break;
+ }
+ } else {
+ actx->created_item = proto_tree_add_expert(tree, actx->pinfo, &ei_per_open_type, tvb, start_offset>>3, BLEN(start_offset, end_offset));
+ }
+
+ return end_offset;
+}
+
+guint32
+dissect_per_open_type(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, per_type_fn type_cb)
+{
+ return dissect_per_open_type_internal(tvb, offset, actx, tree, hf_index, (void*)type_cb, CB_ASN1_ENC);
+}
+
+guint32
+dissect_per_open_type_pdu_new(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, dissector_t type_cb)
+{
+ return dissect_per_open_type_internal(tvb, offset, actx, tree, hf_index, (void*)type_cb, CB_NEW_DISSECTOR);
+}
+
+/* 10.9 General rules for encoding a length determinant --------------------
+
+ NOTE 1 - (Tutorial) The procedures of this subclause are invoked when an explicit length field is needed
+ for some part of the encoding regardless of whether the length count is bounded above
+ (by PER-visible constraints) or not. The part of the encoding to which the length applies may
+ be a bit string (with the length count in bits), an octet string (with the length count in octets),
+ a known-multiplier character string (with the length count in characters), or a list of fields
+ (with the length count in components of a sequence-of or set-of).
+
+ NOTE 2 - (Tutorial) In the case of the ALIGNED variant if the length count is bounded above by an upper bound
+ that is less than 64K, then the constrained whole number encoding is used for the length.
+ For sufficiently small ranges the result is a bit-field, otherwise the unconstrained length ("n" say)
+ is encoded into an octet-aligned bit-field in one of three ways (in order of increasing size):
+ a) ("n" less than 128) a single octet containing "n" with bit 8 set to zero;
+ b) ("n" less than 16K) two octets containing "n" with bit 8 of the first octet set to 1 and bit 7 set to zero;
+ c) (large "n") a single octet containing a count "m" with bit 8 set to 1 and bit 7 set to 1.
+ The count "m" is one to four, and the length indicates that a fragment of the material follows
+ (a multiple "m" of 16K items). For all values of "m", the fragment is then followed by another length encoding
+ for the remainder of the material.
+
+ NOTE 3 - (Tutorial) In the UNALIGNED variant, if the length count is bounded above by an upper bound that is less
+ than 64K, then the constrained whole number encoding is used to encode the length in the minimum number of
+ bits necessary to represent the range. Otherwise, the unconstrained length ("n" say) is encoded into a bit
+ field in the manner described above in Note 2.
+
+ */
+guint32
+dissect_per_length_determinant(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx _U_, proto_tree *tree, int hf_index, guint32 *length, gboolean *is_fragmented)
+{
+ guint8 byte;
+ guint32 len;
+ proto_item *pi;
+ int num_bits;
+ int i, bit, str_length, str_index;
+ gboolean tmp;
+
+ if(!length){
+ length=&len;
+ }
+ if (is_fragmented) {
+ *is_fragmented = FALSE;
+ }
+
+ /* byte aligned */
+ if (actx->aligned){
+ BYTE_ALIGN_OFFSET(offset);
+ byte=tvb_get_guint8(tvb, offset>>3);
+ offset+=8;
+ }else{
+ char *str;
+ guint32 val;
+
+ val = 0;
+
+ /* prepare the string (max number of bits + quartet separators + prepended space) */
+ str_length = 256+64+1;
+ str=(char *)wmem_alloc(wmem_packet_scope(), str_length+1);
+ str_index = 0;
+
+ str_length = snprintf(str, str_length+1, " ");
+ for(bit=0;bit<((int)(offset&0x07));bit++){
+ if(bit&&(!(bit%4))){
+ if (str_index < str_length) str[str_index++] = ' ';
+ }
+ if (str_index < str_length) str[str_index++] = '.';
+ }
+ /* read the bits for the int */
+ num_bits = 8;
+ for(i=0;i<num_bits;i++){
+ if(bit&&(!(bit%4))){
+ if (str_index < str_length) str[str_index++] = ' ';
+ }
+ if(bit&&(!(bit%8))){
+ if (str_index < str_length) str[str_index++] = ' ';
+ }
+ bit++;
+ offset=dissect_per_boolean(tvb, offset, actx, tree, -1, &tmp);
+ val<<=1;
+ if(tmp){
+ val|=1;
+ if (str_index < str_length) str[str_index++] = '1';
+ if (i==0) { /* bit 8 is 1, so not a single byte length */
+ num_bits = 16;
+ }
+ else if (i==1 && val==3) { /* bits 8 and 7 both 1, so unconstrained */
+ if (!is_fragmented) {
+ *length = 0;
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "10.9 Unconstrained");
+ return offset;
+ } else {
+ num_bits = 8;
+ *is_fragmented = TRUE;
+ }
+ }
+ } else {
+ if (str_index < str_length) str[str_index++] = '0';
+ }
+ }
+ str[str_index] = '\0'; /* Terminate string */
+ if(is_fragmented && *is_fragmented==TRUE){
+ *length = val&0x3f;
+ if (*length>4 || *length==0) {
+ *length = 0;
+ *is_fragmented = FALSE;
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "10.9 Unconstrained unexpected fragment count");
+ return offset;
+ }
+ *length *= 0x4000;
+ if(hf_index!=-1){
+ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-1, 1, *length);
+ if (display_internal_per_fields)
+ proto_item_append_text(pi," %s", str);
+ else
+ proto_item_set_hidden(pi);
+ }
+
+ return offset;
+ }
+ else if((val&0x80)==0 && num_bits==8){
+ *length = val;
+ if(hf_index!=-1){
+ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-1, 1, *length);
+ if (display_internal_per_fields)
+ proto_item_append_text(pi," %s", str);
+ else
+ proto_item_set_hidden(pi);
+ }
+
+ return offset;
+ }
+ else if (num_bits==16) {
+ *length = val&0x3fff;
+ if(hf_index!=-1){
+ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-2, 2, *length);
+ if (display_internal_per_fields)
+ proto_item_append_text(pi," %s", str);
+ else
+ proto_item_set_hidden(pi);
+ }
+
+ return offset;
+ }
+ *length = 0;
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "10.9 Unaligned");
+ return offset;
+
+ }
+
+ /* 10.9.3.6 */
+ if((byte&0x80)==0){
+ *length=byte;
+ if(hf_index!=-1){
+ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-1, 1, *length);
+ if (!display_internal_per_fields) proto_item_set_hidden(pi);
+ }
+ return offset;
+ }
+
+ /* 10.9.3.7 */
+ if((byte&0xc0)==0x80){
+ *length=(byte&0x3f);
+ *length=((*length)<<8)+tvb_get_guint8(tvb, offset>>3);
+ offset+=8;
+ if(hf_index!=-1){
+ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-2, 2, *length);
+ if (!display_internal_per_fields) proto_item_set_hidden(pi);
+ }
+ return offset;
+ }
+ /* 10.9.3.8.1 */
+ else if (is_fragmented){
+ *length = byte&0x3f;
+ if (*length>4 || *length==0) {
+ *length = 0;
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "10.9 Unconstrained unexpected fragment count");
+ return offset;
+ }
+ *length *= 0x4000;
+ *is_fragmented = TRUE;
+ if(hf_index!=-1){
+ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-1, 1, *length);
+ if (!display_internal_per_fields) proto_item_set_hidden(pi);
+ }
+ return offset;
+ }
+ *length = 0;
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "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, asn1_ctx_t *actx, proto_tree *tree, int hf_index, guint32 *length)
+{
+ gboolean small_number, length_bit;
+ guint32 len, length_determinant;
+ proto_item *pi;
+
+DEBUG_ENTRY("dissect_per_normally_small_nonnegative_whole_number");
+ if(!length){
+ length=&len;
+ }
+
+ offset=dissect_per_boolean(tvb, offset, actx, tree, hf_per_small_number_bit, &small_number);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ if(!small_number){
+ int i;
+ /* 10.6.1 */
+ *length=0;
+ for(i=0;i<6;i++){
+ offset=dissect_per_boolean(tvb, offset, actx, tree, -1, &length_bit);
+ *length<<=1;
+ if (length_bit) {
+ *length|=1;
+ }
+ }
+ if(hf_index!=-1){
+ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset-6)>>3, (offset%8<6)?2:1, *length);
+ if (!display_internal_per_fields) proto_item_set_hidden(pi);
+ }
+ return offset;
+ }
+
+ /* 10.6.2 */
+ offset=dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_normally_small_nonnegative_whole_number_length, &length_determinant, NULL);
+ switch (length_determinant) {
+ case 0:
+ *length = 0;
+ break;
+ case 1:
+ *length = tvb_get_bits8(tvb, offset, 8);
+ offset += 8;
+ break;
+ case 2:
+ *length = tvb_get_bits16(tvb, offset, 16, ENC_BIG_ENDIAN);
+ offset += 16;
+ break;
+ case 3:
+ *length = tvb_get_bits32(tvb, offset, 24, ENC_BIG_ENDIAN);
+ offset += 24;
+ break;
+ case 4:
+ *length = tvb_get_bits32(tvb, offset, 32, ENC_BIG_ENDIAN);
+ offset += 32;
+ break;
+ default:
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "too long integer(per_normally_small_nonnegative_whole_number)");
+ offset += 8*length_determinant;
+ *length = 0;
+ return offset;
+ }
+ if(hf_index!=-1){
+ pi = proto_tree_add_uint(tree, hf_index, tvb, (offset-(8*length_determinant))>>3, length_determinant, *length);
+ if (!display_internal_per_fields) proto_item_set_hidden(pi);
+ }
+
+ return offset;
+}
+
+
+
+/* this function reads a GeneralString */
+/* currently based on pure guesswork since RFC2833 didn't 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, asn1_ctx_t *actx, proto_tree *tree, int hf_index)
+{
+ guint32 length;
+
+ offset=dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_GeneralString_length, &length, NULL);
+
+ proto_tree_add_item(tree, hf_index, tvb, offset>>3, length, ENC_BIG_ENDIAN);
+
+ offset+=length*8;
+
+ return offset;
+}
+
+/* 17 Encoding the null type */
+guint32
+dissect_per_null(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx _U_, proto_tree *tree, int hf_index) {
+ proto_item *ti_tmp;
+
+ ti_tmp = proto_tree_add_item(tree, hf_index, tvb, offset>>3, 0, ENC_BIG_ENDIAN);
+ proto_item_append_text(ti_tmp, ": NULL");
+
+ return offset;
+}
+
+/* 19 this function dissects a sequence of */
+// Arbitrary. Allow a sequence of NULLs, but not too many since we might add
+// a hierarchy of tree items per NULL
+#define PER_SEQUENCE_OF_MAX_NULLS 10
+static guint32
+dissect_per_sequence_of_helper(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, per_type_fn func, int hf_index, guint32 length)
+{
+ guint32 i;
+
+DEBUG_ENTRY("dissect_per_sequence_of_helper");
+ guint32 old_offset = offset;
+ for(i=0;i<length;i++){
+ guint32 lold_offset=offset;
+ proto_item *litem;
+ proto_tree *ltree;
+
+ ltree=proto_tree_add_subtree_format(tree, tvb, offset>>3, 0, ett_per_sequence_of_item, &litem, "Item %d", i);
+
+ offset=(*func)(tvb, offset, actx, ltree, hf_index);
+ proto_item_set_len(litem, (offset>>3)!=(lold_offset>>3)?(offset>>3)-(lold_offset>>3):1);
+ if (i >= PER_SEQUENCE_OF_MAX_NULLS-1 && offset <= old_offset) {
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "too many nulls in sequence");
+ }
+ }
+
+ return offset;
+}
+guint32
+dissect_per_sequence_of(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *parent_tree, int hf_index, gint ett_index, const per_sequence_t *seq)
+{
+ proto_item *item;
+ proto_tree *tree;
+ guint32 old_offset=offset;
+ guint32 length;
+ header_field_info *hfi;
+
+DEBUG_ENTRY("dissect_per_sequence_of");
+
+ /* semi-constrained whole number for number of elements */
+ /* each element encoded as 10.9 */
+
+ offset=dissect_per_length_determinant(tvb, offset, actx, parent_tree, hf_per_sequence_of_length, &length, NULL);
+
+ hfi = proto_registrar_get_nth(hf_index);
+ if (FT_IS_UINT(hfi->type)) {
+ item = proto_tree_add_uint(parent_tree, hf_index, tvb, old_offset>>3, 0, length);
+ proto_item_append_text(item, (length==1)?" item":" items");
+ } else {
+ item=proto_tree_add_item(parent_tree, hf_index, tvb, old_offset>>3, 0, ENC_BIG_ENDIAN);
+ }
+ tree=proto_item_add_subtree(item, ett_index);
+
+ offset=dissect_per_sequence_of_helper(tvb, offset, actx, tree, seq->func, *seq->p_id, length);
+
+
+ proto_item_set_len(item, (offset>>3)!=(old_offset>>3)?(offset>>3)-(old_offset>>3):1);
+ return offset;
+}
+
+/* XXX we don't do >64k length strings yet */
+static guint32
+dissect_per_restricted_character_string_sorted(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, guint16 lb, guint16 ub, const char *alphabet, int alphabet_length, tvbuff_t **value_tvb)
+{
+ guint32 length;
+ gboolean byte_aligned, use_canonical_order;
+ wmem_strbuf_t *buf;
+ int str_len;
+ char *str;
+ 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){
+ if (value_tvb) {
+ *value_tvb = tvb_new_child_real_data(tvb, NULL, 0, 0);
+ }
+ return offset;
+ }
+
+
+ if (min_len == NO_BOUND) {
+ min_len=0;
+ }
+
+
+ /* 27.5.2 depending of the alphabet length, find how many bits
+ are used to encode each character */
+/* unaligned PER */
+ if (actx->aligned){
+
+ 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;
+ }
+ }else{
+ 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;
+ }
+ }
+
+ /* 27.4 If the type is extensible for PER encodings (see 9.3.16),
+ * then a bit-field consisting of a single bit shall be added to the field-list.
+ * The single bit shall be set to zero if the value is within the range of the extension root,
+ * and to one otherwise. If the value is outside the range of the extension root,
+ * then the following encoding shall be as if there was no effective size constraint,
+ * and shall have an effective permitted-alphabet constraint that consists of the set of characters
+ * of the unconstrained type.
+ * NOTE - Only the known-multiplier character string types can be extensible for PER encodings.
+ * Extensibility markers on other character string types do not affect the PER encoding.
+ */
+
+ if (has_extension) {
+ gboolean extension_present;
+ offset = dissect_per_boolean(tvb, offset, actx, tree, hf_per_extension_present_bit, &extension_present);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ if(extension_present){
+ min_len = NO_BOUND;
+ max_len = NO_BOUND;
+ }
+ }
+
+ byte_aligned=TRUE;
+ if((min_len==max_len)&&(max_len<=2)){
+ byte_aligned=FALSE;
+ }
+ if ((max_len != NO_BOUND) && (max_len < 2)) {
+ byte_aligned=FALSE;
+ }
+
+ /* xx.x */
+ length=max_len;
+ old_offset = offset;
+ if (max_len == NO_BOUND) {
+ offset = dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_octet_string_length, &length, NULL);
+ /* the unconstrained strings are always byte aligned (27.6.3)*/
+ byte_aligned=TRUE;
+ } else if(min_len!=max_len){
+ offset=dissect_per_constrained_integer(tvb, offset, actx,
+ tree, hf_per_octet_string_length, min_len, max_len,
+ &length, FALSE);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ }
+
+ if(!length){
+ /* there is no string at all, so don't do any byte alignment */
+ /* byte_aligned=FALSE; */
+ /* Advance offset to next 'element' */
+ if (offset == old_offset)
+ offset = offset + 1;
+ }
+
+ if((byte_aligned)&&(actx->aligned)){
+ BYTE_ALIGN_OFFSET(offset);
+ }
+
+ /* 30.5: if "ub" is less than or equal to 2^b-1, then "v" is the value specified in above , else
+ the characters are placed in the canonical order defined in ITU-T Rec. X.680 | ISO/IEC 8824-1,
+ clause 43. The first is assigned the value zero and the next in canonical order is assigned a value
+ that is one greater than the value assigned to the previous character in the canonical order. These are the values "v" */
+ use_canonical_order = (ub <= ((guint16)(1<<bits_per_char)-1)) ? FALSE : TRUE;
+
+ buf = wmem_strbuf_new_len(actx->pinfo->pool, NULL, length);
+ 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, actx, tree, -1, &bit);
+ val=(val<<1)|bit;
+ }
+ if(use_canonical_order == FALSE){
+ if (val > ub || val < lb) {
+ wmem_strbuf_append_unichar_repl(buf);
+ } else {
+ wmem_strbuf_append_c(buf, val);
+ }
+ } else {
+ if (val < alphabet_length){
+ wmem_strbuf_append_c(buf, alphabet[val]);
+ } else {
+ wmem_strbuf_append_unichar_repl(buf);
+ }
+ }
+ }
+ str_len = (int)wmem_strbuf_get_len(buf);
+ str = wmem_strbuf_finalize(buf);
+ /* Note that str can contain embedded nulls. Length claims any bytes partially used. */
+ proto_tree_add_string(tree, hf_index, tvb, (old_offset>>3), ((offset+7)>>3)-(old_offset>>3), str);
+ if (value_tvb) {
+ *value_tvb = tvb_new_child_real_data(tvb, str, str_len, str_len);
+ }
+ return offset;
+}
+
+static const char*
+sort_alphabet(char *sorted_alphabet, const char *alphabet, int alphabet_length, guint16 *lb, guint16 *ub)
+{
+ int i, j;
+ guchar c, c_max, c_min;
+ char tmp_buf[256];
+
+ /*
+ * XXX - presumably all members of alphabet will be in the
+ * range 0 to 127. asn2wrs.py doesn't properly handle the
+ * Quadruple or CharacterStringList types needed for other
+ * characters, nor representing characters outside ASCII
+ * in the "cstring" notation (possibly in UTF-8?)
+ */
+ if (!alphabet_length) return sorted_alphabet;
+ memset(tmp_buf, 0, 256);
+ c_min = c_max = (guchar)alphabet[0];
+ for (i=0; i<alphabet_length; i++) {
+ c = (guchar)alphabet[i];
+ tmp_buf[c] = 1;
+ if (c > c_max) c_max = c;
+ else if (c < c_min) c_min = c;
+ }
+ for (i=c_min,j=0; i<=c_max; i++) {
+ if (tmp_buf[i]) sorted_alphabet[j++] = i;
+ }
+ *lb = (guint16)c_min;
+ *ub = (guint16)c_max;
+ return sorted_alphabet;
+}
+
+guint32
+dissect_per_restricted_character_string(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, const char *alphabet, int alphabet_length, tvbuff_t **value_tvb)
+{
+ const char *alphabet_ptr;
+ char sorted_alphabet[128];
+ guint16 lb = 0;
+ guint16 ub = 65535;
+
+ /* XXX: We don't handle permitted-alphabet characters outside the
+ * ASCII range if used in BMPString (UCS2) or UniversalString (UCS4)
+ */
+ if (alphabet_length > 127) {
+ alphabet_ptr = alphabet;
+ } else {
+ alphabet_ptr = sort_alphabet(sorted_alphabet, alphabet, alphabet_length, &lb, &ub);
+ }
+
+ /* This is for a restricted character string type with a permitted-
+ * alphabet constraint type. Such constraints are only PER-visible for
+ * the known-multiplier character string types.
+ */
+
+ return dissect_per_restricted_character_string_sorted(tvb, offset, actx, tree, hf_index, min_len, max_len, has_extension, lb, ub, alphabet_ptr, alphabet_length, value_tvb);
+}
+
+guint32
+dissect_per_IA5String(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, tvbuff_t **value_tvb)
+{
+ offset=dissect_per_restricted_character_string_sorted(tvb, offset, actx, tree, hf_index, min_len, max_len, has_extension,
+ 0, 127, NULL, 128, value_tvb);
+
+ return offset;
+}
+
+guint32
+dissect_per_NumericString(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, tvbuff_t **value_tvb)
+{
+ offset=dissect_per_restricted_character_string_sorted(tvb, offset, actx, tree, hf_index, min_len, max_len, has_extension,
+ 32, 57, " 0123456789", 11, value_tvb);
+
+ return offset;
+}
+guint32
+dissect_per_PrintableString(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, tvbuff_t **value_tvb)
+{
+ offset=dissect_per_restricted_character_string_sorted(tvb, offset, actx, tree, hf_index, min_len, max_len, has_extension,
+ 32, 122, " '()+,-.*0123456789:=?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 74, value_tvb);
+ return offset;
+}
+guint32
+dissect_per_VisibleString(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, tvbuff_t **value_tvb)
+{
+ offset=dissect_per_restricted_character_string_sorted(tvb, offset, actx, tree, hf_index, min_len, max_len, has_extension,
+ 32, 126, " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 95, value_tvb);
+ return offset;
+}
+guint32
+dissect_per_BMPString(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension _U_)
+{
+ guint32 length;
+
+ /* xx.x if the length is 0 bytes there will be no encoding */
+ if(max_len==0){
+ return offset;
+ }
+
+
+ if (min_len == NO_BOUND) {
+ min_len = 0;
+ }
+
+
+ /* xx.x */
+ length=max_len;
+ if(min_len!=max_len){
+ offset=dissect_per_constrained_integer(tvb, offset, actx,
+ tree, hf_per_octet_string_length, min_len, max_len,
+ &length, FALSE);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ }
+
+
+ /* align to byte boundary */
+ BYTE_ALIGN_OFFSET(offset);
+
+ if(length>=1024){
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "BMPString too long");
+ length=1024;
+ }
+
+ proto_tree_add_item(tree, hf_index, tvb, offset>>3, length*2, ENC_UCS_2|ENC_BIG_ENDIAN);
+
+ offset+=(length<<3)*2;
+
+ return offset;
+}
+guint32
+dissect_per_UTF8String(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len _U_, int max_len _U_, gboolean has_extension _U_)
+{
+ tvbuff_t *val_tvb;
+ guint32 length;
+
+ /* UTF8String is not a known-multiplier character string (UTF8
+ * characters are variable width.) Hence subclause 27.6 applies,
+ * and "constraints are never PER-visible, and the type can never
+ * be extensible for PER encoding."
+ */
+
+ /* 27.6.3 unconstrained length determinant with "n" in octets */
+ offset = dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_octet_string_length, &length, NULL);
+
+ if(length){
+
+ /* Unnecessary because the length determinant is aligned. */
+ if(actx->aligned) {
+ BYTE_ALIGN_OFFSET(offset);
+ }
+
+ val_tvb = tvb_new_octet_aligned(tvb, offset, length * 8);
+ /* Add new data source if the offset was unaligned */
+ if ((offset & 7) != 0) {
+ add_new_data_source(actx->pinfo, val_tvb, "Unaligned UTF8String");
+ }
+
+ proto_tree_add_item(tree, hf_index, val_tvb, 0, length, ENC_UTF_8);
+ } else {
+ /* tvb_new_octet_aligned doesn't like zero length.
+ * length zero indicates a present but empty string, so add it
+ */
+ proto_tree_add_item(tree, hf_index, tvb, (offset-1)>>3, length, ENC_UTF_8);
+ }
+
+ offset+=(length<<3);
+
+ return offset;
+}
+
+guint32
+dissect_per_object_descriptor(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, tvbuff_t **value_tvb)
+{
+ offset=dissect_per_octet_string(tvb, offset, actx, tree, hf_index, -1, -1, FALSE, value_tvb);
+
+ return offset;
+}
+
+
+/* this function dissects a constrained sequence of */
+guint32
+dissect_per_constrained_sequence_of(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *parent_tree, int hf_index, gint ett_index, const per_sequence_t *seq, int min_len, int max_len, gboolean has_extension _U_)
+{
+ proto_item *item;
+ proto_tree *tree;
+ guint32 old_offset=offset;
+ guint32 length;
+ header_field_info *hfi;
+
+DEBUG_ENTRY("dissect_per_constrained_sequence_of");
+
+ /* 19.4 If there is a PER-visible constraint and an extension marker is present in it,
+ * a single bit shall be added to the field-list in a bit-field of length one
+ */
+ if (has_extension) {
+ gboolean extension_present;
+ offset=dissect_per_boolean(tvb, offset, actx, parent_tree, hf_per_extension_present_bit, &extension_present);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ if (extension_present){
+ /* 10.9 shall be invoked to add the length determinant as a semi-constrained whole number to the field-list,
+ * followed by the component values
+ */
+ offset = dissect_per_length_determinant(tvb, offset, actx, parent_tree, hf_per_sequence_of_length, &length, NULL);
+ goto call_sohelper;
+ }
+ }
+
+ /* 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) || (max_len == NO_BOUND)) {
+ /* no constraint, see 10.9.4.2 */
+ offset=dissect_per_length_determinant(tvb, offset, actx, parent_tree, hf_per_sequence_of_length, &length, NULL);
+ goto call_sohelper;
+ }
+
+ /* constrained whole number for number of elements */
+ offset=dissect_per_constrained_integer(tvb, offset, actx,
+ parent_tree, hf_per_sequence_of_length, min_len, max_len,
+ &length, FALSE);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+
+call_sohelper:
+ hfi = proto_registrar_get_nth(hf_index);
+ if (FT_IS_UINT(hfi->type)) {
+ item = proto_tree_add_uint(parent_tree, hf_index, tvb, offset>>3, 0, length);
+ proto_item_append_text(item, (length==1)?" item":" items");
+ } else {
+ item=proto_tree_add_item(parent_tree, hf_index, tvb, offset>>3, 0, ENC_BIG_ENDIAN);
+ }
+ tree=proto_item_add_subtree(item, ett_index);
+ per_check_items(length, min_len, max_len, actx, item);
+
+ old_offset = offset;
+ offset=dissect_per_sequence_of_helper(tvb, offset, actx, tree, seq->func, *seq->p_id, length);
+
+ if (offset == old_offset)
+ length = 0;
+ else if (offset >> 3 == old_offset >> 3)
+ length = 1;
+ else
+ length = (offset >> 3) - (old_offset >> 3);
+
+ proto_item_set_len(item, length);
+ return offset;
+}
+
+/* this function dissects a constrained set of */
+guint32
+dissect_per_constrained_set_of(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *parent_tree, int hf_index, gint ett_index, const per_sequence_t *seq, int min_len, int max_len, gboolean has_extension)
+{
+ /* 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, actx, parent_tree, hf_index, ett_index, seq, min_len, max_len, has_extension);
+ return offset;
+}
+
+
+
+
+
+
+/* this function dissects a set of */
+guint32
+dissect_per_set_of(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *parent_tree, int hf_index, gint ett_index, const per_sequence_t *seq)
+{
+ /* 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, actx, parent_tree, hf_index, ett_index, seq);
+ return offset;
+}
+
+
+
+
+/* 23 Encoding the object identifier type */
+static guint32
+dissect_per_any_oid(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, tvbuff_t **value_tvb,
+ gboolean is_absolute)
+{
+ guint length;
+ const char *str;
+ tvbuff_t *val_tvb = NULL;
+ header_field_info *hfi;
+
+ DEBUG_ENTRY("dissect_per_any_oid");
+
+ offset = dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_object_identifier_length, &length, NULL);
+ if(length == 0){
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "unexpected length");
+ }
+ if (actx->aligned) BYTE_ALIGN_OFFSET(offset);
+ val_tvb = tvb_new_octet_aligned(tvb, offset, length * 8);
+ /* Add new data source if the offet was unaligned */
+ if ((offset & 7) != 0) {
+ add_new_data_source(actx->pinfo, val_tvb, "Unaligned OCTET STRING");
+ }
+
+ hfi = proto_registrar_get_nth(hf_index);
+ if ((is_absolute && hfi->type == FT_OID) || (is_absolute && hfi->type == FT_REL_OID)) {
+ actx->created_item = proto_tree_add_item(tree, hf_index, val_tvb, 0, length, ENC_BIG_ENDIAN);
+ } else if (FT_IS_STRING(hfi->type)) {
+ str = oid_encoded2string(wmem_packet_scope(), tvb_get_ptr(val_tvb, 0, length), length);
+ actx->created_item = proto_tree_add_string(tree, hf_index, val_tvb, 0, length, str);
+ } else {
+ DISSECTOR_ASSERT_NOT_REACHED();
+ }
+
+ if (value_tvb) *value_tvb = val_tvb;
+
+ offset += 8 * length;
+
+ return offset;
+}
+
+guint32
+dissect_per_object_identifier(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, tvbuff_t **value_tvb)
+{
+ return dissect_per_any_oid(tvb, offset, actx, tree, hf_index, value_tvb, TRUE);
+}
+
+guint32
+dissect_per_relative_oid(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, tvbuff_t **value_tvb)
+{
+ return dissect_per_any_oid(tvb, offset, actx, tree, hf_index, value_tvb, FALSE);
+}
+
+static guint32
+dissect_per_any_oid_str(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, const char **value_stringx,
+ gboolean is_absolute)
+{
+ tvbuff_t *value_tvb = NULL;
+ guint length;
+
+ offset = dissect_per_any_oid(tvb, offset, actx, tree, hf_index, (value_stringx) ? &value_tvb : NULL, is_absolute);
+
+ if (value_stringx) {
+ if (value_tvb && (length = tvb_captured_length(value_tvb))) {
+ *value_stringx = oid_encoded2string(wmem_packet_scope(), tvb_get_ptr(value_tvb, 0, length), length);
+ } else {
+ *value_stringx = "";
+ }
+ }
+
+ return offset;
+}
+
+guint32
+dissect_per_object_identifier_str(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, const char **value_stringx)
+{
+ return dissect_per_any_oid_str(tvb, offset, actx, tree, hf_index, value_stringx, TRUE);
+}
+
+guint32
+dissect_per_relative_oid_str(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, const char **value_stringx)
+{
+ return dissect_per_any_oid_str(tvb, offset, actx, tree, hf_index, value_stringx, FALSE);
+}
+
+
+/* this function reads a single bit */
+guint32
+dissect_per_boolean(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, gboolean *bool_val)
+{
+ guint8 ch, mask;
+ gboolean value;
+ header_field_info *hfi;
+
+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 bits[10];
+ bits[0] = mask&0x80?'0'+value:'.';
+ bits[1] = mask&0x40?'0'+value:'.';
+ bits[2] = mask&0x20?'0'+value:'.';
+ bits[3] = mask&0x10?'0'+value:'.';
+ bits[4] = ' ';
+ bits[5] = mask&0x08?'0'+value:'.';
+ bits[6] = mask&0x04?'0'+value:'.';
+ bits[7] = mask&0x02?'0'+value:'.';
+ bits[8] = mask&0x01?'0'+value:'.';
+ bits[9] = '\0';
+
+ hfi = proto_registrar_get_nth(hf_index);
+ actx->created_item = proto_tree_add_boolean_format(tree, hf_index, tvb, offset>>3, 1, value,
+ "%s %s: %s", bits, hfi->name,
+ value?"True":"False");
+ } else {
+ actx->created_item = NULL;
+ }
+
+ if(bool_val){
+ *bool_val=value;
+ }
+ return offset+1;
+}
+
+
+
+
+/* we currently only handle integers up to 32 bits in length. */
+guint32
+dissect_per_integer(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, gint32 *value)
+{
+ guint32 i, length;
+ guint32 val;
+ tvbuff_t *val_tvb=NULL;
+ proto_item *it=NULL;
+ header_field_info *hfi;
+
+ /* 12.2.6 b */
+ offset=dissect_per_length_determinant(tvb, offset, actx, tree,hf_per_integer_length, &length, NULL);
+ /* gassert here? */
+ if(length>4){
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "too long integer(per_integer)");
+ length=4;
+ }
+
+ if(length == 0){
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "unexpected length");
+ }
+
+ if (actx->aligned) BYTE_ALIGN_OFFSET(offset);
+ val_tvb = tvb_new_octet_aligned(tvb, offset, length * 8);
+ val=0;
+ for(i=0;i<length;i++){
+ if(i==0){
+ if(tvb_get_guint8(val_tvb, i)&0x80){
+ /* negative number */
+ val=0xffffffff;
+ } else {
+ /* positive number */
+ val=0;
+ }
+ }
+ val=(val<<8)|tvb_get_guint8(val_tvb,i);
+ }
+ offset += length * 8;
+
+ hfi = proto_registrar_get_nth(hf_index);
+ if (! hfi)
+ THROW(ReportedBoundsError);
+ if (FT_IS_INT(hfi->type)) {
+ it=proto_tree_add_int(tree, hf_index, tvb, (offset>>3)-(length+1), length+1, val);
+ } else if (FT_IS_UINT(hfi->type)) {
+ it=proto_tree_add_uint(tree, hf_index, tvb, (offset>>3)-(length+1), length+1, val);
+ } else {
+ proto_tree_add_expert_format(tree, actx->pinfo, &ei_per_field_not_integer, tvb, (offset>>3)-(length+1), length+1,
+ "Field is not an integer: %s", hfi->abbrev);
+ REPORT_DISSECTOR_BUG("PER integer field that's not an FT_INT* or FT_UINT*");
+ }
+
+
+ actx->created_item = it;
+
+ if(value){
+ *value=val;
+ }
+
+ return offset;
+}
+/* 64 bits experimental version, internal for now */
+static guint32
+dissect_per_integer64b(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, gint64 *value)
+{
+ guint32 i, length;
+ guint64 val;
+ proto_item *it=NULL;
+ header_field_info *hfi;
+
+ /* 12.2.6 b */
+ offset=dissect_per_length_determinant(tvb, offset, actx, tree, -1, &length, NULL);
+ /* gassert here? */
+ if(length>8){
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "too long integer (64b)");
+ length=8;
+ }
+
+ val=0;
+ for(i=0;i<length;i++){
+ if(i==0){
+ if(tvb_get_guint8(tvb, offset>>3)&0x80){
+ /* negative number */
+ val=G_GUINT64_CONSTANT(0xffffffffffffffff);
+ } else {
+ /* positive number */
+ val=0;
+ }
+ }
+ val=(val<<8)|tvb_get_guint8(tvb,offset>>3);
+ offset+=8;
+ }
+
+ hfi = proto_registrar_get_nth(hf_index);
+ if (! hfi)
+ THROW(ReportedBoundsError);
+ if (FT_IS_INT(hfi->type)) {
+ it=proto_tree_add_int64(tree, hf_index, tvb, (offset>>3)-(length+1), length+1, (gint64)val);
+ } else if (FT_IS_UINT(hfi->type)) {
+ it=proto_tree_add_uint64(tree, hf_index, tvb, (offset>>3)-(length+1), length+1, val);
+ } else {
+ proto_tree_add_expert_format(tree, actx->pinfo, &ei_per_field_not_integer, tvb, (offset>>3)-(length+1), length+1,
+ "Field is not an integer: %s", hfi->abbrev);
+ REPORT_DISSECTOR_BUG("PER integer field that's not an FT_INT* or FT_UINT*");
+ }
+
+
+ actx->created_item = it;
+
+ if(value){
+ *value=(gint64)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, asn1_ctx_t *actx, proto_tree *tree, int hf_index, guint32 min, guint32 max, guint32 *value, 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;
+
+DEBUG_ENTRY("dissect_per_constrained_integer");
+ if(has_extension){
+ gboolean extension_present;
+ offset=dissect_per_boolean(tvb, offset, actx, tree, hf_per_extension_present_bit, &extension_present);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ if(extension_present){
+ offset = dissect_per_integer(tvb, offset, actx, tree, hf_index, (gint32*)value);
+ return offset;
+ }
+ }
+
+ hfi = proto_registrar_get_nth(hf_index);
+
+ /* 10.5.3 Let "range" be defined as the integer value ("ub" - "lb" 1), and let the value to be encoded be "n".
+ * 10.5.7 In the case of the ALIGNED variant the encoding depends on whether
+ * d) "range" is greater than 64K (the indefinite length case).
+ */
+ if(((max-min)>65536)&&(actx->aligned)){
+ /* just set range really big so it will fall through
+ to the bottom of the encoding */
+ range=1000000;
+ } else {
+ /* Really ugly hack.
+ * We should really use guint64 as parameters for min/max.
+ * This is to prevent range from being 0 if
+ * the range for a signed integer spans the entire 32 bit range.
+ * Special case the 2 common cases when this can happen until
+ * a real fix is implemented.
+ */
+ if( (max==0x7fffffff && min==0x80000000)
+ || (max==0xffffffff && min==0x00000000) ){
+ range=0xffffffff;
+ } else {
+ range=max-min+1;
+ }
+ }
+
+ val=0;
+ timeval.secs=val; timeval.nsecs=0;
+ /* 10.5.4 If "range" has the value 1, then the result of the encoding shall be an empty bit-field (no bits).*/
+
+ /* something is really wrong if range is 0 */
+ DISSECTOR_ASSERT(range!=0);
+
+ if(range==1){
+ val_start = offset>>3; val_length = 0;
+ val = min;
+ } else if((range<=255)||(!actx->aligned)) {
+ /* 10.5.7.1
+ * 10.5.6 In the case of the UNALIGNED variant the value ("n" - "lb") shall be encoded
+ * as a non-negative binary integer in a bit field as specified in 10.3 with the minimum
+ * number of bits necessary to represent the range.
+ */
+ char *str;
+ int i, length;
+ guint32 mask,mask2;
+ /* We only handle 32 bit integers */
+ mask = 0x80000000;
+ mask2 = 0x7fffffff;
+ i = 32;
+ while ((range & mask)== 0){
+ i = i - 1;
+ mask = mask>>1;
+ mask2 = mask2>>1;
+ }
+ if ((range & mask2) == 0)
+ i = i-1;
+
+ num_bits = i;
+ length=(num_bits+7)>>3;
+ if(range<=2){
+ num_bits=1;
+ }
+
+ val_start = (offset)>>3;
+ val_length = length;
+ val = (guint32)tvb_get_bits64(tvb,offset,num_bits,ENC_BIG_ENDIAN);
+
+ if (display_internal_per_fields){
+ str = decode_bits_in_field(actx->pinfo->pool, (offset&0x07),num_bits,val,ENC_BIG_ENDIAN);
+ proto_tree_add_uint(tree, hf_per_internal_min, tvb, val_start,val_length, min);
+ proto_tree_add_uint64(tree, hf_per_internal_range, tvb, val_start, val_length, range);
+ proto_tree_add_uint(tree, hf_per_internal_num_bits, tvb, val_start, val_length, num_bits);
+ proto_tree_add_uint64_format_value(tree, hf_per_internal_value, tvb, val_start, val_length, val+min, "%s decimal value: %u", str, val+min);
+ }
+ /* The actual value */
+ val+=min;
+ offset = offset+num_bits;
+ } else if(range==256){
+ /* 10.5.7.2 */
+
+ /* in the aligned case, align to byte boundary */
+ BYTE_ALIGN_OFFSET(offset);
+ 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 */
+
+ /* in the aligned case, align to byte boundary */
+ BYTE_ALIGN_OFFSET(offset);
+ 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, actx, tree, -1, &bit);
+ num_bytes=bit;
+ offset=dissect_per_boolean(tvb, offset, actx, tree, -1, &bit);
+ num_bytes=(num_bytes<<1)|bit;
+
+ num_bytes++; /* lower bound for length determinant is 1 */
+ if (display_internal_per_fields)
+ proto_tree_add_uint(tree, hf_per_const_int_len, tvb, (offset>>3), 1, num_bytes);
+
+ /* byte aligned */
+ BYTE_ALIGN_OFFSET(offset);
+ 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 (FT_IS_UINT(hfi->type)) {
+ it = proto_tree_add_uint(tree, hf_index, tvb, val_start, val_length, val);
+ per_check_value(val, min, max, actx, it, FALSE);
+ } else if (FT_IS_INT(hfi->type)) {
+ it = proto_tree_add_int(tree, hf_index, tvb, val_start, val_length, val);
+ per_check_value(val, min, max, actx, it, TRUE);
+ } else if (FT_IS_TIME(hfi->type)) {
+ it = proto_tree_add_time(tree, hf_index, tvb, val_start, val_length, &timeval);
+ } else {
+ THROW(ReportedBoundsError);
+ }
+ actx->created_item = it;
+ if (value) *value = val;
+ return offset;
+}
+
+guint32
+dissect_per_constrained_integer_64b(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, guint64 min, guint64 max, guint64 *value, gboolean has_extension)
+{
+ proto_item *it=NULL, *int_item=NULL;
+ guint64 range, val;
+ gint val_start, val_length;
+ nstime_t timeval;
+ header_field_info *hfi;
+ int num_bits;
+ gboolean tmp;
+
+DEBUG_ENTRY("dissect_per_constrained_integer_64b");
+ if(has_extension){
+ gboolean extension_present;
+ offset=dissect_per_boolean(tvb, offset, actx, tree, hf_per_extension_present_bit, &extension_present);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ if(extension_present){
+ offset = dissect_per_integer64b(tvb, offset, actx, tree, hf_index, (gint64*)value);
+ return offset;
+ }
+ }
+
+ hfi = proto_registrar_get_nth(hf_index);
+
+ /* 10.5.3 Let "range" be defined as the integer value ("ub" - "lb" 1), and let the value to be encoded be "n".
+ * 10.5.7 In the case of the ALIGNED variant the encoding depends on whether
+ * d) "range" is greater than 64K (the indefinite length case).
+ */
+ if(((max-min)>65536)&&(actx->aligned)){
+ /* just set range really big so it will fall through
+ to the bottom of the encoding */
+ /* range=1000000; */
+ range = max-min;
+ if (range==65536)
+ range++; /* make it fall trough? */
+ } else {
+ /* Copied from the 32 bit version, assuming the same problem occurs
+ * at 64 bit boundary.
+ * Really ugly hack.
+ * We should really use guint64 as parameters for min/max.
+ * This is to prevent range from being 0 if
+ * the range for a signed integer spans the entire 32 bit range.
+ * Special case the 2 common cases when this can happen until
+ * a real fix is implemented.
+ */
+ if( (max==G_GINT64_CONSTANT(0x7fffffffffffffff) && min==G_GINT64_CONSTANT(0x8000000000000000))
+ || (max==G_GINT64_CONSTANT(0xffffffffffffffff) && min==0) ){
+ range=G_GINT64_CONSTANT(0xffffffffffffffff);
+ } else {
+ range=max-min+1;
+ }
+ }
+
+ val=0;
+ timeval.secs=0; timeval.nsecs=0;
+ /* 10.5.4 If "range" has the value 1, then the result of the encoding shall be an empty bit-field (no bits).*/
+
+ /* something is really wrong if range is 0 */
+ DISSECTOR_ASSERT(range!=0);
+
+ if(range==1){
+ val_start = offset>>3; val_length = 0;
+ val = min;
+ } else if((range<=255)||(!actx->aligned)) {
+ /* 10.5.7.1
+ * 10.5.6 In the case of the UNALIGNED variant the value ("n" - "lb") shall be encoded
+ * as a non-negative binary integer in a bit field as specified in 10.3 with the minimum
+ * number of bits necessary to represent the range.
+ */
+ char *str;
+ int i, bit, length, str_length, str_index = 0;
+ guint64 mask,mask2;
+ /* We only handle 64 bit integers */
+ mask = G_GUINT64_CONSTANT(0x8000000000000000);
+ mask2 = G_GUINT64_CONSTANT(0x7fffffffffffffff);
+ i = 64;
+ while ((range & mask)== 0){
+ i = i - 1;
+ mask = mask>>1;
+ mask2 = mask2>>1;
+ }
+ if ((range & mask2) == 0)
+ i = i-1;
+
+ num_bits = i;
+ length=1;
+ if(range<=2){
+ num_bits=1;
+ }
+
+ /* prepare the string (max number of bits + quartet separators) */
+ str_length = 512+128;
+ str = (char *)wmem_alloc(wmem_packet_scope(), str_length+1);
+ for(bit=0;bit<((int)(offset&0x07));bit++){
+ if(bit&&(!(bit%4))){
+ if (str_index < str_length) str[str_index++] = ' ';
+ }
+ if (str_index < str_length) str[str_index++] = '.';
+ }
+ /* read the bits for the int */
+ for(i=0;i<num_bits;i++){
+ if(bit&&(!(bit%4))){
+ if (str_index < str_length) str[str_index++] = ' ';
+ }
+ if(bit&&(!(bit%8))){
+ length+=1;
+ if (str_index < str_length) str[str_index++] = ' ';
+ }
+ bit++;
+ offset=dissect_per_boolean(tvb, offset, actx, tree, -1, &tmp);
+ val<<=1;
+ if(tmp){
+ val|=1;
+ if (str_index < str_length) str[str_index++] = '1';
+ } else {
+ if (str_index < str_length) str[str_index++] = '0';
+ }
+ }
+ for(;bit%8;bit++){
+ if(bit&&(!(bit%4))){
+ if (str_index < str_length) str[str_index++] = ' ';
+ }
+ if (str_index < str_length) str[str_index++] = '.';
+ }
+ str[str_index] = '\0'; /* Terminate string */
+ val_start = (offset-num_bits)>>3; val_length = length;
+ val+=min;
+ if (display_internal_per_fields) {
+ proto_tree_add_uint64(tree, hf_per_internal_range, tvb, val_start, val_length, range);
+ proto_tree_add_uint(tree, hf_per_internal_num_bits, tvb, val_start,val_length, num_bits);
+ proto_tree_add_uint64_format_value(tree, hf_per_internal_value, tvb, val_start, val_length, val, "%s decimal value: %" PRIu64, str, val);
+ }
+ } else if(range==256){
+ /* 10.5.7.2 */
+
+ /* in the aligned case, align to byte boundary */
+ BYTE_ALIGN_OFFSET(offset);
+ 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 */
+
+ /* in the aligned case, align to byte boundary */
+ BYTE_ALIGN_OFFSET(offset);
+ 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,n_bits;
+
+ /* 10.5.7.4 */
+ /* 12.2.6 */
+ /* calculate the number of bits to hold the length */
+ if ((range & G_GINT64_CONSTANT(0xffffffff00000000)) != 0){
+ n_bits=3;
+ }else{
+ n_bits=2;
+ }
+ num_bytes =tvb_get_bits8(tvb, offset, n_bits);
+ num_bytes++; /* lower bound for length determinant is 1 */
+ if (display_internal_per_fields){
+ int_item = proto_tree_add_bits_item(tree, hf_per_const_int_len, tvb, offset,n_bits, ENC_BIG_ENDIAN);
+ proto_item_append_text(int_item,"+1=%u bytes, Range = (%" PRIu64 ")",num_bytes, range);
+ }
+ offset = offset+n_bits;
+ /* byte aligned */
+ BYTE_ALIGN_OFFSET(offset);
+ 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;
+ }
+
+
+ if (FT_IS_UINT(hfi->type)) {
+ it = proto_tree_add_uint64(tree, hf_index, tvb, val_start, val_length, val);
+ per_check_value64(val, min, max, actx, it, FALSE);
+ } else if (FT_IS_INT(hfi->type)) {
+ it = proto_tree_add_int64(tree, hf_index, tvb, val_start, val_length, val);
+ per_check_value64(val, min, max, actx, it, TRUE);
+ } else if (FT_IS_TIME(hfi->type)) {
+ timeval.secs = (guint32)val;
+ it = proto_tree_add_time(tree, hf_index, tvb, val_start, val_length, &timeval);
+ } else {
+ THROW(ReportedBoundsError);
+ }
+ actx->created_item = it;
+ if (value) *value = val;
+ return offset;
+}
+
+/* 13 Encoding the enumerated type */
+guint32
+dissect_per_enumerated(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, guint32 root_num, guint32 *value, gboolean has_extension, guint32 ext_num, guint32 *value_map)
+{
+
+ proto_item *it=NULL;
+ guint32 enum_index, val;
+ guint32 start_offset = offset;
+ gboolean extension_present = FALSE;
+ header_field_info *hfi;
+
+ if (has_extension) {
+ /* Extension bit */
+ offset = dissect_per_boolean(tvb, offset, actx, tree, hf_per_extension_present_bit, &extension_present);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ }
+
+ if (!extension_present) {
+ /* 13.2 */
+ offset = dissect_per_constrained_integer(tvb, offset, actx, tree, hf_per_enum_index, 0, root_num - 1, &enum_index, FALSE);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ } else {
+ /* 13.3 ".. and the value shall be added to the field-list as a
+ * normally small non-negative whole number whose value is the
+ * enumeration index of the additional enumeration and with "lb" set to 0.."
+ */
+ offset = dissect_per_normally_small_nonnegative_whole_number(tvb, offset, actx, tree, hf_per_enum_extension_index, &enum_index);
+ enum_index += root_num;
+ }
+ val = (value_map && (enum_index<(root_num+ext_num))) ? value_map[enum_index] : enum_index;
+ hfi = proto_registrar_get_nth(hf_index);
+ if (FT_IS_UINT(hfi->type)) {
+ it = proto_tree_add_uint(tree, hf_index, tvb, start_offset>>3, BLEN(start_offset, offset), val);
+ } else {
+ THROW(ReportedBoundsError);
+ }
+ actx->created_item = it;
+ if (value) *value = val;
+ return offset;
+}
+
+/* 14 Encoding the real type */
+guint32
+dissect_per_real(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, double *value)
+{
+ guint32 val_length, end_offset;
+ tvbuff_t *val_tvb;
+ double val = 0;
+
+ offset = dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_real_length, &val_length, NULL);
+ if(val_length == 0){
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "unexpected length");
+ }
+ if (actx->aligned) BYTE_ALIGN_OFFSET(offset);
+ val_tvb = tvb_new_octet_aligned(tvb, offset, val_length * 8);
+ /* Add new data source if the offet was unaligned */
+ if ((offset & 7) != 0) {
+ add_new_data_source(actx->pinfo, val_tvb, "Unaligned OCTET STRING");
+ }
+ end_offset = offset + val_length * 8;
+
+ val = asn1_get_real(tvb_get_ptr(val_tvb, 0, val_length), val_length);
+ actx->created_item = proto_tree_add_double(tree, hf_index, val_tvb, 0, val_length, val);
+
+ if (value) *value = val;
+
+ return end_offset;
+}
+
+/* 22 Encoding the choice type */
+guint32
+dissect_per_choice(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, gint ett_index, const per_choice_t *choice, gint *value)
+{
+ gboolean /*extension_present,*/ extension_flag;
+ int extension_root_entries;
+ guint32 choice_index;
+ int i, idx, cidx;
+ guint32 ext_length = 0;
+ guint32 old_offset = offset;
+ proto_item *choice_item = NULL;
+ proto_tree *choice_tree = NULL;
+
+DEBUG_ENTRY("dissect_per_choice");
+
+ if (value) *value = -1;
+
+ /* 22.5 */
+ if (choice[0].extension == ASN1_NO_EXTENSIONS){
+ /*extension_present = FALSE; ?? */
+ extension_flag = FALSE;
+ } else {
+ /*extension_present = TRUE; ?? */
+ offset = dissect_per_boolean(tvb, offset, actx, tree, hf_per_extension_bit, &extension_flag);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ }
+
+ /* count the number of entries in the extension root and extension addition */
+ extension_root_entries = 0;
+ for (i=0; choice[i].p_id; i++) {
+ switch(choice[i].extension){
+ case ASN1_NO_EXTENSIONS:
+ case ASN1_EXTENSION_ROOT:
+ extension_root_entries++;
+ break;
+ case ASN1_NOT_EXTENSION_ROOT:
+ break;
+ }
+ }
+
+ if (!extension_flag) { /* 22.6, 22.7 */
+ if (extension_root_entries == 1) { /* 22.5 */
+ choice_index = 0;
+ } else {
+ offset = dissect_per_constrained_integer(tvb, offset, actx,
+ tree, hf_per_choice_index, 0, extension_root_entries - 1,
+ &choice_index, FALSE);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ }
+
+ idx = -1; cidx = choice_index;
+ for (i=0; choice[i].p_id; i++) {
+ if(choice[i].extension != ASN1_NOT_EXTENSION_ROOT){
+ if (!cidx) { idx = i; break; }
+ cidx--;
+ }
+ }
+ } else { /* 22.8 */
+ offset = dissect_per_normally_small_nonnegative_whole_number(tvb, offset, actx, tree, hf_per_choice_extension_index, &choice_index);
+ offset = dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_open_type_length, &ext_length, NULL);
+
+ idx = -1; cidx = choice_index;
+ for (i=0; choice[i].p_id; i++) {
+ if(choice[i].extension == ASN1_NOT_EXTENSION_ROOT){
+ if (!cidx) { idx = i; break; }
+ cidx--;
+ }
+ }
+ }
+
+ if (idx != -1) {
+ choice_item = proto_tree_add_uint(tree, hf_index, tvb, old_offset>>3, 0, choice[idx].value);
+ choice_tree = proto_item_add_subtree(choice_item, ett_index);
+ if (!extension_flag) {
+ offset = choice[idx].func(tvb, offset, actx, choice_tree, *choice[idx].p_id);
+ } else {
+ choice[idx].func(tvb, offset, actx, choice_tree, *choice[idx].p_id);
+ offset += ext_length * 8;
+ }
+ proto_item_set_len(choice_item, BLEN(old_offset, offset));
+ } else {
+ if (!extension_flag) {
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "unknown extension root index in choice");
+ } else {
+ offset += ext_length * 8;
+ proto_tree_add_expert_format(tree, actx->pinfo, &ei_per_choice_extension_unknown,
+ tvb, old_offset>>3, BLEN(old_offset, offset),
+ "Choice no. %d in extension", choice_index);
+ }
+ }
+
+ if (value && (idx != -1))
+ *value = choice[idx].value;
+
+ return offset;
+}
+
+
+static const char *
+index_get_optional_name(const per_sequence_t *sequence, int idx)
+{
+ int i;
+ header_field_info *hfi;
+
+ for(i=0;sequence[i].p_id;i++){
+ if((sequence[i].extension!=ASN1_NOT_EXTENSION_ROOT)&&(sequence[i].optional==ASN1_OPTIONAL)){
+ if (idx == 0) {
+ hfi = proto_registrar_get_nth(*sequence[i].p_id);
+ return (hfi) ? hfi->name : "<unknown filed>";
+ }
+ idx--;
+ }
+ }
+ return "<unknown type>";
+}
+
+static const char *
+index_get_extension_name(const per_sequence_t *sequence, int idx)
+{
+ int i;
+ header_field_info *hfi;
+
+ for(i=0;sequence[i].p_id;i++){
+ if(sequence[i].extension==ASN1_NOT_EXTENSION_ROOT){
+ if (idx == 0) {
+ if (*sequence[i].p_id == -1) return "extension addition group";
+ hfi = proto_registrar_get_nth(*sequence[i].p_id);
+ return (hfi) ? hfi->name : "<unknown filed>";
+ }
+ idx--;
+ }
+ }
+ return "<unknown type>";
+}
+
+static const char *
+index_get_field_name(const per_sequence_t *sequence, int idx)
+{
+ if (sequence) {
+ header_field_info *hfi = proto_registrar_get_nth(*sequence[idx].p_id);
+
+ if (hfi) {
+ return hfi->name;
+ }
+ }
+ return "<unknown field>";
+}
+
+/* this functions decodes a SEQUENCE
+ it can only handle SEQUENCES with at most 32 DEFAULT or OPTIONAL fields
+18.1 extension bit
+18.2 optional/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, asn1_ctx_t *actx, proto_tree *parent_tree, int hf_index, gint ett_index, const per_sequence_t *sequence)
+{
+ gboolean /*extension_present,*/ extension_flag, optional_field_flag;
+ proto_item *item;
+ proto_tree *tree;
+ guint32 old_offset=offset;
+ guint32 i, j, num_opts;
+ guint32 optional_mask[SEQ_MAX_COMPONENTS>>5];
+
+DEBUG_ENTRY("dissect_per_sequence");
+ DISSECTOR_ASSERT(sequence);
+
+ item=proto_tree_add_item(parent_tree, hf_index, tvb, offset>>3, 0, ENC_BIG_ENDIAN);
+ 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 {
+ /*extension_present=1; ?? */
+ offset=dissect_per_boolean(tvb, offset, actx, tree, hf_per_extension_bit, &extension_flag);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ }
+ /* 18.2 */
+ num_opts=0;
+ for(i=0;sequence[i].p_id;i++){
+ if((sequence[i].extension!=ASN1_NOT_EXTENSION_ROOT)&&(sequence[i].optional==ASN1_OPTIONAL)){
+ num_opts++;
+ }
+ }
+ if (num_opts > SEQ_MAX_COMPONENTS) {
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "too many optional/default components");
+ }
+
+ memset(optional_mask, 0, sizeof(optional_mask));
+ for(i=0;i<num_opts;i++){
+ offset=dissect_per_boolean(tvb, offset, actx, tree, hf_per_optional_field_bit, &optional_field_flag);
+ if (tree) {
+ proto_item_append_text(actx->created_item, " (%s %s present)",
+ index_get_optional_name(sequence, i), optional_field_flag?"is":"is NOT");
+ }
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ if(optional_field_flag){
+ optional_mask[i>>5]|=0x80000000>>(i&0x1f);
+ }
+ }
+
+
+ /* 18.4 */
+ for(i=0,j=0;sequence[i].p_id;i++){
+ if( (sequence[i].extension==ASN1_NO_EXTENSIONS)
+ || (sequence[i].extension==ASN1_EXTENSION_ROOT) ){
+ if(sequence[i].optional==ASN1_OPTIONAL){
+ gboolean is_present;
+ if (num_opts == 0){
+ continue;
+ }
+ is_present=(0x80000000>>(j&0x1f))&optional_mask[j>>5];
+ num_opts--;
+ j++;
+ if(!is_present){
+ continue;
+ }
+ }
+ if(sequence[i].func){
+ offset=sequence[i].func(tvb, offset, actx, tree, *sequence[i].p_id);
+ } else {
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, index_get_field_name(sequence, i));
+ }
+ }
+ }
+
+
+ if(extension_flag){
+ gboolean extension_bit;
+ guint32 num_known_extensions;
+ guint32 num_extensions;
+ guint32 extension_mask;
+
+ offset=dissect_per_normally_small_nonnegative_whole_number(tvb, offset, actx, tree, 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 don't 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 don't report it as a bug
+ then it won't get fixed!
+ */
+ num_extensions+=1;
+ if (num_extensions > 32) {
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "too many extensions");
+ }
+
+ extension_mask=0;
+ for(i=0;i<num_extensions;i++){
+ offset=dissect_per_boolean(tvb, offset, actx, tree, hf_per_extension_present_bit, &extension_bit);
+ if (tree) {
+ proto_item_append_text(actx->created_item, " (%s %s present)",
+ index_get_extension_name(sequence, i), extension_bit?"is":"is NOT");
+ }
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+
+ extension_mask=(extension_mask<<1)|extension_bit;
+ }
+
+ /* find how many extensions we know about */
+ num_known_extensions=0;
+ for(i=0;sequence[i].p_id;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;
+ gint32 difference;
+ guint32 extension_index;
+ guint32 k;
+
+ if(!((1U<<(num_extensions-1-i))&extension_mask)){
+ /* this extension is not encoded in this PDU */
+ continue;
+ }
+
+ offset=dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_open_type_length, &length, NULL);
+
+ if(i>=num_known_extensions){
+ /* we don't know how to decode this extension */
+ offset+=length*8;
+ expert_add_info(actx->pinfo, item, &ei_per_sequence_extension_unknown);
+ continue;
+ }
+
+ extension_index=0;
+ for(j=0,k=0;sequence[j].p_id;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, actx, tree, *sequence[extension_index].p_id);
+ offset+=length*8;
+ difference = offset - new_offset;
+ /* A difference of 7 or less might be byte aligning */
+ /* Difference could be 8 if open type has no bits and the length is 1 */
+ if ((length > 1) && (difference > 7)) {
+ proto_tree_add_expert_format(tree, actx->pinfo, &ei_per_encoding_error, tvb, new_offset>>3, (offset-new_offset)>>3,
+ "Possible encoding error full length not decoded. Open type length %u, decoded %u",length, length - (difference>>3));
+ }
+ else if (difference < 0) {
+ proto_tree_add_expert_format(tree, actx->pinfo, &ei_per_encoding_error, tvb, new_offset>>3, (offset-new_offset)>>3,
+ "Possible encoding error open type length less than dissected bits. Open type length %u, decoded %u", length, length - (difference>>3));
+ }
+ } else {
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, index_get_field_name(sequence, extension_index));
+ offset+=length*8;
+ }
+ }
+ }
+
+ proto_item_set_len(item, (offset>>3)!=(old_offset>>3)?(offset>>3)-(old_offset>>3):1);
+ actx->created_item = item;
+ return offset;
+}
+
+guint32
+dissect_per_sequence_eag(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, const per_sequence_t *sequence)
+{
+ gboolean optional_field_flag;
+ guint32 i, j, num_opts;
+ guint32 optional_mask[SEQ_MAX_COMPONENTS>>5];
+
+DEBUG_ENTRY("dissect_per_sequence_eag");
+
+ num_opts=0;
+ for(i=0;sequence[i].p_id;i++){
+ if(sequence[i].optional==ASN1_OPTIONAL){
+ num_opts++;
+ }
+ }
+ if (num_opts > SEQ_MAX_COMPONENTS) {
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "too many optional/default components");
+ }
+
+ memset(optional_mask, 0, sizeof(optional_mask));
+ for(i=0;i<num_opts;i++){
+ offset=dissect_per_boolean(tvb, offset, actx, tree, hf_per_optional_field_bit, &optional_field_flag);
+ if (tree) {
+ proto_item_append_text(actx->created_item, " (%s %s present)",
+ index_get_optional_name(sequence, i), optional_field_flag?"is":"is NOT");
+ }
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ if(optional_field_flag){
+ optional_mask[i>>5]|=0x80000000>>(i&0x1f);
+ }
+ }
+
+ for(i=0,j=0;sequence[i].p_id;i++){
+ if(sequence[i].optional==ASN1_OPTIONAL){
+ gboolean is_present;
+ if (num_opts == 0){
+ continue;
+ }
+ is_present=(0x80000000>>(j&0x1f))&optional_mask[j>>5];
+ num_opts--;
+ j++;
+ if(!is_present){
+ continue;
+ }
+ }
+ if(sequence[i].func){
+ offset=sequence[i].func(tvb, offset, actx, tree, *sequence[i].p_id);
+ } else {
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, index_get_field_name(sequence, i));
+ }
+ }
+
+ return offset;
+}
+
+
+/* 15 Encoding the bitstring type
+
+ max_len or min_len == NO_BOUND means there is no lower/upper constraint
+
+*/
+
+static tvbuff_t *dissect_per_bit_string_display(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, header_field_info *hfi, guint32 length, int * const *named_bits, gint num_named_bits _U_)
+{
+ tvbuff_t *out_tvb = NULL;
+ guint32 pad_length=0;
+ guint64 value;
+
+ out_tvb = tvb_new_octet_aligned(tvb, offset, length);
+ add_new_data_source(actx->pinfo, out_tvb, "Bitstring tvb");
+
+ if (hfi) {
+ actx->created_item = proto_tree_add_item(tree, hf_index, out_tvb, 0, -1, ENC_BIG_ENDIAN);
+ proto_item_append_text(actx->created_item, " [bit length %u", length);
+ if (length%8) {
+ pad_length = 8-(length%8);
+ proto_item_append_text(actx->created_item, ", %u LSB pad bits", pad_length);
+ }
+
+ if (length<=64) { /* if read into 64 bits also handle length <= 24, 40, 48, 56 bits */
+ if (length<=8) {
+ value = tvb_get_bits8(out_tvb, 0, length);
+ }else if (length<=16) {
+ value = tvb_get_bits16(out_tvb, 0, length, ENC_BIG_ENDIAN);
+ }else if (length<=24) { /* first read 16 and then the remaining bits */
+ value = tvb_get_bits16(out_tvb, 0, 16, ENC_BIG_ENDIAN);
+ value <<= 8 - pad_length;
+ value |= tvb_get_bits8(out_tvb, 16, length - 16);
+ }else if (length<=32) {
+ value = tvb_get_bits32(out_tvb, 0, length, ENC_BIG_ENDIAN);
+ }else if (length<=40) { /* first read 32 and then the remaining bits */
+ value = tvb_get_bits32(out_tvb, 0, 32, ENC_BIG_ENDIAN);
+ value <<= 8 - pad_length;
+ value |= tvb_get_bits8(out_tvb, 32, length - 32);
+ }else if (length<=48) { /* first read 32 and then the remaining bits */
+ value = tvb_get_bits32(out_tvb, 0, 32, ENC_BIG_ENDIAN);
+ value <<= 16 - pad_length;
+ value |= tvb_get_bits16(out_tvb, 32, length - 32, ENC_BIG_ENDIAN);
+ }else if (length<=56) { /* first read 32 and 16 then the remaining bits */
+ value = tvb_get_bits32(out_tvb, 0, 32, ENC_BIG_ENDIAN);
+ value <<= 16;
+ value |= tvb_get_bits16(out_tvb, 32, 16, ENC_BIG_ENDIAN);
+ value <<= 8 - pad_length;
+ value |= tvb_get_bits8(out_tvb, 48, length - 48);
+ }else {
+ value = tvb_get_bits64(out_tvb, 0, length, ENC_BIG_ENDIAN);
+ }
+ proto_item_append_text(actx->created_item, ", %s decimal value %" PRIu64,
+ decode_bits_in_field(actx->pinfo->pool, 0, length, value, ENC_BIG_ENDIAN), value);
+ if (named_bits) {
+ const guint32 named_bits_bytelen = (num_named_bits + 7) / 8;
+ proto_tree *subtree = proto_item_add_subtree(actx->created_item, ett_per_named_bits);
+ for (guint32 i = 0; i < named_bits_bytelen; i++) {
+ // If less data is available than the number of named bits, then
+ // the trailing (right) bits are assumed to be 0.
+ value = 0;
+ const guint32 bit_offset = 8 * i;
+ if (bit_offset < length) {
+ value = tvb_get_guint8(out_tvb, i);
+ }
+
+ // Process 8 bits at a time instead of 64, each field masks a
+ // single byte.
+ int* const * section_named_bits = named_bits + bit_offset;
+ int* flags[9];
+ if (num_named_bits - bit_offset > 8) {
+ memcpy(&flags[0], named_bits + bit_offset, 8 * sizeof(int*));
+ flags[8] = NULL;
+ section_named_bits = flags;
+ }
+
+ // TODO should non-zero pad bits be masked from the value?
+ // When trailing zeroes are not present in the data, mark the
+ // last byte for the lack of a better alternative.
+ proto_tree_add_bitmask_list_value(subtree, out_tvb, offset + MIN(i, length - 1), 1, section_named_bits, value);
+ }
+ }
+ }
+ proto_item_append_text(actx->created_item, "]");
+ }
+
+ return out_tvb;
+}
+guint32
+dissect_per_bit_string(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, int * const *named_bits, gint num_named_bits, tvbuff_t **value_tvb, int *len)
+{
+ /*gint val_start, val_length;*/
+ guint32 length, fragmented_length = 0;
+ header_field_info *hfi;
+ gboolean is_fragmented = FALSE;
+ tvbuff_t *fragmented_tvb = NULL, *out_tvb = NULL, *fragment_tvb = NULL;
+
+ 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) {
+ if (value_tvb)
+ *value_tvb = out_tvb;
+ if (len)
+ *len = 0;
+ return offset;
+ }
+
+ if (min_len == NO_BOUND) {
+ min_len = 0;
+ }
+ /* 15.6 If an extension marker is present in the size constraint specification of the bitstring type,
+ * a single bit shall be added to the field-list in a bit-field of length one.
+ * The bit shall be set to 1 if the length of this encoding is not within the range of the extension root,
+ * and zero otherwise.
+ */
+ if (has_extension) {
+ gboolean extension_present;
+ offset = dissect_per_boolean(tvb, offset, actx, tree, hf_per_extension_present_bit, &extension_present);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ if(extension_present){
+ next_fragment1:
+ offset=dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_bit_string_length, &length, &is_fragmented);
+ if(length || fragmented_length){
+ /* align to byte */
+ if (actx->aligned){
+ BYTE_ALIGN_OFFSET(offset);
+ }
+ if(is_fragmented){
+ fragment_tvb = tvb_new_octet_aligned(tvb, offset, length);
+ if(fragmented_length==0)
+ fragmented_tvb = tvb_new_composite();
+ tvb_composite_append(fragmented_tvb, fragment_tvb);
+ offset += length;
+ fragmented_length += length;
+ goto next_fragment1;
+ }
+ if(fragmented_length){
+ if(length){
+ tvb_composite_append(fragmented_tvb, tvb_new_octet_aligned(tvb, offset, length));
+ fragmented_length += length;
+ }
+ tvb_composite_finalize(fragmented_tvb);
+ add_new_data_source(actx->pinfo, fragmented_tvb, "Fragmented bitstring tvb");
+ out_tvb = dissect_per_bit_string_display(fragmented_tvb, 0, actx, tree, hf_index, hfi,
+ fragmented_length, named_bits, num_named_bits);
+ }
+ else
+ out_tvb = dissect_per_bit_string_display(tvb, offset, actx, tree, hf_index, hfi, length, named_bits, num_named_bits);
+ }
+ /* XXX: ?? */
+ /*val_start = offset>>3;*/
+ /*val_length = (length+7)/8;*/
+ offset+=length;
+
+ if (value_tvb)
+ *value_tvb = out_tvb;
+ if (len)
+ *len = fragmented_length ? fragmented_length : length;
+
+ return offset;
+ }
+ }
+
+ /* 15.9 if length is fixed and less than or equal to sixteen bits*/
+ if ((min_len==max_len) && (max_len<=16)) {
+ out_tvb = dissect_per_bit_string_display(tvb, offset, actx, tree, hf_index, hfi, min_len, named_bits, num_named_bits);
+ offset+=min_len;
+ if (value_tvb)
+ *value_tvb = out_tvb;
+ if (len)
+ *len = min_len;
+ return offset;
+ }
+
+
+ /* 15.10 if length is fixed and less than to 64kbits*/
+ if((min_len==max_len)&&(min_len<65536)){
+ /* (octet-aligned in the ALIGNED variant)
+ * align to byte
+ */
+ if (actx->aligned){
+ BYTE_ALIGN_OFFSET(offset);
+ }
+ out_tvb = dissect_per_bit_string_display(tvb, offset, actx, tree, hf_index, hfi, min_len, named_bits, num_named_bits);
+ offset+=min_len;
+ if (value_tvb)
+ *value_tvb = out_tvb;
+ if (len)
+ *len = min_len;
+ return offset;
+ }
+
+ /* 15.11 */
+ if (max_len != NO_BOUND && max_len < 65536) {
+ offset=dissect_per_constrained_integer(tvb, offset, actx,
+ tree, hf_per_bit_string_length, min_len, max_len,
+ &length, FALSE);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ } else {
+ next_fragment2:
+ offset=dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_bit_string_length, &length, &is_fragmented);
+ }
+ if(length || fragmented_length){
+ /* align to byte */
+ if (actx->aligned){
+ BYTE_ALIGN_OFFSET(offset);
+ }
+ if(is_fragmented){
+ fragment_tvb = tvb_new_octet_aligned(tvb, offset, length);
+ if(fragmented_length==0)
+ fragmented_tvb = tvb_new_composite();
+ tvb_composite_append(fragmented_tvb, fragment_tvb);
+ offset += length;
+ fragmented_length += length;
+ goto next_fragment2;
+ }
+ if(fragmented_length){
+ if(length){
+ tvb_composite_append(fragmented_tvb, tvb_new_octet_aligned(tvb, offset, length));
+ fragmented_length += length;
+ }
+ tvb_composite_finalize(fragmented_tvb);
+ add_new_data_source(actx->pinfo, fragmented_tvb, "Fragmented bitstring tvb");
+ out_tvb = dissect_per_bit_string_display(fragmented_tvb, 0, actx, tree, hf_index, hfi,
+ fragmented_length, named_bits, num_named_bits);
+ }
+ else
+ out_tvb = dissect_per_bit_string_display(tvb, offset, actx, tree, hf_index, hfi, length, named_bits, num_named_bits);
+ }
+ /* XXX: ?? */
+ /*val_start = offset>>3;*/
+ /*val_length = (length+7)/8;*/
+ offset+=length;
+
+ if (value_tvb)
+ *value_tvb = out_tvb;
+ if (len)
+ *len = fragmented_length ? fragmented_length : length;
+
+ return offset;
+}
+
+guint32 dissect_per_bit_string_containing_pdu_new(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, dissector_t type_cb)
+{
+ tvbuff_t *val_tvb = NULL;
+ proto_tree *subtree = tree;
+
+ offset = dissect_per_bit_string(tvb, offset, actx, tree, hf_index, min_len, max_len, has_extension, NULL, 0, &val_tvb, NULL);
+
+ if (type_cb && val_tvb) {
+ subtree = proto_item_add_subtree(actx->created_item, ett_per_containing);
+ type_cb(val_tvb, actx->pinfo, subtree, NULL);
+ }
+
+ return offset;
+}
+
+/* this function 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 == NO_BOUND 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, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, tvbuff_t **value_tvb)
+{
+ gint val_start = 0, val_length;
+ guint32 length = 0, fragmented_length = 0;;
+ header_field_info *hfi;
+ gboolean is_fragmented = FALSE;
+ tvbuff_t *out_tvb = NULL, *fragment_tvb = NULL;
+
+ hfi = (hf_index==-1) ? NULL : proto_registrar_get_nth(hf_index);
+
+DEBUG_ENTRY("dissect_per_octet_string");
+
+ if (has_extension) { /* 16.3 an extension marker is present */
+ gboolean extension_present;
+ offset = dissect_per_boolean(tvb, offset, actx, tree, hf_per_extension_present_bit, &extension_present);
+ if (!display_internal_per_fields) proto_item_set_hidden(actx->created_item);
+ if (extension_present) max_len = NO_BOUND; /* skip to 16.8 */
+ }
+
+ if (min_len == NO_BOUND) {
+ 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*/
+ val_start = offset>>3;
+ val_length = min_len;
+ out_tvb = tvb_new_octet_aligned(tvb, offset, val_length * 8);
+ /* Add new data source if the offet was unaligned */
+ if ((offset & 7) != 0) {
+ add_new_data_source(actx->pinfo, out_tvb, "Unaligned OCTET STRING");
+ }
+ offset+=min_len*8;
+
+ } else if ((min_len==max_len)&&(min_len<65536)) {
+ /* 16.7 if length is fixed and less than to 64k*/
+
+ /* align to byte */
+ if (actx->aligned){
+ BYTE_ALIGN_OFFSET(offset);
+ }
+ val_start = offset>>3;
+ val_length = min_len;
+ out_tvb = tvb_new_octet_aligned(tvb, offset, val_length * 8);
+ if ((offset & 7) != 0) {
+ add_new_data_source(actx->pinfo, out_tvb, "Unaligned OCTET STRING");
+ }
+ offset+=min_len*8;
+
+ } else { /* 16.8 */
+ if(max_len>0) {
+ offset = dissect_per_constrained_integer(tvb, offset, actx, tree,
+ hf_per_octet_string_length, min_len, max_len, &length, FALSE);
+
+ if (!display_internal_per_fields)
+ proto_item_set_hidden(actx->created_item);
+ } else {
+ next_fragment:
+ offset = dissect_per_length_determinant(tvb, offset, actx, tree,
+ hf_per_octet_string_length, &length, &is_fragmented);
+ }
+
+ if(length || fragmented_length){
+ /* align to byte */
+ if (actx->aligned){
+ BYTE_ALIGN_OFFSET(offset);
+ }
+ if (is_fragmented) {
+ fragment_tvb = tvb_new_octet_aligned(tvb, offset, length * 8);
+ if (fragmented_length == 0)
+ out_tvb = tvb_new_composite();
+ tvb_composite_append(out_tvb, fragment_tvb);
+ offset += length * 8;
+ fragmented_length += length;
+ goto next_fragment;
+ }
+ if (fragmented_length) {
+ if (length) {
+ tvb_composite_append(out_tvb, tvb_new_octet_aligned(tvb, offset, length * 8));
+ fragmented_length += length;
+ }
+ tvb_composite_finalize(out_tvb);
+ add_new_data_source(actx->pinfo, out_tvb, "Fragmented OCTET STRING");
+ } else {
+ out_tvb = tvb_new_octet_aligned(tvb, offset, length * 8);
+ if ((offset & 7) != 0) {
+ add_new_data_source(actx->pinfo, out_tvb, "Unaligned OCTET STRING");
+ }
+ }
+ } else {
+ val_start = offset>>3;
+ }
+ val_length = fragmented_length ? fragmented_length : length;
+ offset+=length*8;
+ }
+
+ if (hfi) {
+ if (FT_IS_UINT(hfi->type)||FT_IS_INT(hfi->type)) {
+ /* If the type has been converted to FT_UINT or FT_INT in the .cnf file
+ * display the length of this octet string instead of the octetstring itself
+ */
+ if (FT_IS_UINT(hfi->type))
+ actx->created_item = proto_tree_add_uint(tree, hf_index, out_tvb, 0, val_length, val_length);
+ else
+ actx->created_item = proto_tree_add_int(tree, hf_index, out_tvb, 0, val_length, val_length);
+ proto_item_append_text(actx->created_item, plurality(val_length, " octet", " octets"));
+ } else {
+ if(out_tvb){
+ actx->created_item = proto_tree_add_item(tree, hf_index, out_tvb, 0, val_length, ENC_BIG_ENDIAN);
+ }else{
+ /* Length = 0 */
+ actx->created_item = proto_tree_add_item(tree, hf_index, tvb, val_start, val_length, ENC_BIG_ENDIAN);
+ }
+ }
+ }
+
+ if (value_tvb)
+ *value_tvb = (out_tvb) ? out_tvb : tvb_new_subset_length(tvb, val_start, val_length);
+
+ return offset;
+}
+
+guint32 dissect_per_octet_string_containing_pdu_new(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, int min_len, int max_len, gboolean has_extension, dissector_t type_cb)
+{
+ tvbuff_t *val_tvb = NULL;
+ proto_tree *subtree = tree;
+
+ offset = dissect_per_octet_string(tvb, offset, actx, tree, hf_index, min_len, max_len, has_extension, &val_tvb);
+
+ if (type_cb && val_tvb && (tvb_reported_length(val_tvb) > 0)) {
+ subtree = proto_item_add_subtree(actx->created_item, ett_per_containing);
+ type_cb(val_tvb, actx->pinfo, subtree, NULL);
+ }
+
+ return offset;
+}
+
+guint32 dissect_per_size_constrained_type(tvbuff_t *tvb, guint32 offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index, per_type_fn type_cb, const gchar *name, int min_len, int max_len, gboolean has_extension)
+{
+ asn1_stack_frame_push(actx, name);
+ asn1_param_push_integer(actx, min_len);
+ asn1_param_push_integer(actx, max_len);
+ asn1_param_push_boolean(actx, has_extension);
+
+ offset = type_cb(tvb, offset, actx, tree, hf_index);
+
+ asn1_stack_frame_pop(actx, name);
+
+ return offset;
+}
+
+gboolean get_size_constraint_from_stack(asn1_ctx_t *actx, const gchar *name, int *pmin_len, int *pmax_len, gboolean *phas_extension)
+{
+ asn1_par_t *par;
+
+ if (pmin_len) *pmin_len = NO_BOUND;
+ if (pmax_len) *pmax_len = NO_BOUND;
+ if (phas_extension) *phas_extension = FALSE;
+
+ if (!actx->stack) return FALSE;
+ if (strcmp(actx->stack->name, name)) return FALSE;
+
+ par = actx->stack->par;
+ if (!par || (par->ptype != ASN1_PAR_INTEGER)) return FALSE;
+ if (pmin_len) *pmin_len = par->value.v_integer;
+ par = par->next;
+ if (!par || (par->ptype != ASN1_PAR_INTEGER)) return FALSE;
+ if (pmax_len) *pmax_len = par->value.v_integer;
+ par = par->next;
+ if (!par || (par->ptype != ASN1_PAR_BOOLEAN)) return FALSE;
+ if (phas_extension) *phas_extension = par->value.v_boolean;
+
+ return TRUE;
+}
+
+
+/* 26 Encoding of a value of the external type */
+
+/* code generated from definition in 26.1 */
+/*
+[UNIVERSAL 8] IMPLICIT SEQUENCE {
+ direct-reference OBJECT IDENTIFIER OPTIONAL,
+ indirect-reference INTEGER OPTIONAL,
+ data-value-descriptor ObjectDescriptor OPTIONAL,
+ encoding CHOICE {
+ single-ASN1-type [0] ABSTRACT-SYNTAX.&Type,
+ octet-aligned [1] IMPLICIT OCTET STRING,
+ arbitrary [2] IMPLICIT BIT STRING
+ }
+}
+*/
+/* NOTE: This sequence type differs from that in ITU-T Rec. X.680 | ISO/IEC 8824-1 for historical reasons. */
+
+static int
+dissect_per_T_direct_reference(tvbuff_t *tvb, int offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index) {
+
+ DISSECTOR_ASSERT(actx);
+ offset = dissect_per_object_identifier_str(tvb, offset, actx, tree, hf_index, &actx->external.direct_reference);
+
+ actx->external.direct_ref_present = TRUE;
+ return offset;
+}
+
+
+
+static int
+dissect_per_T_indirect_reference(tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
+ offset = dissect_per_integer(tvb, offset, actx, tree, hf_index, &actx->external.indirect_reference);
+
+ actx->external.indirect_ref_present = TRUE;
+ return offset;
+}
+
+
+
+static int
+dissect_per_T_data_value_descriptor(tvbuff_t *tvb, int offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index) {
+ offset = dissect_per_object_descriptor(tvb, offset, actx, tree, hf_index, &actx->external.data_value_descriptor);
+
+ actx->external.data_value_descr_present = TRUE;
+ return offset;
+}
+
+
+
+static int
+dissect_per_T_single_ASN1_type(tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
+ offset = dissect_per_open_type(tvb, offset, actx, tree, actx->external.hf_index, actx->external.u.per.type_cb);
+
+ return offset;
+}
+
+
+
+static int
+dissect_per_T_octet_aligned(tvbuff_t *tvb, int offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index) {
+ offset = dissect_per_octet_string(tvb, offset, actx, tree, hf_index,
+ NO_BOUND, NO_BOUND, FALSE, &actx->external.octet_aligned);
+
+ if (actx->external.octet_aligned) {
+ if (actx->external.u.per.type_cb) {
+ actx->external.u.per.type_cb(actx->external.octet_aligned, 0, actx, tree, actx->external.hf_index);
+ } else {
+ actx->created_item = proto_tree_add_expert(tree, actx->pinfo, &ei_per_external_type, actx->external.octet_aligned, 0, -1);
+ }
+ }
+ return offset;
+}
+
+
+
+static int
+dissect_per_T_arbitrary(tvbuff_t *tvb, int offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index) {
+ offset = dissect_per_bit_string(tvb, offset, actx, tree, hf_index,
+ NO_BOUND, NO_BOUND, FALSE, NULL, 0, &actx->external.arbitrary, NULL);
+
+ if (actx->external.arbitrary) {
+ if (actx->external.u.per.type_cb) {
+ actx->external.u.per.type_cb(actx->external.arbitrary, 0, actx, tree, actx->external.hf_index);
+ } else {
+ actx->created_item = proto_tree_add_expert(tree, actx->pinfo, &ei_per_external_type, actx->external.arbitrary, 0, -1);
+ }
+ }
+ return offset;
+}
+
+
+static const value_string per_External_encoding_vals[] = {
+ { 0, "single-ASN1-type" },
+ { 1, "octet-aligned" },
+ { 2, "arbitrary" },
+ { 0, NULL }
+};
+
+static const per_choice_t External_encoding_choice[] = {
+ { 0, &hf_per_single_ASN1_type, ASN1_NO_EXTENSIONS , dissect_per_T_single_ASN1_type },
+ { 1, &hf_per_octet_aligned , ASN1_NO_EXTENSIONS , dissect_per_T_octet_aligned },
+ { 2, &hf_per_arbitrary , ASN1_NO_EXTENSIONS , dissect_per_T_arbitrary },
+ { 0, NULL, 0, NULL }
+};
+
+static int
+dissect_per_External_encoding(tvbuff_t *tvb, int offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index) {
+ // This assertion is used to remove clang's warning.
+ DISSECTOR_ASSERT(actx);
+ offset = dissect_per_choice(tvb, offset, actx, tree, hf_index,
+ ett_per_External_encoding, External_encoding_choice,
+ &actx->external.encoding);
+
+ return offset;
+}
+
+
+static const per_sequence_t External_sequence[] = {
+ { &hf_per_direct_reference, ASN1_NO_EXTENSIONS , ASN1_OPTIONAL , dissect_per_T_direct_reference },
+ { &hf_per_indirect_reference, ASN1_NO_EXTENSIONS , ASN1_OPTIONAL , dissect_per_T_indirect_reference },
+ { &hf_per_data_value_descriptor, ASN1_NO_EXTENSIONS , ASN1_OPTIONAL , dissect_per_T_data_value_descriptor },
+ { &hf_per_encoding , ASN1_NO_EXTENSIONS , ASN1_NOT_OPTIONAL, dissect_per_External_encoding },
+ { NULL, 0, 0, NULL }
+};
+
+static int
+dissect_per_External(tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
+ offset = dissect_per_sequence(tvb, offset, actx, tree, hf_index,
+ ett_per_External, External_sequence);
+
+ return offset;
+}
+
+guint32
+dissect_per_external_type(tvbuff_t *tvb _U_, guint32 offset, asn1_ctx_t *actx, proto_tree *tree _U_, int hf_index _U_, per_type_fn type_cb)
+{
+ asn1_ctx_clean_external(actx);
+ actx->external.u.per.type_cb = type_cb;
+ offset = dissect_per_External(tvb, offset, actx, tree, hf_index);
+
+ asn1_ctx_clean_external(actx);
+ return offset;
+}
+
+/*
+ * Calls the callback defined with register_per_oid_dissector() if found.
+ * Offset is in bits.
+ */
+
+int
+call_per_oid_callback(const char *oid, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, asn1_ctx_t *actx, int hf_index)
+{
+ guint32 type_length, end_offset, start_offset;
+ tvbuff_t *val_tvb = NULL;
+
+ start_offset = offset;
+ offset = dissect_per_length_determinant(tvb, offset, actx, tree, hf_per_open_type_length, &type_length, NULL);
+ if(type_length == 0){
+ dissect_per_not_decoded_yet(tree, actx->pinfo, tvb, "unexpected length");
+ }
+ if (actx->aligned) BYTE_ALIGN_OFFSET(offset);
+ end_offset = offset + type_length;
+
+
+ /* length in bits */
+ val_tvb = tvb_new_octet_aligned(tvb, offset, type_length * 8);
+ if ((offset & 7) != 0) {
+ add_new_data_source(actx->pinfo, val_tvb, "Unaligned OCTET STRING");
+ }
+
+ if (oid == NULL ||
+ (dissector_try_string(per_oid_dissector_table, oid, val_tvb, pinfo, tree, actx)) == 0)
+ {
+ proto_tree_add_expert(tree, pinfo, &ei_per_oid_not_implemented, val_tvb, 0, -1);
+ dissect_per_open_type(tvb, start_offset, actx, tree, hf_index, NULL);
+ }
+
+ return end_offset;
+}
+
+void
+register_per_oid_dissector(const char *oid, dissector_t dissector, int proto, const char *name)
+{
+ dissector_handle_t dissector_handle;
+
+ /* FIXME: This would be better as register_dissector()
+ * so the dissector could be referenced by name
+ * from the command line, Lua, etc.
+ * But can we blindly trust name to be a unique dissector name,
+ * or should we prefix "per." or something?
+ */
+ dissector_handle = create_dissector_handle(dissector, proto);
+ dissector_add_string("per.oid", oid, dissector_handle);
+ oid_add_from_string(name, oid);
+}
+
+
+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_index,
+ { "Choice Index", "per.choice_index", FT_UINT32, BASE_DEC,
+ NULL, 0, "Which index of the Choice within extension root is encoded", HFILL }},
+ { &hf_per_choice_extension_index,
+ { "Choice Extension Index", "per.choice_extension_index", FT_UINT32, BASE_DEC,
+ NULL, 0, "Which index of the Choice within extension addition is encoded", HFILL }},
+ { &hf_per_enum_index,
+ { "Enumerated Index", "per.enum_index", FT_UINT32, BASE_DEC,
+ NULL, 0, "Which index of the Enumerated within extension root is encoded", HFILL }},
+ { &hf_per_enum_extension_index,
+ { "Enumerated Extension Index", "per.enum_extension_index", FT_UINT32, BASE_DEC,
+ NULL, 0, "Which index of the Enumerated within extension addition 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,
+ NULL, 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,
+ NULL, 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 Identifier 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_real_length,
+ { "Real Length", "per.real_length", FT_UINT32, BASE_DEC,
+ NULL, 0, "Length of an real 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 }},
+ { &hf_per_normally_small_nonnegative_whole_number_length,
+ { "Normally Small Non-negative Whole Number Length", "per.normally_small_nonnegative_whole_number_length", FT_UINT32, BASE_DEC,
+ NULL, 0, "Number of bytes in the Normally Small Non-negative Whole Number", HFILL }},
+ { &hf_per_const_int_len,
+ { "Constrained Integer Length", "per.const_int_len", FT_UINT32, BASE_DEC,
+ NULL, 0, "Number of bytes in the Constrained Integer", HFILL }},
+ { &hf_per_direct_reference,
+ { "direct-reference", "per.direct_reference",
+ FT_OID, BASE_NONE, NULL, 0,
+ "per.T_direct_reference", HFILL }},
+ { &hf_per_indirect_reference,
+ { "indirect-reference", "per.indirect_reference",
+ FT_INT32, BASE_DEC, NULL, 0,
+ "per.T_indirect_reference", HFILL }},
+ { &hf_per_data_value_descriptor,
+ { "data-value-descriptor", "per.data_value_descriptor",
+ FT_STRING, BASE_NONE, NULL, 0,
+ "per.T_data_value_descriptor", HFILL }},
+ { &hf_per_encoding,
+ { "encoding", "per.encoding",
+ FT_UINT32, BASE_DEC, VALS(per_External_encoding_vals), 0,
+ "per.External_encoding", HFILL }},
+ { &hf_per_single_ASN1_type,
+ { "single-ASN1-type", "per.single_ASN1_type",
+ FT_NONE, BASE_NONE, NULL, 0,
+ "per.T_single_ASN1_type", HFILL }},
+ { &hf_per_octet_aligned,
+ { "octet-aligned", "per.octet_aligned",
+ FT_BYTES, BASE_NONE, NULL, 0,
+ "per.T_octet_aligned", HFILL }},
+ { &hf_per_arbitrary,
+ { "arbitrary", "per.arbitrary",
+ FT_BYTES, BASE_NONE, NULL, 0,
+ "per.T_arbitrary", HFILL }},
+ { &hf_per_integer_length,
+ { "integer length", "per.integer_length",
+ FT_UINT32, BASE_DEC, NULL, 0,
+ NULL, HFILL }},
+#if 0
+ { &hf_per_debug_pos,
+ { "Current bit offset", "per.debug_pos",
+ FT_UINT32, BASE_DEC, NULL, 0,
+ NULL, HFILL }},
+#endif
+ { &hf_per_internal_range,
+ { "Range", "per.internal.range",
+ FT_UINT64, BASE_DEC, NULL, 0,
+ NULL, HFILL }},
+ { &hf_per_internal_num_bits,
+ { "Bitfield length", "per.internal.num_bits",
+ FT_UINT32, BASE_DEC, NULL, 0,
+ NULL, HFILL }},
+ { &hf_per_internal_min,
+ { "Min", "per.internal.min",
+ FT_UINT32, BASE_DEC, NULL, 0,
+ NULL, HFILL }},
+ { &hf_per_internal_value,
+ { "Bits", "per.internal.value",
+ FT_UINT64, BASE_DEC, NULL, 0,
+ NULL, HFILL }},
+ { &hf_per_encoding_boiler_plate,
+ { "PER encoded protocol, to see PER internal fields set protocol PER preferences", "per.encoding_boiler_plate",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL } },
+
+ };
+
+ static gint *ett[] = {
+ &ett_per_open_type,
+ &ett_per_containing,
+ &ett_per_sequence_of_item,
+ &ett_per_External,
+ &ett_per_External_encoding,
+ &ett_per_named_bits,
+ };
+ static ei_register_info ei[] = {
+ { &ei_per_size_constraint_value,
+ { "per.size_constraint.value", PI_PROTOCOL, PI_WARN, "Size constraint: value too big", EXPFILL }},
+ { &ei_per_size_constraint_too_few,
+ { "per.size_constraint.too_few", PI_PROTOCOL, PI_WARN, "Size constraint: too few items", EXPFILL }},
+ { &ei_per_size_constraint_too_many,
+ { "per.size_constraint.too_many", PI_PROTOCOL, PI_WARN, "Size constraint: too many items", EXPFILL }},
+ { &ei_per_choice_extension_unknown,
+ { "per.choice_extension_unknown", PI_UNDECODED, PI_NOTE, "unknown choice extension", EXPFILL }},
+ { &ei_per_sequence_extension_unknown,
+ { "per.sequence_extension_unknown", PI_UNDECODED, PI_NOTE, "unknown sequence extension", EXPFILL }},
+ { &ei_per_encoding_error,
+ { "per.encoding_error", PI_MALFORMED, PI_WARN, "Encoding error", EXPFILL }},
+ { &ei_per_oid_not_implemented,
+ { "per.error.oid_not_implemented", PI_UNDECODED, PI_WARN, "PER: Dissector for OID not implemented. Contact Wireshark developers if you want this supported", EXPFILL }},
+ { &ei_per_undecoded,
+ { "per.error.undecoded", PI_UNDECODED, PI_WARN, "PER: Something unknown here", EXPFILL }},
+ { &ei_per_field_not_integer,
+ { "per.field_not_integer", PI_PROTOCOL, PI_ERROR, "Field is not an integer", EXPFILL }},
+ { &ei_per_external_type,
+ { "per.external_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown EXTERNAL Type", EXPFILL }},
+ { &ei_per_open_type,
+ { "per.open_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown Open Type", EXPFILL }},
+ { &ei_per_open_type_len,
+ { "per.open_type.len", PI_PROTOCOL, PI_ERROR, "Open Type length > available data(tvb)", EXPFILL }}
+ };
+
+ module_t *per_module;
+ expert_module_t* expert_per;
+
+ 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));
+ expert_per = expert_register_protocol(proto_per);
+ expert_register_field_array(expert_per, ei, array_length(ei));
+
+ 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);
+
+ per_oid_dissector_table = register_dissector_table("per.oid", "PER OID", proto_per, FT_STRING, STRING_CASE_SENSITIVE);
+
+
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */