Commit 03d18778 authored by Cedric Roux's avatar Cedric Roux

PER: fix encoding and decoding of OPENTYPE with size constraints

Constraints have to be used. If not the encoding or decoding may be
wrong.

For example RRC-Version of 3GPP 38.473 contains an extension with a
fixed size constraint (so the size is not encoded).

Here is a small ASN.1 file extracted from 38.473 to illustrate the
problem.

----
F1AP-PDU-Descriptions  {
itu-t (0) identified-organization (4) etsi (0) mobileDomain (0)
ngran-access (22) modules (3) f1ap (3) version1 (1) f1ap-PDU-Descriptions (0)}

DEFINITIONS AUTOMATIC TAGS ::=

BEGIN

ProtocolExtensionID     ::= INTEGER (0..65535)
Criticality             ::= ENUMERATED { reject, ignore, notify }
Presence                ::= ENUMERATED { optional, conditional, mandatory }
maxProtocolExtensions                                   INTEGER ::= 65535
id-latest-RRC-Version-Enhanced                                          ProtocolIE-ID ::= 199

ProtocolIE-ID           ::= INTEGER (0..65535)

F1AP-PROTOCOL-EXTENSION ::= CLASS {
        &id                             ProtocolExtensionID                     UNIQUE,
        &criticality    Criticality,
        &Extension,
        &presence               Presence
}
WITH SYNTAX {
        ID                              &id
        CRITICALITY             &criticality
        EXTENSION               &Extension
        PRESENCE                &presence
}

