CSN1.info logo by Dafocus

Pitfalls

As explained in the introduction , the CSN.1 language was designed to make life easier by giving a formal and unambiguous definition of the message structure.
However, due to the difficoulty of writing the encoding with such a language, 3GPP definitions are often wrong.

In this chapter shows some CSN.1 pitfalls that can be found on 3GPP standards. Often the errors are due to wrong precedencies.

Wrong use of sendconstruction

In the example below, the bold part shows the error location.
3GPP TS 44.060 V6.7.0 (2004-05), 11.2.21b:

< PSI3 quater message content > ::=
  < PAGE_MODE : bit (2) >
  < PSI3_CHANGE_MARK : bit (2) >
  < PSI3_QUATER_INDEX : bit (4) >
  < PSI3_QUATER_COUNT : bit (4) >
  { { 0 | 1 < GPRS REP_PRIORITY Description : < GPRS REP PRIORITY Description struct >> }
    { 0 | 1 < 3G Neighbour Cells Description : < 3G Neighbour Cells Description struct >> }
    { 0 | 1 < 3G MEASUREMENT Parameters Description :
                      < 3G MEASUREMENT PARAMETERS Description struct >> }
    { 0 | 1 < 3G Initial Dedicated Mode Reporting Description : 
                      < 3G Initial Dedicated Mode Reporting Description struct >> }
  { null | 0  bit** = < no string > --Receiver compatible with earlier release
  | 1                   --Additions in Release 6:
    < 3G_CCN_ACTIVE : bit >
    < padding bits > } } //   -- truncation at end of message allowed, bits '0' assumed
   ! < Distribution part error : bit (*) = < no string > > ;

In the choice "null | 0 bit** = < no string > | 1 < 3G_CCN_ACTIVE : bit >...", they meant: "we expect an empty string (very old release), 0 followed by any sequence of bits (release 5) or 1 followed by the data added in release 6".
The sendconstruction "0 bit** = < no string >" was meant to allow reception of 0 and any other bit string, but the sending of "0" alone only.

However, the precedence of the sendconstruction (=) is the lowest. Therefore, the string has the following precedency: OX{null | 0 bit**} = {< no string > | 1 < 3G_CCN_ACTIVE : bit >...}

With this precedency set, the decoder only expects either "null" or "0 bit**": the "1" case for R6 is never accepted.

Wrong use of intersection

In the example below, the bold part shows the error location.
3GPP TS 44.060 V6.7.0 (2004-05), 12.3.1:

< EGPRS Ack/Nack Description IE > ::=
  0 < EGPRS Ack/Nack Description struct > -- This IE fills rest of message
  | 1 < Length L : bit (8) > -- Value part of this IE is of length L
      < bit (val(Length L)) > & < EGPRS Ack/Nack Description struct > ;

< EGPRS Ack/Nack Description struct > ::=
  < FINAL_ACK_INDICATION : bit (1) >
  < BEGINNING_OF_WINDOW : bit (1) >
  < END_OF_WINDOW : bit (1) >
  < STARTING_SEQUENCE_NUMBER : bit (11) >
  { 0 | 1 < COMPRESSED_BITMAP_LENGTH: bit (7) >
    < COMPRESSED_BITMAP_STARTING_COLOR_CODE: bit (1) >
    < COMPRESSED_RECEIVED_BLOCK_BITMAP : 
      bit (val(COMPRESSED_BITMAP_LENGTH)) > }
  < UNCOMPRESSED_RECEIVED_BLOCK_BITMAP: bit** > ;

The precedence of the intersection operator (&) is the same of the choice operator.
Therefore, the precendencies for the string above are:

< EGPRS Ack/Nack Description IE > ::=
  {
    0 < EGPRS Ack/Nack Description struct > -- This IE fills rest of message
  }
  | 
  {
    1 
    < Length L : bit (8) > -- Value part of this IE is of length L
    < bit (val(Length L)) >
  }
  & 
  {
    < EGPRS Ack/Nack Description struct > 
  };

The intersection is done on the information element data and on its "1 < Length L : bit (8) >" part. But this is wrong, since the "< EGPRS Ack/Nack Description struct >", does not begin with a dummy bit followed by a 8-bit length.

With the description above, the "UNCOMPRESSED_RECEIVED_BLOCK_BITMAP" found at the end of the "< EGPRS Ack/Nack Description struct >" would have been 9 bits too long.

The correct definition would have been:

3GPP TS 44.060 V6.7.0 (2004-05), 12.3.1:

< EGPRS Ack/Nack Description IE > ::=
  0 < EGPRS Ack/Nack Description struct > -- This IE fills rest of message
  | 1 < Length L : bit (8) > -- Value part of this IE is of length L
      { < bit (val(Length L)) > & < EGPRS Ack/Nack Description struct > } ;

Rules defined in comments

Despite of all the bells and whistles of using a formal language, some 3GPP CSN.1 definitions still have fundamental encoding rules hidden in comments:
3GPP TS 24.008 V5.9.0 (2003-09), Table 10.5.146:

<MS RA capability value part struct >::=  --recursive structure allows any number of Access technologies
  {	{	< Access Technology Type: bit (4) > exclude 1111
      < Access capabilities : <Access capabilities struct> > }
   |  {	< Access Technology Type: bit (4) == 1111 >	-- structure adding Access technologies with same capabilities
      < Length : bit (7) > -- length in bits of list of Additional access technologies and spare bits
      { 1 < Additional access technologies: < Additional access technologies struct > > } ** 0
      <spare bits>** } };

The apparently innocuous words "length in bits of list of Additional access technologies and spare bits" hide a fundamental rule: that the "<Additional access technologies struct>" and the "<spare bits>" must limit their length altogether to "Length" and not to eat out all the remaining bytes.

If used literally, the definition above would not work. They should have defined instead:

< Length : bit (7) > -- length in bits of list of Additional access technologies and spare bits
{
  bit(val(Length)) 
  &
  { 
    { 1 < Additional access technologies: < Additional access technologies struct > > } ** 0
    <spare bits>**
  }
}

Wrong subclassing

In this example, they use the ":=" integer subclassing symbol instead of the "==" subclassing one. With that, the 11111 string will be interpreted as decimal and not as a binary string.
3GPP TS 44.060 V6.7.0 (2004-05), Table 11.2.9e.1:

< Packet Neighbour Cell Data message content > ::=
  < PAGE_MODE : bit (2) >
  { 0   < Global TFI : < Global TFI IE > >

    { < CONTAINER_ID : bit (2) >
      < spare : bit (1)
      < CONTAINER_INDEX : bit (5) >
      ? 0 | 1 < ARFCN : bit (10) >
        < BSIC : bit (6) > }
      < CONTAINER : < Container repetition struct > >
      < padding bits >
      ! < Non-distribution part error : bit (*) = < no string > > }
    ! < Address information part error : bit (*) = < no string > > }
  ! < Distribution part error : bit (*) = < no string > > ;

< Container repetition struct > ::=
  {
    { < PD : bit (3) >
      < CD_LENGTH : { bit (5) exclude 00000 exclude 11111 } >
      < CONTAINER_DATA : octet (val(CD_LENGTH)) > -- Final container segment. Next container follows.

    | < PD : bit (3) >
      < CD_LENGTH : { bit (5) := 11111 } >
      < CONTAINER_DATA : octet ** > } ** -- Container continued in next message.

    { < spare bit (3) > -- Repetition of the container repetition struct continues until:
      < CD_LENGTH : { bit (5) := 00000 } > }      -- A) val(CD_LENGTH) = 0 or
  } // ; -- B) end of PNCD message.