Commit ee6458b2 authored by Cedric Roux's avatar Cedric Roux

APER: fix non negative normally small whole numbers

aper_put_nsnnwn() and aper_get_nsnnwn() were wrong. All the places
where they were used are modified, if needed.

The functions aper_get_constrained_whole_number() and
aper_put_constrained_whole_number() are introduced.
They don't cover all cases, very big numbers are not supported.

The sample ASN.1 file and C program at the end show some issues.

For sequence-of, APER decoding fails and the XER output after
APER encode/decode is:

-----------
xer after encode/decode:
<ListOfInt>
    <INTEGER>1</INTEGER>
    <INTEGER>259</INTEGER>
</ListOfInt>
-----------

instead of:

-----------
xer after encode/decode:
<ListOfInt>
    <INTEGER>1</INTEGER>
    <INTEGER>2</INTEGER>
    <INTEGER>3</INTEGER>
</ListOfInt>
-----------

For the enum test, we have:

-----------
aper ue lost[1]: d4
-----------

instead of:

-----------
aper ue lost[1]: 95
-----------

And APER decoding fails.

For the choice test, we see:

-----------
aper snssai[3]: 80 01 00
-----------

instead of:

-----------
aper snssai[3]: 84 01 00
-----------

And XER after encode/decode is wrong.

To generate C code from the ASN.1 file, asn1c is run as:
asn1c -pdu=all -fno-include-deps -fcompound-names -gen-UPER -no-gen-BER -no-gen-JER -no-gen-OER -gen-APER -no-gen-example

ASN.1 file:

-----------
Test DEFINITIONS AUTOMATIC TAGS ::=

BEGIN

TestCond-Type ::= CHOICE{
        gBR                                     ENUMERATED {true, ...},
        aMBR                            ENUMERATED {true, ...},
        isStat                          ENUMERATED {true, ...},
        isCatM                          ENUMERATED {true, ...},
        rSRP                            ENUMERATED {true, ...},
        rSRQ                            ENUMERATED {true, ...},
        ...,
        ul-rSRP                         ENUMERATED {true, ...},
        cQI                                     ENUMERATED {true, ...},
        fiveQI                          ENUMERATED {true, ...},
        qCI                                     ENUMERATED {true, ...},
        sNSSAI                          ENUMERATED {true, ...}
}

CauseRadioNetwork ::= ENUMERATED {
        handover-desirable-for-radio-reasons,
        time-critical-handover,
        resource-optimisation-handover,
        reduce-load-in-serving-cell,
        partial-handover,
        unknown-new-eNB-UE-X2AP-ID,
        unknown-old-eNB-UE-X2AP-ID,
        unknown-pair-of-UE-X2AP-ID,
        ho-target-not-allowed,
        tx2relocoverall-expiry,
        trelocprep-expiry,
        cell-not-available,
        no-radio-resources-available-in-target-cell,
        invalid-MME-GroupID,
        unknown-MME-Code,
        encryption-and-or-integrity-protection-algorithms-not-supported,
        reportCharacteristicsEmpty,
        noReportPeriodicity,
        existingMeasurementID,
        unknown-eNB-Measurement-ID,
        measurement-temporarily-not-available,
        unspecified,
        ...,
        load-balancing,
        handover-optimisation,
        value-out-of-allowed-range,
        multiple-E-RAB-ID-instances,
        switch-off-ongoing,
        not-supported-QCI-value,
        measurement-not-supported-for-the-object,
        tDCoverall-expiry,
        tDCprep-expiry,
        action-desirable-for-radio-reasons,
        reduce-load,
        resource-optimisation,
        time-critical-action,
        target-not-allowed,
        no-radio-resources-available,
        invalid-QoS-combination,
        encryption-algorithms-not-supported,
        procedure-cancelled,
        rRM-purpose,
        improve-user-bit-rate,
        user-inactivity,
        radio-connection-with-UE-lost,
        failure-in-the-radio-interface-procedure,
        bearer-option-not-supported,
        mCG-Mobility,
        sCG-Mobility,
        count-reaches-max-value,
        unknown-old-en-gNB-UE-X2AP-ID,
        pDCP-Overload
}

ListOfInt ::= SEQUENCE (SIZE (3)) OF INTEGER

END
-----------

C program:

-----------

void test(void *v, int is_aper, char *name, void *t)
{
  unsigned char b[128];
  asn_enc_rval_t r = asn_encode_to_buffer(NULL,
                       is_aper ? ATS_ALIGNED_BASIC_PER
                               : ATS_UNALIGNED_BASIC_PER,
                       t, v, b, sizeof(b));
  if (r.encoded <= 0) printf("error\n"); else printf("ok\n");
  printf("%s %s[%ld]:", is_aper ? "aper" : "uper", name, r.encoded);
  for (int i = 0; i < r.encoded; i++) printf(" %2.2x", b[i]);
  printf("\n");

  void *ret = NULL;
  asn_dec_rval_t d = asn_decode(NULL,
                       is_aper ? ATS_ALIGNED_BASIC_PER
                               : ATS_UNALIGNED_BASIC_PER,
                       t, &ret, b, r.encoded);
  if (d.consumed != r.encoded) printf("error\n"); else printf("ok\n");
  printf("xer of input:\n");
  xer_fprint(stdout, t, v);
  printf("xer after encode/decode:\n");
  xer_fprint(stdout, t, ret);
}

int main(void)
{
  /* test sequence of */
  ListOfInt_t l = { 0 };
  long val[3] = { 1, 2, 3 };
  asn_sequence_add(&l.list, &val[0]);
  asn_sequence_add(&l.list, &val[1]);
  asn_sequence_add(&l.list, &val[2]);
  test(&l, 1, "sequence-of (size 3)", &asn_DEF_ListOfInt);
  test(&l, 0, "sequence-of (size 3)", &asn_DEF_ListOfInt);

  /* test enum */
  CauseRadioNetwork_t v;
  v = CauseRadioNetwork_radio_connection_with_UE_lost;

  test(&v, 1, "ue lost", &asn_DEF_CauseRadioNetwork);
  test(&v, 0, "ue lost", &asn_DEF_CauseRadioNetwork);

  v = CauseRadioNetwork_cell_not_available;

  test(&v, 1, "no cell", &asn_DEF_CauseRadioNetwork);
  test(&v, 0, "no cell", &asn_DEF_CauseRadioNetwork);

  /* test choice */
  TestCond_Type_t w;
  w.present = TestCond_Type_PR_sNSSAI;
  w.choice.sNSSAI = TestCond_Type__sNSSAI_true;

  test(&w, 1, "snssai", &asn_DEF_TestCond_Type);
  test(&w, 0, "snssai", &asn_DEF_TestCond_Type);

  w.present = TestCond_Type_PR_gBR;
  w.choice.sNSSAI = TestCond_Type__gBR_true;

  test(&w, 1, "gbr", &asn_DEF_TestCond_Type);
  test(&w, 0, "gbr", &asn_DEF_TestCond_Type);

  return 0;
}
-----------
parent 10a060e3
......@@ -64,7 +64,7 @@ NativeEnumerated_decode_aper(const asn_codec_ctx_t *opt_codec_ctx,
*/
/* XXX handle indefinite index length > 64k */
value = aper_get_nsnnwn(pd, 65537);
value = aper_get_nsnnwn(pd);
if(value < 0) ASN__DECODE_STARVED;
value += specs->extension - 1;
//if(value >= specs->map_count)
......@@ -148,9 +148,7 @@ NativeEnumerated_encode_aper(const asn_TYPE_descriptor_t *td,
ASN_DEBUG("value = %ld, ext = %d, inext = %d, res = %ld",
value, specs->extension, inext,
value - (inext ? (specs->extension - 1) : 0));
if(aper_put_nsnnwn(po,
ct->upper_bound - ct->lower_bound + 1,
value - (inext ? (specs->extension - 1) : 0)))
if(aper_put_nsnnwn(po, value - (inext ? (specs->extension - 1) : 0)))
ASN__ENCODE_FAILED;
ASN__ENCODED_OK(er);
......
......@@ -179,7 +179,6 @@ OCTET_STRING_decode_aper(const asn_codec_ctx_t *opt_codec_ctx,
raw_len = aper_get_length(pd, csiz->lower_bound, csiz->upper_bound,
csiz->effective_bits, &repeat);
if(raw_len < 0) RETURN(RC_WMORE);
raw_len += csiz->lower_bound;
ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",
(long)csiz->effective_bits, (long)raw_len,
......
......@@ -25,8 +25,7 @@ aper_get_length(asn_per_data_t *pd, ssize_t lb, ssize_t ub,
*repeat = 0;
if (constrained && ub < 65536) {
int range = ub - lb + 1;
return aper_get_nsnnwn(pd, range);
return aper_get_constrained_whole_number(pd, lb, ub);
}
if (aper_get_align(pd) < 0)
......@@ -70,55 +69,117 @@ aper_get_nslength(asn_per_data_t *pd) {
}
ssize_t
aper_get_nsnnwn(asn_per_data_t *pd, int range) {
ssize_t value;
int bytes = 0;
aper_get_nsnnwn(asn_per_data_t *pd) {
int b;
int length;
ASN_DEBUG("getting nsnnwn with range %d", range);
ASN_DEBUG("getting nsnnwn");
if(range <= 255) {
int i;
b = per_get_few_bits(pd, 1);
if (b == -1)
return -1;
if (range < 0) return -1;
/* 1 -> 8 bits */
for (i = 1; i <= 8; i++) {
int upper = 1 << i;
if (upper >= range)
break;
}
value = per_get_few_bits(pd, i);
return value;
} else if (range == 256){
/* 1 byte */
bytes = 1;
} else if (range <= 65536) {
/* 2 bytes */
bytes = 2;
} else {
//return -1;
int length;
/* X.691 2002 10.6.1 */
if (b == 0)
return per_get_few_bits(pd, 6);
if (aper_get_align(pd) < 0)
return -1;
/* handle indefinite range */
length = per_get_few_bits(pd, 1);
if (length == 0)
return per_get_few_bits(pd, 6);
/* X.691 2002 10.6.2 */
/* X.691 2002 10.9.3.5 */
b = per_get_few_bits(pd, 1);
if (b == -1)
return -1;
if (b == 1) {
/* other 10.9.3.x cases not handled, it's doubtful we reach them in practice */
ASN_DEBUG("todo: X.691 2002 10.9.3.x");
return -1;
}
/* X.691 2002 10.9.3.6 */
length = per_get_few_bits(pd, 7);
if (length > 4) {
/* todo */
ASN_DEBUG("todo: X.691 2002 10.9.3.6 for length > 4");
return -1;
}
ASN_DEBUG("length %d\n", length);
/* todo: 0xffffffff will be seen as -1 and will lead to decoding failure */
return per_get_few_bits(pd, length * 8);
}
if (aper_get_align(pd) < 0)
/* X.691 2002 10.5 - Decoding of a constrained whole number */
long
aper_get_constrained_whole_number(asn_per_data_t *pd, long lb, long ub) {
assert(ub >= lb);
long range = ub - lb + 1;
int range_len;
int value_len;
long value;
ASN_DEBUG("aper get constrained_whole_number with lb %ld and ub %ld", lb, ub);
/* X.691 2002 10.5.4 */
if (range == 1)
return lb;
/* X.691 2002 10.5.7.1 - The bit-field case. */
if (range <= 255) {
int bitfield_size = 8;
for (bitfield_size = 8; bitfield_size >= 2; bitfield_size--)
if ((range - 1) & (1 << (bitfield_size-1)))
break;
value = per_get_few_bits(pd, bitfield_size);
if (value < 0 || value >= range)
return -1;
return value + lb;
}
length = per_get_few_bits(pd, 8);
/* the length is not likely to be that big */
if (length > 4)
/* X.691 2002 10.5.7.2 - The one-octet case. */
if (range == 256) {
if (aper_get_align(pd))
return -1;
value = 0;
if (per_get_many_bits(pd, (uint8_t *)&value, 0, length * 8) < 0)
value = per_get_few_bits(pd, 8);
if (value < 0 || value >= range)
return -1;
return value;
return value + lb;
}
if (aper_get_align(pd) < 0)
/* X.691 2002 10.5.7.3 - The two-octet case. */
if (range <= 65536) {
if (aper_get_align(pd))
return -1;
value = per_get_few_bits(pd, 16);
if (value < 0 || value >= range)
return -1;
return value + lb;
}
/* X.691 2002 10.5.7.4 - The indefinite length case. */
/* since we limit input to be 'long' we don't handle all numbers */
/* and so length determinant is retrieved as X.691 2002 10.9.3.3 */
/* number of bytes to store the range */
for (range_len = 3; ; range_len++) {
long bits = ((long)1) << (8 * range_len);
if (range - 1 < bits)
break;
}
value_len = aper_get_constrained_whole_number(pd, 1, range_len);
if (value_len == -1)
return -1;
if (value_len > 4) {
ASN_DEBUG("todo: aper_get_constrained_whole_number: value_len > 4");
return -1;
}
if (aper_get_align(pd))
return -1;
value = per_get_few_bits(pd, value_len * 8);
if (value < 0 || value >= range)
return -1;
value = per_get_few_bits(pd, 8 * bytes);
return value;
return value + lb;
}
int aper_put_align(asn_per_outp_t *po) {
......@@ -142,11 +203,9 @@ aper_put_length(asn_per_outp_t *po, ssize_t lb, ssize_t ub, size_t n, int *need_
ASN_DEBUG("APER put length %zu with range (%zd..%zd)", n, lb, ub);
/* 11.9 X.691 Note 2 */
if (constrained && ub < 65536) {
int range = ub - lb + 1;
return aper_put_nsnnwn(po, range, n) ? -1 : (ssize_t)n;
}
/* X.691 2002 10.9.3.3 */
if (constrained && ub < 65536)
return aper_put_constrained_whole_number(po, lb, ub, n + lb) ? -1 : (ssize_t)n;
if (aper_put_align(po) < 0)
return -1;
......@@ -189,51 +248,113 @@ aper_put_nslength(asn_per_outp_t *po, size_t length) {
}
int
aper_put_nsnnwn(asn_per_outp_t *po, int range, int number) {
int bytes;
aper_put_nsnnwn(asn_per_outp_t *po, int number) {
int len;
ASN_DEBUG("aper put nsnnwn %d", number);
if (number <= 63) {
if (per_put_few_bits(po, 0, 1))
return -1;
return per_put_few_bits(po, number, 6);
}
ASN_DEBUG("aper put nsnnwn %d with range %d", number, range);
/* 10.5.7.1 X.691 */
if(range < 0) {
if (per_put_few_bits(po, 1, 1))
return -1;
if (number < 256) {
len = 1;
} else if (number < 65536) {
len = 2;
} else { /* number > 64K */
int i;
for (i = 1; ; i++) {
for (i = 3; ; i++) {
int bits = 1 << (8 * i);
if (number <= bits)
if (number < bits)
break;
}
bytes = i;
assert(i <= 4);
len = i;
}
if(range <= 255) {
int i;
for (i = 1; i <= 8; i++) {
int bits = 1 << i;
if (range <= bits)
break;
}
return per_put_few_bits(po, number, i);
} else if(range == 256) {
if (number >= range)
if (aper_put_align(po) < 0)
return -1;
/* put the length which is a non-constrained whole number */
if (len <= 127) {
if(per_put_few_bits(po, 0, 1))
return -1;
bytes = 1;
} else if(range <= 65536) {
if (number >= range)
if(per_put_few_bits(po, len, 7))
return -1;
bytes = 2;
} else { /* Ranges > 64K */
int i;
for (i = 1; ; i++) {
int bits = 1 << (8 * i);
if (range <= bits)
break;
}
assert(i <= 4);
bytes = i;
} else {
/* todo but not big problem, it's very doubtful that the
* number of bytes to encode 'number' will be > 127
*/
return -1;
}
if(aper_put_align(po) < 0) /* Aligning on octet */
return -1;
/* if(per_put_few_bits(po, bytes, 8))
return per_put_few_bits(po, number, 8 * len);
}
/* X.691 2002 10.5 - Encoding of a constrained whole number */
int
aper_put_constrained_whole_number(asn_per_outp_t *po, long lb, long ub, long number) {
assert(ub >= lb);
long range = ub - lb + 1;
long value = number - lb;
int range_len;
int value_len;
ASN_DEBUG("aper put constrained_whole_number %ld with lb %ld and ub %ld", number, lb, ub);
if (number < lb || number > ub)
return -1;
/* X.691 2002 10.5.4 */
if (range == 1)
return 0;
/* X.691 2002 10.5.7.1 - The bit-field case. */
if (range <= 255) {
int bitfield_size = 8;
for (bitfield_size = 8; bitfield_size >= 2; bitfield_size--)
if ((range - 1) & (1 << (bitfield_size-1)))
break;
return per_put_few_bits(po, value, bitfield_size);
}
/* X.691 2002 10.5.7.2 - The one-octet case. */
if (range == 256) {
if (aper_put_align(po))
return -1;
return per_put_few_bits(po, value, 8);
}
/* X.691 2002 10.5.7.3 - The two-octet case. */
if (range <= 65536) {
if (aper_put_align(po))
return -1;
return per_put_few_bits(po, value, 16);
}
/* X.691 2002 10.5.7.4 - The indefinite length case. */
/* since we limit input to be 'long' we don't handle all numbers */
/* and so length determinant is stored as X.691 2002 10.9.3.3 */
/* number of bytes to store the range */
for (range_len = 3; ; range_len++) {
int bits = 1 << (8 * range_len);
if (range - 1 < bits)
break;
}
/* number of bytes to store the value */
for (value_len = 1; ; value_len++) {
long bits = ((long)1) << (8 * value_len);
if (value < bits)
break;
}
if (aper_put_constrained_whole_number(po, 1, range_len, value_len))
return -1;
if (aper_put_align(po))
return -1;
*/
return per_put_few_bits(po, number, 8 * bytes);
return per_put_few_bits(po, value, value_len * 8);
}
......@@ -27,7 +27,12 @@ ssize_t aper_get_nslength(asn_per_data_t *pd);
/*
* Get the normally small non-negative whole number.
*/
ssize_t aper_get_nsnnwn(asn_per_data_t *pd, int range);
ssize_t aper_get_nsnnwn(asn_per_data_t *pd);
/*
* Get the constrained whole number.
*/
long aper_get_constrained_whole_number(asn_per_data_t *po, long lb, long ub);
/*
* X.691 (08/2015) #11.9 "General rules for encoding a length determinant"
......@@ -54,7 +59,12 @@ int aper_put_nslength(asn_per_outp_t *po, size_t length);
/*
* Put the normally small non-negative whole number.
*/
int aper_put_nsnnwn(asn_per_outp_t *po, int range, int number);
int aper_put_nsnnwn(asn_per_outp_t *po, int number);
/*
* Put the constrained whole number.
*/
int aper_put_constrained_whole_number(asn_per_outp_t *po, long lb, long ub, long number);
#ifdef __cplusplus
}
......
......@@ -56,7 +56,7 @@ CHOICE_decode_aper(const asn_codec_ctx_t *opt_codec_ctx,
ASN__DECODE_FAILED;
if(specs && specs->tag2el_count > specs->ext_start) {
value = aper_get_nsnnwn(pd, specs->tag2el_count - specs->ext_start); /* extension elements range */
value = aper_get_nsnnwn(pd); /* extension elements range */
if(value < 0) ASN__DECODE_STARVED;
value += specs->ext_start;
if((unsigned)value >= td->elements_count)
......@@ -168,7 +168,7 @@ CHOICE_encode_aper(const asn_TYPE_descriptor_t *td,
asn_enc_rval_t rval = {0,0,0};
if(specs->ext_start == -1)
ASN__ENCODE_FAILED;
if(aper_put_nsnnwn(po, ct ? ct->range_bits : 0, present - specs->ext_start))
if(aper_put_nsnnwn(po, present - specs->ext_start))
ASN__ENCODE_FAILED;
if(aper_open_type_put(elm->type, elm->encoding_constraints.per_constraints,
memb_ptr, po))
......
......@@ -129,13 +129,12 @@ SET_OF_decode_aper(const asn_codec_ctx_t *opt_codec_ctx,
if(value) ct = 0; /* Not restricted! */
}
if(ct && ct->effective_bits >= 0) {
if(ct && ct->upper_bound >= 1 && ct->upper_bound <= 65535
&& ct->upper_bound == ct->lower_bound) {
/* X.691, #19.5: No length determinant */
nelems = aper_get_nsnnwn(pd, ct->upper_bound - ct->lower_bound + 1);
ASN_DEBUG("Preparing to fetch %ld+%lld elements from %s",
(long)nelems, (long long int)ct->lower_bound, td->name);
if(nelems < 0) ASN__DECODE_STARVED;
nelems += ct->lower_bound;
nelems = ct->upper_bound;
ASN_DEBUG("Preparing to fetch %ld elements from %s",
(long)nelems, td->name);
} else {
nelems = -1;
}
......
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