ProtocolExtensionContainer {F1AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::=
        SEQUENCE (SIZE (1..maxProtocolExtensions)) OF
        ProtocolExtensionField {{ExtensionSetParam}}

ProtocolExtensionField {F1AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::= SEQUENCE {
        id                                      F1AP-PROTOCOL-EXTENSION.&id                             ({ExtensionSetParam}),
        criticality                     F1AP-PROTOCOL-EXTENSION.&criticality    ({ExtensionSetParam}{@id}),
        extensionValue          F1AP-PROTOCOL-EXTENSION.&Extension              ({ExtensionSetParam}{@id})
}

RRC-Version ::= SEQUENCE        {
        latest-RRC-Version                      BIT STRING (SIZE(3)),
        iE-Extensions                           ProtocolExtensionContainer { { RRC-Version-ExtIEs } }   OPTIONAL}

RRC-Version-ExtIEs      F1AP-PROTOCOL-EXTENSION ::= {
        {ID id-latest-RRC-Version-Enhanced              CRITICALITY ignore EXTENSION OCTET STRING (SIZE(3))             PRESENCE optional },
        ...
}

END
----

And a small program to test:

----

int main(void)
{
  RRC_Version_t version;
  unsigned char x;
  char out[1024];

  unsigned char ver3[3] = { 0x11, 0x05, 0x01 };

  version.latest_RRC_Version.buf = &x;
  version.latest_RRC_Version.buf[0] = 0xe0;
  version.latest_RRC_Version.size = 1;
  version.latest_RRC_Version.bits_unused = 5;

  ProtocolExtensionContainer_32P0_t ext = { 0 };

  RRC_Version_ExtIEs_t ie;
  ie.id = ProtocolIE_ID_id_latest_RRC_Version_Enhanced;
  ie.criticality = Criticality_ignore;
  ie.extensionValue.present = RRC_Version_ExtIEs__extensionValue_PR_OCTET_STRING_SIZE_3_;
  ie.extensionValue.choice.OCTET_STRING_SIZE_3_.buf = ver3;
  ie.extensionValue.choice.OCTET_STRING_SIZE_3_.size = 3;
  ASN_SEQUENCE_ADD(&ext.list, &ie);

  version.iE_Extensions = (void*)&ext;

  fflush(stdout);
  fflush(stderr);
  xer_fprint(stdout, &asn_DEF_RRC_Version, &version);
  fflush(stdout);
  fflush(stderr);

  void *dec;

  asn_enc_rval_t enc_ret = aper_encode_to_buffer(&asn_DEF_RRC_Version, NULL, &version, out, sizeof(out));
  if (enc_ret.encoded <= 0) printf("encode failed\n"); else printf("encode ok\n");
  printf("encoded aper[%ld]:", (enc_ret.encoded+7)/8);
  for (int i = 0; i < (enc_ret.encoded+7) / 8; i++) printf(" %2.2x", (unsigned char)out[i]);
  printf("\n");

  dec = NULL;
  asn_dec_rval_t dec_ret = asn_decode(NULL, ATS_ALIGNED_BASIC_PER, &asn_DEF_RRC_Version, &dec, out, (enc_ret.encoded+7) / 8);
  if (dec_ret.code) printf("decode failed\n"); else printf("decode ok\n");
  fflush(stdout);
  fflush(stderr);
  xer_fprint(stdout, &asn_DEF_RRC_Version, dec);
  fflush(stdout);
  fflush(stderr);

  enc_ret = uper_encode_to_buffer(&asn_DEF_RRC_Version, NULL, &version, out, sizeof(out));
  if (enc_ret.encoded <= 0) printf("encode failed\n"); else printf("encode ok\n");
  printf("encoded uper[%ld]:", (enc_ret.encoded+7)/8);
  for (int i = 0; i < (enc_ret.encoded+7) / 8; i++) printf(" %2.2x", (unsigned char)out[i]);
  printf("\n");

  dec = NULL;
  dec_ret = asn_decode(NULL, ATS_UNALIGNED_BASIC_PER, &asn_DEF_RRC_Version, &dec, out, (enc_ret.encoded+7) / 8);
  if (dec_ret.code) printf("decode failed\n"); else printf("decode ok\n");
  fflush(stdout);
  fflush(stderr);
  xer_fprint(stdout, &asn_DEF_RRC_Version, dec);
  fflush(stdout);
  fflush(stderr);

  return 0;
}
----

It encodes as following:

APER: f0 00 00 00 c7 40 04 03 11 05 01
UPER: f0 00 00 0c 74 10 0c 44 14 04

Instead of:

APER: f0 00 00 00 c7 40 03 11 05 01
UPER: f0 00 00 0c 74 0c 44 14 04

(Basically since the size is fixed, it shall not be encoded.)

Note: this commit does not solve all cases. For example the constraint:

    SIZE(3..1000000)

is not managed properly. (Solved in another commit.)
parent bbde80f6
...@@ -53,7 +53,8 @@ OPEN_TYPE_aper_get(const asn_codec_ctx_t *opt_codec_ctx, ...@@ -53,7 +53,8 @@ OPEN_TYPE_aper_get(const asn_codec_ctx_t *opt_codec_ctx,
(char *)*memb_ptr2 (char *)*memb_ptr2
+ elm->type->elements[selected.presence_index - 1].memb_offset; + elm->type->elements[selected.presence_index - 1].memb_offset;
rv = aper_open_type_get(opt_codec_ctx, selected.type_descriptor, NULL, rv = aper_open_type_get(opt_codec_ctx, selected.type_descriptor,
elm->type->elements[selected.presence_index - 1].encoding_constraints.per_constraints,
&inner_value, pd); &inner_value, pd);
switch(rv.code) { switch(rv.code) {
case RC_OK: case RC_OK:
...@@ -110,7 +111,7 @@ OPEN_TYPE_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -110,7 +111,7 @@ OPEN_TYPE_encode_aper(const asn_TYPE_descriptor_t *td,
memb_ptr = (const char *)sptr + elm->memb_offset; memb_ptr = (const char *)sptr + elm->memb_offset;
} }
if(aper_open_type_put(elm->type, NULL, memb_ptr, po) < 0) { if(aper_open_type_put(elm->type, elm->encoding_constraints.per_constraints, memb_ptr, po) < 0) {
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
} }
......
...@@ -53,7 +53,8 @@ OPEN_TYPE_uper_get(const asn_codec_ctx_t *opt_codec_ctx, ...@@ -53,7 +53,8 @@ OPEN_TYPE_uper_get(const asn_codec_ctx_t *opt_codec_ctx,
(char *)*memb_ptr2 (char *)*memb_ptr2
+ elm->type->elements[selected.presence_index - 1].memb_offset; + elm->type->elements[selected.presence_index - 1].memb_offset;
rv = uper_open_type_get(opt_codec_ctx, selected.type_descriptor, NULL, rv = uper_open_type_get(opt_codec_ctx, selected.type_descriptor,
elm->type->elements[selected.presence_index - 1].encoding_constraints.per_constraints,
&inner_value, pd); &inner_value, pd);
switch(rv.code) { switch(rv.code) {
case RC_OK: case RC_OK:
...@@ -110,7 +111,9 @@ OPEN_TYPE_encode_uper(const asn_TYPE_descriptor_t *td, ...@@ -110,7 +111,9 @@ OPEN_TYPE_encode_uper(const asn_TYPE_descriptor_t *td,
memb_ptr = (const char *)sptr + elm->memb_offset; memb_ptr = (const char *)sptr + elm->memb_offset;
} }
if(uper_open_type_put(elm->type, NULL, memb_ptr, po) < 0) { if(uper_open_type_put(elm->type,
elm->encoding_constraints.per_constraints,
memb_ptr, po) < 0) {
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment