FreeCalypso > hg > freecalypso-sw
diff gsm-fw/ccd/cdc_com.c @ 648:970d6199f2c5
gsm-fw/ccd/*.[ch]: initial import from the LoCosto source
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Thu, 04 Sep 2014 05:48:57 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/ccd/cdc_com.c Thu Sep 04 05:48:57 2014 +0000 @@ -0,0 +1,3304 @@ +/* ++----------------------------------------------------------------------------- +| Project : +| Modul : cdc_com.c ++----------------------------------------------------------------------------- +| Copyright 2002 Texas Instruments Berlin, AG +| All rights reserved. +| +| This file is confidential and a trade secret of Texas +| Instruments Berlin, AG +| The receipt of or possession of this file does not convey +| any rights to reproduce or disclose its contents or to +| manufacture, use, or sell anything it may describe, in +| whole, or in part, without the specific written consent of +| Texas Instruments Berlin, AG. ++----------------------------------------------------------------------------- +| Purpose : Condat Conder Decoder +| Definitions of common functions for encoding and decoding of +| GSM, GPRS or UMTS air interface messages ++----------------------------------------------------------------------------- +*/ + +#ifdef _MSDOS +#include <dos.h> +#include <conio.h> +#endif + +/* + * standard definitions like UCHAR, ERROR etc. + */ +#include "typedefs.h" +#include "header.h" +#include <string.h> +#include <stdlib.h> + +/* + * Prototypes of ccd (USE_DRIVER EQ undef) for prototypes only + * look at ccdapi.h + */ +#undef USE_DRIVER +#include "ccdapi.h" + +/* + * Types and functions for bit access and manipulation + */ +#include "ccd_globs.h" +#include "bitfun.h" + +/* + * Declaration of coder/decoder-tables + */ +#include "ccdtable.h" +#include "ccddata.h" + +/* + * Prototypes and constants in the common part of ccd + */ +#include "ccd.h" +#include "ccd_codingtypes.h" + +/* + * Need memory allocation functions for dynamic arrays (pointers) + */ +#ifdef DYNAMIC_ARRAYS +#include "vsi.h" +#endif + +#ifndef RUN_FLASH +const UBYTE padding_bits[8] = {0, 0, 1, 0, 1, 0, 1, 1}; +const UBYTE padding_bits_prev[8] = {1, 0, 0, 1, 0, 1, 0, 1}; +#endif /* !RUN_FLASH */ + +#ifndef RUN_FLASH +/* Attention for RUN_...: static data (used in cdc_skipElem) */ +static UBYTE dummy[256]; +#endif /* !RUN_FLASH */ + +typedef struct unknownTag +{ + U8 errCode; + U8 tag; + U16 bitpos; + struct unknownTag *next; +}T_UNKNOWN_TAG; + + +#ifndef RUN_FLASH +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : cdc_init_ctx_table | ++--------------------------------------------------------------------+ + + PURPOSE : init the iei_ctx table. This must be done before decoding + a message. + +*/ + +static void cdc_init_ctx_table (T_CCD_Globs *globs) +{ + int i; + +#ifdef DEBUG_CCD + TRACE_CCD (globs, "CONTEXT table init"); +#endif + + for (i=0; i<MAX_RECURSIONS_PER_MSG; i++) + { + globs->iei_ctx[i].valid = FALSE; + } + globs->numEOCPending = 0; +} +#endif /* !RUN_FLASH */ + +#ifndef RUN_INT_RAM +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CCD | +| STATE : code ROUTINE : cdc_BCD_decode | ++--------------------------------------------------------------------+ + + PURPOSE : Decoding of an bitstream containing a BCD string + with k digits. If the first digit in the bitstream + is DIGIT_2, the digits are ordered + in the Bitstream as follow: + + MSBit LSBit + 8 7 6 5 4 3 2 1 + DIGIT_2 DIGIT_1 Octett n + DIGIT_4 DIGIT_3 Octett n+1 + : : : : : : : : + DIGIT_Z DIGIT_X Octett n+m + + if the number of the digits is odd, the last + Octett contains the bit pattern 1111 in the + most significant nibble. + + : : : : : : : : + 1 1 1 1 DIGIT_X Octett n+m + + NOTE: If the first digit in the bitstream is DIGIT_1, + the digits are ordered in a different way: + + MSBit LSBit + 8 7 6 5 4 3 2 1 + DIGIT_1 XXXXXXX Octett n + DIGIT_3 DIGIT_2 Octett n+1 + DIGIT_5 DIGIT_4 Octett n+2 + : : : : : : : : + DIGIT_Z DIGIT_X Octett n+m + + In this case, if the number of the digits + is even, the last octett contains the bit + pattern 1111 in the most significant nibble. + + : : : : : : : : + 1 1 1 1 DIGIT_X Octett n+m + + The amount of digits may be constant or variable. + + NOTE: A special case (type BCD_NOFILL) is the encoding and + decoding of a BCD string starting with DIGIT_2 but + without setting/checking the most significant nibble + of Octet n+m. This nibble belongs to the next IE + (usual coded by type BCD_MNC). + Type BCD_NOFILL is coded by startDigit EQ 2. +*/ + +void cdc_BCD_decode (const ULONG e_ref, UBYTE startDigit, T_CCD_Globs *globs) +{ + BOOL is_variable; + UBYTE *digits; + UBYTE *addr_c_xxx; + ULONG i, max_rep, nibbles_to_read, repeat; + ULONG cix_ref, num_prolog_steps, prolog_step_ref; + int k; + +#ifdef DEBUG_CCD + #ifndef CCD_SYMBOLS + TRACE_CCD (globs, "cdc_BCD_decode()"); + #else + TRACE_CCD (globs, "cdc_BCD_decode() %s", ccddata_get_alias((USHORT) e_ref, 1)); + #endif +#endif + + cix_ref = melem[e_ref].calcIdxRef; + num_prolog_steps = calcidx[cix_ref].numPrologSteps; + prolog_step_ref = calcidx[cix_ref].prologStepRef; + + /* + * if this element is conditional, check the condition + */ + if (calcidx[cix_ref].numCondCalcs NEQ 0 + AND ! ccd_conditionOK (e_ref, globs)) + return; + + /* + * if this element have a defined Prolog + * we have to process it before decoding the bitstream + */ + if (num_prolog_steps) + { + ccd_performOperations (num_prolog_steps, prolog_step_ref, globs); + } + + /* + * if this element is repeatable, and the number of + * repeats depends on another element, calculate the repeater + */ + + if (melem[e_ref].repType NEQ ' ') + { + is_variable = ccd_calculateRep (e_ref, &repeat, &max_rep, globs); + } + else + { + repeat = 1; + is_variable = FALSE; + } + + /* + * setup the offset into the C-structure for this element + */ + globs->pstructOffs = melem[e_ref].structOffs; + + if (melem[e_ref].optional) + { + /* + * for optional elements set the valid-flag + */ + globs->pstruct[globs->pstructOffs++] = (UBYTE) TRUE; + } + + + if (is_variable) + { + /* + * for variable sized elements store the min-value + * as counter into the C-Structure (c_xxx). + */ + addr_c_xxx = (UBYTE *) (globs->pstruct + globs->pstructOffs++); + if (max_rep > 255) + globs->pstructOffs++; + } + else + addr_c_xxx = NULL; + + digits = (UBYTE *) (globs->pstruct + globs->pstructOffs); + + + if (startDigit EQ 1) + { + /* + * read the BCD digits out of the bitstream. + * The read order is 1,X,3,2,5,4 ... + */ + /* + * if the first digit is digit_1 read it and skip + * the next 4 bits, because they do not belong to + * the BCD stream. + */ + digits[0] = bf_decodeByteNumber (4, globs); + bf_incBitpos (4, globs); + /* + * make a correction on the repeatvalue + */ + if (melem[e_ref].repType NEQ ' ') + { + is_variable = ccd_calculateRep (e_ref, &repeat, &max_rep, globs); + } + + k = 2; + + for (i=0; i<repeat; i++) + { + digits[k] = bf_decodeByteNumber (4, globs); + #ifdef DEBUG_CCD + TRACE_CCD (globs, "BCD digit (%X) read", (USHORT) digits[k]); + #endif + k = ((k&1) EQ 0) ? (k-1) : (k+3); + } + } + else + { + /* + * read the BCD digits out of the bitstream. + * The read order is 2,1,4,3,6,5 ... + */ + k = 1; + + nibbles_to_read = repeat; + + if (repeat & 1) + nibbles_to_read++; + + for (i=0; i<nibbles_to_read; i++) + { + digits[k] = bf_decodeByteNumber (4, globs); + #ifdef DEBUG_CCD + TRACE_CCD (globs, "BCD digit (%X) read", (USHORT) digits[k]); + #endif + k = ((k&1) EQ 1) ? (k-1) : (k+3); + } + } + + /* + * check the 1111 pattern and the even odd criteria + */ + + if (startDigit EQ 1) + { + if ((repeat & 1) EQ 0) + { + /* even number of digits */ + if (digits[repeat] NEQ 0xf) + repeat++; + } + } + else + { + if ((repeat & 1) EQ 1) + { + /* odd number of digits */ + if (digits[repeat] NEQ 0xf AND startDigit EQ 0) + { + /* + * if there is no 1111 pattern generate an error + */ + ccd_setError (globs, ERR_PATTERN_MISMATCH, + CONTINUE, + (USHORT) (globs->bitpos-8), (USHORT) -1); + } + } + + else + { + /* even number of digits - the last may be 0xf */ + if (digits[repeat-1] EQ 0xf) + repeat--; /* 0x0f dosn't belong to the coded digit string */ + } + } + + if (addr_c_xxx NEQ NULL) + { + /* + * store the number of digits into the + * c_xxx variable if there is one. + */ + if (max_rep > 65535) + { + ULONG *addr_c_xxx_u32; + addr_c_xxx_u32 = (ULONG *)addr_c_xxx; + *addr_c_xxx_u32 = repeat; + } + else if (max_rep > 255) + { + USHORT *addr_c_xxx_u16; + addr_c_xxx_u16 = (USHORT *)addr_c_xxx; + *addr_c_xxx_u16 = (USHORT) repeat; + } + else + *addr_c_xxx = (UBYTE) repeat; + } +} +#endif /* !RUN_INT_RAM */ + +#ifndef RUN_INT_RAM +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CCD | +| STATE : code ROUTINE : cdc_BCD_encode | ++--------------------------------------------------------------------+ + + PURPOSE : encoding a Bytearray, that contain a BCD Number, into + bitstream. + The digits coded in the following order + into the Bitstream: + + MSBit LSBit + 7 8 6 5 4 3 2 1 + DIGIT_2 DIGIT_1 Octett n + DIGIT_4 DIGIT_3 Octett n+1 + : : : : : : : : + DIGIT_Z DIGIT_X Octett n+m + + if the number of the digits are odd, the bit pattern 1111 + will be coded in the most significant nibble of + the last Octett. + + : : : : : : : : + 1 1 1 1 DIGIT_X Octett n+m + + The amount of digits may be constant or variable. +*/ +void cdc_BCD_encode (const ULONG e_ref, UBYTE startDigit, T_CCD_Globs *globs) +{ + ULONG repeat; + int k; + register UBYTE *digits; + BOOL fullBitsNeeded=FALSE; + ULONG cix_ref, num_prolog_steps, prolog_step_ref; + +#ifdef DEBUG_CCD + #ifndef CCD_SYMBOLS + TRACE_CCD (globs, "cdc_BCD_encode()"); + #else + TRACE_CCD (globs, "cdc_BCD_encode() %s", ccddata_get_alias((USHORT) e_ref, 1)); + #endif +#endif + + cix_ref = melem[e_ref].calcIdxRef; + num_prolog_steps = calcidx[cix_ref].numPrologSteps; + prolog_step_ref = calcidx[cix_ref].prologStepRef; + + /* + * if this element is conditional, check the condition + */ + if (calcidx[cix_ref].numCondCalcs NEQ 0 + AND ! ccd_conditionOK (e_ref, globs)) + return; + + /* + * if this element have a defined Prolog + * we have to process it before decoding the bitstream + */ + if (num_prolog_steps) + { + ccd_performOperations (num_prolog_steps, prolog_step_ref, globs); + } + + /* + * setup the offset into the C-structure for this element + */ + globs->pstructOffs = melem[e_ref].structOffs; + + if (melem[e_ref].optional) + { + /* + * for optional elements check the valid-flag + */ + if (globs->pstruct[globs->pstructOffs++] == FALSE) + return; +#ifdef DEBUG_CCD + else if (globs->pstruct [melem[e_ref].structOffs] != TRUE) + { + TRACE_CCD (globs, "Ambiguous value for valid flag!\n...assumed 1 for ccdID=%d", + e_ref); + } +#endif + } + + /* + * if this element is repeatable, and the number of + * repeats depends on another element, calculate the repeater + */ + if (melem[e_ref].repType EQ 'v' OR melem[e_ref].repType EQ 'i') + { + /* + * for variable sized elements read the amount + * of repeats out of the C-Structure (c_xxx). + * If the number of repeats given by the C-Structure + * exceeds the allowed value (maxRepeat) CCD gives a warning! + */ + if (melem[e_ref].maxRepeat > 255) + { + ULONG count = (ULONG) (* (USHORT *)(globs->pstruct + globs->pstructOffs++)); + repeat = MINIMUM (count, (ULONG) melem[e_ref].maxRepeat); + if (repeat < count) + ccd_recordFault (globs, ERR_MAX_REPEAT, CONTINUE, + e_ref, globs->pstruct + globs->pstructOffs); + } + else + { + repeat = (ULONG)MINIMUM (globs->pstruct[globs->pstructOffs], + melem[e_ref].maxRepeat); + if ( repeat < (ULONG) (globs->pstruct[globs->pstructOffs]) ) + ccd_recordFault (globs, ERR_MAX_REPEAT, CONTINUE, + (USHORT) e_ref, globs->pstruct + globs->pstructOffs); + } + globs->pstructOffs++; + } + else + if (melem[e_ref].repType EQ 'c') + repeat = (ULONG) melem[e_ref].maxRepeat; + else + repeat = 1; + + /* There seems to exist cases where address contains no digits. */ + if (repeat EQ 0) + return; + + /* + * setup the read pointer to the byte array that contain + * the BCD number. + */ + digits = (UBYTE *) (globs->pstruct + globs->pstructOffs); + + if (startDigit EQ 1) + { + /* + * write the BCD digits into the bitstream. + * The write order is 1,X,3,2,5,4 ... + */ + if ((repeat & 1) EQ 0) + { + /* + * for even digits store the 1111 pattern at last digit + */ + fullBitsNeeded = TRUE; + } + /* + * if the first digit is digit_1 write it and skip + * the next 4 bits, because they does not belong to + * the BCD stream. + */ + bf_codeByteNumber (4, digits[0], globs); + + #ifdef DEBUG_CCD + TRACE_CCD (globs, "BCD digit (%X) written", (USHORT) digits[0]); + TRACE_CCD (globs, "skipping 4 bits"); + #endif + + bf_incBitpos (4, globs); + k = 2; + + while (--repeat>1) + { + bf_codeByteNumber (4, digits[k], globs); + #ifdef DEBUG_CCD + TRACE_CCD (globs, "BCD digit (%X) written", (USHORT) digits[k]); + #endif + k = ((k&1) EQ 0) ? (k-1) : (k+3); + } + if (repeat) + { + if (fullBitsNeeded) + { + bf_codeByteNumber (4, 0xf, globs); + k = ((k&1) EQ 0) ? (k-1) : (k+3); + } + bf_codeByteNumber (4, digits[k], globs); + } + + } + else + { + /* + * store the BCD digits into the bitstream. + * The write order is 2,1,4,3,6,5 ... + */ + if (repeat & 1) + { + /* + * for odd digits store the 1111 pattern at last digit + * in case of type BCD_NOFILL use 0 instead + */ + fullBitsNeeded = TRUE; + } + + k = 1; + + while ( repeat-- > 1) + { + bf_codeByteNumber (4, digits[k], globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "BCD digit (%X) written", (USHORT) digits[k]); +#endif + k = ((k&1) EQ 1) ? (k-1) : (k+3); + } + if (fullBitsNeeded) + { + bf_codeByteNumber (4, (UBYTE)((startDigit NEQ 2) ? 0xf : 0), globs); + k = ((k&1) EQ 1) ? (k-1) : (k+3); + } + bf_codeByteNumber (4, digits[k], globs); + } +} +#endif /* !RUN_INT_RAM */ + +#ifndef RUN_FLASH +/* Attention for RUN_...: static function */ +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : cdc_init_table | ++--------------------------------------------------------------------+ + + PURPOSE : init the iei_table for each new msg that is to be decoded. + The c_ref references a composition (msg). The function + initialises the table entrys only for the used iei for + this message. + +*/ + +static void cdc_init_table (const ULONG c_ref, T_CCD_Globs *globs) + +{ + ULONG look_up; + ULONG num_elems; + ULONG ie_table_idx; + ULONG rlevel = globs->ccd_recurs_level; + + if (globs->iei_ctx[rlevel].valid AND rlevel < (ULONG) globs->last_level) + { + int i; + /* + * this iei context has been initialized before, so + * no action for this. All deeper levels must be set + * to invalid; + */ + for (i=globs->last_level; i<MAX_RECURSIONS_PER_MSG; i++) + globs->iei_ctx[i].valid = FALSE; + +#ifdef DEBUG_CCD + TRACE_CCD (globs, "TAG table init for old level %d", rlevel); +#endif + } + else + { + /* + * this iei context has not been initialized before, so + * initialize the iei_table for this. + */ +#ifdef DEBUG_CCD + TRACE_CCD (globs, "TAG table init for new level %d", rlevel); +#endif + look_up = (ULONG) mcomp[c_ref].componentRef; + num_elems = (ULONG) mcomp[c_ref].numOfComponents; + + /* + * store the startposition of the corresponding melem table and + * the number of elements in the IEtable + */ + globs->iei_ctx[rlevel].melemStart = (USHORT) look_up; + globs->iei_ctx[rlevel].ieTableLen = (USHORT) num_elems; + globs->iei_ctx[rlevel].EOCPending = FALSE; + globs->iei_ctx[rlevel].countSkipped = 0; + + /* + * for each element with an iei (ident) setup the + * the iei_table-entry. + */ + ie_table_idx = 0; + + /* + * if the number of IE in this message is greater than + * the allocated IEItable, generate an error. + */ + if (num_elems > MAX_IE_PER_MSG) + ccd_setError (globs, ERR_INTERNAL_ERROR, BREAK, (USHORT) -1); + + while (num_elems--) + { + if (melem[look_up].ident NEQ 0xffff) + { + globs->iei_ctx[rlevel].iei_table[ie_table_idx].ident = (UBYTE) melem[look_up].ident; + + /* + * GSM1TV elements have only a 4 bit Tag (T). For this + * elements we have to shift the ident into the upper nibble + * and set the lower nibble to zero. For GSM2T elements and + * GSM1TV elements set the MSBit (Bit7). + */ + if (melem[look_up].codingType EQ CCDTYPE_GSM1_TV) + { + /* + * shift into the upper nibble, clear the lower nibble + * and set the MSBit. + */ + globs->iei_ctx[rlevel].iei_table[ie_table_idx].ident <<= 4; + globs->iei_ctx[rlevel].iei_table[ie_table_idx].ident |= 0x80; + globs->iei_ctx[rlevel].iei_table[ie_table_idx].ident &= 0xf0; + } + else + { + if (melem[look_up].codingType EQ CCDTYPE_GSM2_T) + { + /* + * Set the MSBit. + */ + globs->iei_ctx[rlevel].iei_table[ie_table_idx].ident |= 0x80; + } + } + globs->iei_ctx[rlevel].iei_table[ie_table_idx].act_amount = 0; + globs->iei_ctx[rlevel].iei_table[ie_table_idx].exhausted = FALSE; + + switch (melem[look_up].codingType) + { + case CCDTYPE_GSM1_TV: + + case CCDTYPE_GSM2_T: + + case CCDTYPE_GSM3_TV: + + case CCDTYPE_GSM4_TLV: + + case CCDTYPE_GSM5_TV: + + case CCDTYPE_GSM5_TLV: + + case CCDTYPE_GSM1_ASN: + + case CCDTYPE_GSM6_TLV: + + globs->iei_ctx[rlevel].iei_table[ie_table_idx].valid = TRUE; + break; + + default: + globs->iei_ctx[rlevel].iei_table[ie_table_idx].valid = FALSE; + break; + } + } + else + globs->iei_ctx[rlevel].iei_table[ie_table_idx].valid = FALSE; + +#ifdef DEBUG_CCD + TRACE_CCD (globs, "iei_table[%d] v=%d ident=%x level=%d", + ie_table_idx, + globs->iei_ctx[rlevel].iei_table[ie_table_idx].valid, + globs->iei_ctx[rlevel].iei_table[ie_table_idx].ident, + rlevel); +#endif + + look_up++; + ie_table_idx++; + } + globs->iei_ctx[rlevel].valid = TRUE; + } +} +#endif /* !RUN_FLASH */ + +#ifndef RUN_FLASH +/* Attention for RUN_...: static function */ +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : cdc_search_table | ++--------------------------------------------------------------------+ + + PURPOSE : search on the iei_table for the given TAG (T). + if the TAG can be found (and - in case of CCDTYPE_GSM1_ASN - + if the information element isn't exhausted), the table + index was returned as a difference between the found index + and the aktIndex, -127 otherwise. + +*/ + +static int cdc_search_table + ( + int akt_index, + ULONG t, + BOOL limited, + BOOL *nonTaggedFound, + T_CCD_Globs *globs + ) +{ + int tab_idx; + ULONG iei; + int ret = -127; + ULONG rec_level = globs->ccd_recurs_level; + + /* + * search from the akt position to the end of the table. + * This is faster, because in correct messages the found Tag + * is at a later position in the table. + */ + tab_idx = akt_index; + + *nonTaggedFound = FALSE; + + while (tab_idx < (int) globs->iei_ctx[rec_level].ieTableLen) + { +#ifdef DEBUG_CCD + TRACE_CCD (globs, "looking for Tag(%x) iei_table[%d] v=%d ident=%x level=%d", + t, tab_idx, + globs->iei_ctx[rec_level].iei_table[tab_idx].valid, + globs->iei_ctx[rec_level].iei_table[tab_idx].ident, + rec_level); +#endif + + if (globs->iei_ctx[rec_level].iei_table[tab_idx].valid) + { + if (limited) + { + iei= (ULONG)(globs->iei_ctx[rec_level].iei_table[tab_idx].ident & 0x7f); + } + else + { + iei= (ULONG)(globs->iei_ctx[rec_level].iei_table[tab_idx].ident); + } + if ( iei EQ t ) + { + if ( globs->iei_ctx[rec_level].iei_table[tab_idx].exhausted EQ FALSE ) + { + return (tab_idx-akt_index); + } + else if ( (globs->iei_ctx[rec_level].melemStart + akt_index) + EQ (int) globs->iei_ctx[rec_level].melemLast) + { + /* + * allows multiple appearance of the repeated element is coded as + * TLV0 TLV1 TLV2 .... + */ + return (tab_idx-akt_index); + } + else + { + ret = (tab_idx-akt_index); + } + } + } + else + *nonTaggedFound = TRUE; + tab_idx++; + } + + tab_idx = 0; + + while (tab_idx < akt_index) + { +#ifdef DEBUG_CCD + TRACE_CCD (globs, "looking for Tag(%x) iei_table[%d] v=%d ident=%x level=%d", + t, tab_idx, + globs->iei_ctx[rec_level].iei_table[tab_idx].valid, + globs->iei_ctx[rec_level].iei_table[tab_idx].ident, + rec_level); +#endif + if (limited) + { + iei= (ULONG)(globs->iei_ctx[rec_level].iei_table[tab_idx].ident & 0x7f); + } + else + { + iei= (ULONG) globs->iei_ctx[rec_level].iei_table[tab_idx].ident; + } + if (globs->iei_ctx[rec_level].iei_table[tab_idx].valid + AND (iei EQ t) ) + { + if ( globs->iei_ctx[rec_level].iei_table[tab_idx].exhausted EQ FALSE ) + { + return (tab_idx-akt_index); + } + else + { + ret = (tab_idx-akt_index); + } + } + tab_idx++; + } + + if (ret != -127) + { + globs->SequenceError = TRUE; + } + + return ret; +} +#endif /* !RUN_FLASH */ + +#ifndef RUN_FLASH +/* Attention for RUN_...: static function */ +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : cdc_decode_L | ++--------------------------------------------------------------------+ + + PURPOSE : Decode the length element of TLV and LV values +*/ + +static ULONG cdc_decode_L (const ULONG e_ref, const ULONG len_l, T_CCD_Globs *globs) +{ + ULONG l; + + switch (melem[e_ref].codingType) + { + case CCDTYPE_GSM1_ASN: + l = (ULONG) bf_decodeByteNumber (8, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "decoding 8 bits, l = (%x)", l); +#endif + if (l EQ 0x80) + l = 0xFFFF; + else if (l EQ 0x81) + { + l = (ULONG) bf_decodeByteNumber (8, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "decoding 8 bits after 0x81, l = (%x)", l); +#endif + } + else if (l EQ 0x82) + { + l = bf_decodeShortNumber (16, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "decoding 16 bits after 0x82, l = (%x)", l); +#endif + } + break; + + case CCDTYPE_GSM5_TLV: + l = (ULONG) bf_decodeByteNumber (8, globs); + + if (l EQ 0x81) + { + l = (ULONG) bf_decodeByteNumber (8, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "decoding 8 bits after 0x81, l = (%x)", l); + } + else + { + TRACE_CCD (globs, "decoding 8 bits, l = (%x)", l); +#endif + } + break; + + case CCDTYPE_GSM6_TLV: + l = bf_decodeShortNumber (16, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "decoding 16 bits, l = (%x)", l); +#endif + break; + + default: + l = (ULONG) bf_decodeByteNumber (len_l, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "decoding %d bits, l = (%x)", len_l, l); +#endif + break; + } + + /* + * Write the value of l at the end of UPN Stack. + * this could be read by an IE of the coding type NO_CODE. + */ + globs->KeepReg[0] = l ; + return l; +} +#endif /* !RUN_FLASH */ + +#ifndef RUN_FLASH +/* Attention for RUN_...: static function */ +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : cdc_tagged_LV_decode| ++--------------------------------------------------------------------+ + + PURPOSE : If the parameter lenL is set to a positive value, + this function decodes the L-component. + After this it decodes the element referenced + by eRef out of the bitstream into the C-Structure + (globs->pstruct) at position globs->pstructOffs. + If a repeat value is defined for this element, + this function decodes only one appeareance + of the element because it is a tagged + element. In this case the decoded element is stored in + an array wich is indexed by eIndex; +*/ + +static BOOL cdc_tagged_LV_decode (const ULONG e_ref, + ULONG e_index, + const ULONG len_l, + T_CCD_Globs *globs) +{ + ULONG amount, l; + USHORT act_maxBP, tmp_maxBP; + BOOL endOfComposition = FALSE; + BOOL asn1=FALSE; + U32 offset=0; +#ifdef DYNAMIC_ARRAYS + U8 *old_pstruct = NULL; +#endif + + if (melem[e_ref].codingType EQ CCDTYPE_GSM1_ASN) + asn1 = TRUE; + + if (melem[e_ref].elemType NEQ 'S') + { + /* + * set the offset into the C-structure for this element. + */ + if (melem[e_ref].optional) + { + globs->pstruct[globs->pstructOffs++] = (UBYTE) TRUE; + } + + if (melem[e_ref].repType EQ 'i') + { + /* + * The number of appearance of all repeatable IEs may + * differ in a message. So we have to store the number + * in a c_xxx counter into the C-Structure. + */ + if (melem[e_ref].maxRepeat > 65535) + *(ULONG *) (globs->pstruct + globs->pstructOffs++) = e_index; + else if (melem[e_ref].maxRepeat > 255) + *(USHORT *) (globs->pstruct + globs->pstructOffs++) = (USHORT) e_index; + else + globs->pstruct[globs->pstructOffs] = (UBYTE) e_index; + + globs->pstructOffs++; + + /* + * Recalculate the struct offset for repeatable IEs. + * New pointer types 'R' and 'F' are equivalent to 'V'. + */ +#ifdef DYNAMIC_ARRAYS + offset = (e_index-1) * ((melem[e_ref].elemType EQ 'V' + OR melem[e_ref].elemType EQ 'R' + OR melem[e_ref].elemType EQ 'F' + ) ? mvar[melem[e_ref].elemRef].cSize + : mcomp[melem[e_ref].elemRef].cSize + ); +#else + offset = (e_index-1) * ((melem[e_ref].elemType EQ 'V') + ? mvar[melem[e_ref].elemRef].cSize + : mcomp[melem[e_ref].elemRef].cSize + ); +#endif + } + } + /* + * If len_l > 0 read the l-Component out of the bistream. + */ + if (len_l) + { + if( len_l <= (ULONG) (globs->maxBitpos - globs->bitpos) ) + { + act_maxBP = globs->maxBitpos; + l = cdc_decode_L (e_ref, len_l, globs); + + if (l EQ 0xFFFF) + { + /* + * For ASN1-BER encoding we must look for the special + * length 0x80 because it indicates the indefinite + * length. This needs a special handling with later EOC tags. + * + */ + globs->iei_ctx[globs->ccd_recurs_level].EOCPending = TRUE; + globs->numEOCPending++; + + #ifdef DEBUG_CCD + TRACE_CCD (globs, "implicit ASN1 length - EOC is pending"); + #endif + } + else + { + /* + * Calculate the max bitpos for this element + */ + tmp_maxBP = (USHORT) (globs->bitpos + (l*8)); + if (globs->buflen < tmp_maxBP) + { + ccd_recordFault (globs, ERR_MSG_LEN, CONTINUE, (USHORT) e_ref, globs->pstruct + globs->pstructOffs); + } + else if (globs->maxBitpos < tmp_maxBP) + { + ccd_recordFault (globs, ERR_ELEM_LEN, BREAK, (USHORT) e_ref, globs->pstruct + globs->pstructOffs); + } + globs->maxBitpos = (USHORT)MINIMUM (globs->buflen, tmp_maxBP); + tmp_maxBP = globs->maxBitpos; + } + } + else + { + ccd_recordFault (globs, ERR_ELEM_LEN, BREAK, (USHORT) e_ref, globs->pstruct + globs->pstructOffs); + } + } +#ifdef DYNAMIC_ARRAYS + /* + * Check for pointer types; allocate memory if necessary. + */ + if ((melem[e_ref].elemType >= 'P' AND melem[e_ref].elemType <= 'R') OR + (melem[e_ref].elemType >= 'D' AND melem[e_ref].elemType <= 'F')) + { + U32 cSize; + U8 *addr; + + /* + * Find size to allocate; + * - Read from mcomp or mvar according to type + */ + cSize = (ULONG)((melem[e_ref].elemType EQ 'V' OR + melem[e_ref].elemType EQ 'R') + ? mvar[melem[e_ref].elemRef].cSize + : mcomp[melem[e_ref].elemRef].cSize + ); + + /* + * Allocate additional memory + */ + addr = (U8 *)DP_ALLOC( cSize, globs->alloc_head, DP_NO_FRAME_GUESS); + + /* If no memory, log error and return immediately */ + if (addr EQ NULL) { + ccd_setError (globs, ERR_NO_MEM, + BREAK, + (USHORT) -1); + return endOfComposition; + } + else + memset (addr, 0, (size_t)(cSize)); + + /* + * Memory allocated; + * 1. Save old "globs->pstruct" variables + * 2. Store pointer to freshly allocated memory area in structure + * 3. Initialize pstruct to point to the freshly allocated memory area. + * 4. Initialize pstructOffs to 0 to start decoding at offset 0 + * in the new memory area. + */ + old_pstruct = globs->pstruct; + *(U8 **)(globs->pstruct + globs->pstructOffs) = addr; + globs->pstruct = addr; + globs->pstructOffs = 0; + } + else + { + globs->pstructOffs += offset; + } +#else /* DYNAMIC_ARRAYS */ + globs->pstructOffs += offset; +#endif /* DYNAMIC_ARRAYS */ + + + /* + * Decode the value. Keep caution with BER encoding of ASN1 integers. + * All other types can be decoded by a generic function. + */ + if (asn1 AND melem[e_ref].elemType EQ 'V' + AND + melem[e_ref].repType EQ ' ' + AND + l NEQ 0xFFFF + ) + { +#ifdef DEBUG_CCD +#ifdef CCD_SYMBOLS + TRACE_CCD (globs, "BER decoding of ASN.1 integer %s", + ccddata_get_alias((USHORT) e_ref, 1)); +#else + TRACE_CCD (globs, "BER decoding of ASN.1 integer; e_ref = %d", melem[e_ref].elemRef); +#endif +#endif + + if (mvar[melem[e_ref].elemRef].cType EQ 'X') + bf_readBitChunk (l*8, globs); + else + bf_readBits (l*8, globs); + } + else + { + amount = 1; + if (len_l) + { + if (l > 0) + { + cdc_decodeElemvalue (e_ref, &amount, globs); + } + else + { + amount = 0; + } + } + else + { + if (melem[e_ref].codingType != CCDTYPE_GSM2_T) + cdc_decodeElemvalue (e_ref, &amount, globs); + } + } +#ifdef DYNAMIC_ARRAYS + /* + * Restore globs->pstruct for possible use below + */ + if (old_pstruct NEQ NULL) + globs->pstruct = old_pstruct; +#endif + + if (asn1 AND globs->numEOCPending AND !bf_endOfBitstream(globs)) + { + UBYTE T = bf_decodeByteNumber (8, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "looking for EOC decoding 8 bits T = (%x)", T); +#endif + + if (T EQ 0) + { +#ifdef DEBUG_CCD + TRACE_CCD (globs, "First EOC octet found"); +#endif + + if (globs->iei_ctx[globs->ccd_recurs_level].EOCPending) + { +#ifdef DEBUG_CCD + TRACE_CCD (globs, "End of ASN1 TLV"); +#endif + /* + * Skip the second EOC octet. + */ + bf_incBitpos (8, globs); + globs->iei_ctx[globs->ccd_recurs_level].EOCPending = FALSE; + globs->numEOCPending--; + } + else + { + /* + * The read first EOC octet belongs to an ASN1 TLV of a + * higher recursion level. Let it be read and evalauted later + * again for that IE. + */ + bf_setBitpos (globs->bitpos-8, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "End of higer level ASN1 TLV"); + TRACE_CCD (globs, "Decrementing bitpos by 8 to %d", globs->bitpos); +#endif + endOfComposition = TRUE; + } + } + else + { + if (globs->iei_ctx[globs->ccd_recurs_level].EOCPending) + { + /* + * EOC element is pending but not found. + */ + ccd_setError (globs, ERR_EOC_TAG_MISSING, + BREAK, + (USHORT) T, + globs->bitpos-8, + (USHORT) -1); + + bf_setBitpos (globs->bitpos-8, globs); + } + else + { + /* + * normal TAG leave it in the bitstream + */ +#ifdef DEBUG_CCD + TRACE_CCD (globs, "Normal TAG - Decrementing bitpos by 8 to %d", globs->bitpos); +#endif + bf_setBitpos (globs->bitpos-8, globs); + } + } + } + + if (len_l) + { + if (!asn1) + { + if (globs->bitpos > tmp_maxBP) + { + ccd_recordFault (globs, ERR_ELEM_LEN, CONTINUE, (USHORT) e_ref, globs->pstruct + globs->pstructOffs); + } + else + { + /* + * set the bitpos to the end of the LV or TLV element + */ + bf_setBitpos (tmp_maxBP, globs); + } + } + /* + * set the maxBitpos to the next octet boundary if the + * last non-spare IE does not end at an octet boundary. + * This is necessary for avoiding an early end of decoding. + */ +/* + globs->maxBitpos = globs->buflen; +*/ + globs->maxBitpos = act_maxBP; + } + + return endOfComposition; +} +#endif /* !RUN_FLASH */ + +#ifndef RUN_FLASH +/* Attention for RUN_...: static function */ +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : cdc_normal_LV_decode| ++--------------------------------------------------------------------+ + + PURPOSE : If the parameter lenL is set, this function + decodes the L-component. After this it decodes + the element referenced by eRef from the + bitstream into the C-Structure (globs->pstruct) + at position globs->pstructOffs. + If a repeat value is defined for this element + this function decodes the V-component multiple and stores + the values into an array. +*/ + +static BOOL cdc_normal_LV_decode (const ULONG e_ref, + const ULONG len_l, + T_CCD_Globs *globs) +{ + ULONG l, repeat, amount, max_rep; + USHORT act_maxBP, tmp_maxBP; + BOOL is_variable; + BOOL endOfComposition = FALSE; + BOOL asn1; + BOOL length_in_bits; +#ifdef DYNAMIC_ARRAYS + U8 *old_pstruct = NULL; +#endif + + switch (melem[e_ref].codingType) + { + case CCDTYPE_GSM1_ASN: + asn1 = TRUE; + length_in_bits = FALSE; + break; + + case CCDTYPE_GSM7_LV: + asn1 = FALSE; + length_in_bits = TRUE; + break; + + default: + asn1 = FALSE; + length_in_bits = FALSE; + break; + } + + /* + * if this element is repeatable, and the number of + * repeats depends on another element, calculate the repeater + */ + if (melem[e_ref].repType NEQ ' ') + { + is_variable = ccd_calculateRep (e_ref, &repeat, &max_rep, globs); + } + else + { + repeat = 1; + is_variable = FALSE; + } + + if (melem[e_ref].elemType NEQ 'S') + { + /* + * Element is not a SPARE. + * Setup the offset into the C-structure for this element + */ + if (melem[e_ref].optional) + { + globs->pstruct[globs->pstructOffs++] = (UBYTE) TRUE; + } + + if (is_variable) + { + /* + * for variable sized elements store the min-value + * as counter into the C-Structure (c_xxx). + */ + if (max_rep > 65535) + *(ULONG *) (globs->pstruct + globs->pstructOffs++) = repeat; + else if (max_rep > 255) + *(USHORT *) (globs->pstruct + globs->pstructOffs++) = (USHORT) repeat; + else + globs->pstruct[globs->pstructOffs] = (UBYTE) repeat; + + globs->pstructOffs++; + } + } + + /* + * if len_l > 0 read the l-Component out of the bistream. + */ + if (len_l) + { + if( len_l <= (ULONG)(globs->maxBitpos - globs->bitpos) ) + { + act_maxBP = globs->maxBitpos; + + l = cdc_decode_L (e_ref, len_l, globs); + + if (l EQ 0xFFFF) + { + /* + * for ASN1 element coding we must look for the special + * length 0x80 because it indicates the indefinite + * length. This needs a special handling with later EOC tags. + */ + globs->iei_ctx[globs->ccd_recurs_level].EOCPending = TRUE; + + globs->numEOCPending++; + + #ifdef DEBUG_CCD + TRACE_CCD (globs, "implicit ASN1 length - EOC is pending"); + #endif + } + else + { + /* + * calculate the max bitpos for this element + */ + if (!length_in_bits) + l *= 8; + + tmp_maxBP = (USHORT) (globs->bitpos + l); + + if (globs->buflen < tmp_maxBP) + { + ccd_recordFault (globs, ERR_MSG_LEN, CONTINUE, (USHORT) e_ref, globs->pstruct + globs->pstructOffs); + } + else if (globs->maxBitpos < tmp_maxBP) + { + ccd_recordFault (globs, ERR_ELEM_LEN, BREAK, (USHORT) e_ref, globs->pstruct + globs->pstructOffs); + } + globs->maxBitpos = (USHORT)MINIMUM (globs->buflen, tmp_maxBP); + tmp_maxBP = globs->maxBitpos; + + /* + * for bitfields which appear in TLV or LV elements + * we must calculate the length (repeat) from the l values + */ + if (melem[e_ref].repType EQ 'b') + repeat = l; + } + } + else + { + ccd_recordFault (globs, ERR_ELEM_LEN, BREAK, (USHORT) e_ref, globs->pstruct + globs->pstructOffs); + } + } +#ifdef DYNAMIC_ARRAYS + /* + * MVJ: Dynamic array addition. + * Check for pointer types; allocate memory if necessary. + */ + if ((melem[e_ref].elemType >= 'P' AND melem[e_ref].elemType <= 'R') OR + (melem[e_ref].elemType >= 'D' AND melem[e_ref].elemType <= 'F')) { + ULONG cSize, rep; + U8 *addr; + + /* + * Find size to allocate; + * - Read from mcomp or mvar according to type + * - Unbounded (0-terminated) ASN1-types are allocated with MAX repeat + */ + if (globs->iei_ctx[globs->ccd_recurs_level].EOCPending) { + rep = (ULONG) melem[e_ref].maxRepeat; + } else { + rep = repeat; + } + cSize = (ULONG)((melem[e_ref].elemType EQ 'V' OR + melem[e_ref].elemType EQ 'R') + ? mvar[melem[e_ref].elemRef].cSize + : mcomp[melem[e_ref].elemRef].cSize + ) * rep; + + /* + * Allocate additional memory + */ + addr = (U8 *)DP_ALLOC( cSize, globs->alloc_head, DP_NO_FRAME_GUESS); + + /* If no memory, log error and return immediately */ + if (addr EQ NULL) { + ccd_setError (globs, ERR_NO_MEM, + BREAK, + (USHORT) -1); + return endOfComposition; + } + else + memset (addr, 0, (size_t)cSize); + + /* + * Memory allocated; + * 1. Save old "globs->pstruct" variables + * 2. Store pointer to freshly allocated memory area in structure + * 3. Initialize pstruct to point to the freshly allocated memory area. + * 4. Initialize pstructOffs to 0 to start decoding at offset 0 + * in the new memory area. + */ + old_pstruct = globs->pstruct; + *(U8 **)(globs->pstruct + globs->pstructOffs) = addr; + globs->pstruct = addr; + globs->pstructOffs = 0; + } +#endif + + /* + * Decode the value. Keep caution with BER encoding of ASN1 integers. + * All other types can be decoded by a generic function. + */ + if (asn1 AND melem[e_ref].elemType EQ 'V' + AND + melem[e_ref].repType EQ ' ' + AND + l NEQ 0xFFFF + ) + { +#ifdef DEBUG_CCD +#ifdef CCD_SYMBOLS + TRACE_CCD (globs, "BER decoding of ASN.1 integer %s", + ccddata_get_alias((USHORT) e_ref, 1)); +#else + TRACE_CCD (globs, "BER decoding of ASN.1 integer; e_ref = %d", melem[e_ref].elemRef); +#endif +#endif + amount = l; + if (mvar[melem[e_ref].elemRef].cType EQ 'X') + bf_readBitChunk (l, globs); + else + bf_readBits (l, globs); + } + else + { + amount = repeat; + if (len_l) + { + if (l > 0) + { + cdc_decodeElemvalue (e_ref, &amount, globs); + } + else + { + amount = 0; + } + } + else + { + if (melem[e_ref].codingType != CCDTYPE_GSM2_T) + cdc_decodeElemvalue (e_ref, &amount, globs); + } + } + +#ifdef DYNAMIC_ARRAYS + /* + * Restore globs->pstruct for possible use below + */ + if (old_pstruct NEQ NULL) { + globs->pstruct = old_pstruct; + } +#endif + + if (amount NEQ repeat AND is_variable) + { + /* + * If the number of decoded elements is not equal to the given + * repeat value, because the bitstream or the IE ended, + * store the new c_xxx value. + */ + globs->pstructOffs = melem[e_ref].structOffs; + + if (melem[e_ref].optional) + globs->pstructOffs++; + + globs->pstruct[globs->pstructOffs] = (UBYTE) amount; + + if (melem[e_ref].repType NEQ 'i') + { + /* + * if this element is not of the repeat style 'interval' + * ([X..Y] where X and Y are constants) we have to generate + * an ccd error because some outstanding repeats are missing. + */ + ccd_setError (globs, ERR_MAND_ELEM_MISS, + CONTINUE, + (USHORT) -1); + } + } + + if (asn1 AND globs->numEOCPending AND !bf_endOfBitstream(globs)) + { + UBYTE T = bf_decodeByteNumber (8, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "looking for EOC decoding 8 bits T = (%x)", T); +#endif + + if (T EQ 0) + { +#ifdef DEBUG_CCD + TRACE_CCD (globs, "First EOC octet found"); +#endif + + if (globs->iei_ctx[globs->ccd_recurs_level].EOCPending) + { +#ifdef DEBUG_CCD + TRACE_CCD (globs, "End of ASN1 TLV"); +#endif + /* + * Skip the second EOC octet. + */ + bf_incBitpos (8, globs); + globs->iei_ctx[globs->ccd_recurs_level].EOCPending = FALSE; + globs->numEOCPending--; + } + else + { + /* + * The read first EOC octet belongs to an ASN1 TLV of a + * higher recursion level. Let it be read and evalauted later + * again for that IE. + */ + bf_setBitpos (globs->bitpos-8, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "End of higer level ASN1 TLV"); + TRACE_CCD (globs, "Decrementing bitpos by 8 to %d", globs->bitpos); +#endif + endOfComposition = TRUE; + } + } + else + { + if (globs->iei_ctx[globs->ccd_recurs_level].EOCPending) + { + /* + * EOC element is pending but not found. + */ + ccd_setError (globs, ERR_EOC_TAG_MISSING, + BREAK, + (USHORT) T, + globs->bitpos-8, + (USHORT) -1); + + bf_setBitpos (globs->bitpos-8, globs); + } + else + { + /* + * normal TAG leave it in the bitstream + */ +#ifdef DEBUG_CCD + TRACE_CCD (globs, "Normal TAG - Decrementing bitpos by 8 to %d", globs->bitpos); +#endif + bf_setBitpos (globs->bitpos-8, globs); + } + } + } + + if (len_l) + { + if (!asn1) + { + if (globs->bitpos > tmp_maxBP) + { + ccd_recordFault (globs, ERR_ELEM_LEN, CONTINUE, (USHORT) e_ref, globs->pstruct + globs->pstructOffs); + } + else + { + /* + * set the bitpos to the end of the LV or TLV element + */ + bf_setBitpos (tmp_maxBP, globs); + } + } + + /* + * set the maxBitpos to the next octet boundary if the + * last non-spare IE does not end at an octet boundary. + * This is necessary for avoiding an early end of decoding. + */ +/* + globs->maxBitpos = globs->buflen; +*/ + globs->maxBitpos = act_maxBP; + } + + return endOfComposition; +} +#endif /* !RUN_FLASH */ + +#ifndef RUN_FLASH +/* Attention for RUN_...: static function */ +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : cdc_skipElem | ++--------------------------------------------------------------------+ + + PURPOSE : Skip an element referenced by eRef. This function + perform a decoding of this element, but not into + the target C-Structure. A dummy C-Structure is used + instead. + The complete decoding is necesary, because there is + no information about the length of this element. + B.t.w. for mandatory elements with fixed length, we can + calculate the length, for optional elements or for + variable sized arrays or bitbuffers it is impossible + without decoding the entire element. +*/ + +static void cdc_skipElem (const ULONG e_ref, const ULONG len_l, T_CCD_Globs *globs) +{ + UBYTE *ActStructAddr; + U32 ActStructOffs; + +#ifdef DEBUG_CCD + TRACE_CCD (globs, "skipping element %d", + melem[e_ref].elemRef); +#endif + + ActStructAddr = globs->pstruct; + ActStructOffs = globs->pstructOffs; + + globs->pstruct = dummy; + globs->pstructOffs = 0; + + cdc_tagged_LV_decode (e_ref, 1, len_l, globs); + + globs->pstruct = ActStructAddr; + globs->pstructOffs = ActStructOffs; +} +#endif /* !RUN_FLASH */ + +#ifndef RUN_FLASH +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : cdc_tlv_decode | ++--------------------------------------------------------------------+ + + PURPOSE : Decoding of the T-components of T TV and TLV typed + information elements. The len determines the + length of the T component. This function returns the + index (reference) of the rigth element. If the + iei is not known in this composition (msg or submsg) + an error handling is done and NO_REF is returned. + +*/ + +SHORT cdc_tlv_decode (const ULONG c_ref, + const ULONG e_ref, + const T_TLV_SORT *tlv_inf, + T_CCD_Globs *globs) +{ + ULONG repeat, max_rep; + ULONG ie_amount, l, len_l, len_t, t; + BOOL is_variable, nonTagged, limitSearch=FALSE; + UBYTE CR=FALSE; + SHORT IdxOffset = 0; + int ieTableIdx; + BOOL asn1, non_std_tag; + SHORT ret; + ULONG cix_ref, num_prolog_steps, prolog_step_ref; + /* .../src/linux/include/asm/current.h defines a macro 'current' */ + T_UNKNOWN_TAG *first, *currentTag; + + + /* + * Set the flag for the type of extension which is to expect + * at the end of the message. + */ + globs->SeekTLVExt = TRUE; + + /* Set ref number for calcidx table. */ + cix_ref = melem[e_ref].calcIdxRef; + num_prolog_steps = calcidx[cix_ref].numPrologSteps; + prolog_step_ref = calcidx[cix_ref].prologStepRef; + + /* + * if this element is conditional, check the condition + */ + if (calcidx[cix_ref].numCondCalcs NEQ 0 + AND ! ccd_conditionOK (e_ref, globs)) + return 1; + + len_t = 8; + switch (melem[e_ref].codingType) + { + case CCDTYPE_GSM1_ASN: + asn1 = TRUE; + non_std_tag = FALSE; + len_l = 8; + break; + + case CCDTYPE_GSM5_TV: + case CCDTYPE_GSM5_TLV: + non_std_tag = TRUE; + asn1 = FALSE; + len_l = 8; + break; + + case CCDTYPE_GSM6_TLV: + non_std_tag = FALSE; + asn1 = FALSE; + len_l = 16; + break; + + case CCDTYPE_GSM7_LV: + non_std_tag = FALSE; + asn1 = FALSE; + len_l = 7; + break; + + default: + asn1 = FALSE; + non_std_tag = FALSE; + len_l = 8; + break; + } + + /* + * if this element have a defined Prolog + * we have to process it before decoding the bitstream + */ + if (num_prolog_steps) + { + ccd_performOperations (num_prolog_steps, prolog_step_ref, globs); + } + + if (tlv_inf->gotTag) + { + /* + * tagged element + */ + len_t = 8; + /* + * initialize the iei_table for each new message + */ + if (globs->ccd_recurs_level NEQ globs->last_level) + { + cdc_init_table (c_ref, globs); + globs->TagPending = FALSE; + globs->SequenceError = FALSE; + globs->last_level = globs->ccd_recurs_level; + } + + /* + * calculate the index into the ieTable for this element + */ + ieTableIdx = (int)(e_ref - globs->iei_ctx[globs->ccd_recurs_level].melemStart); + + if (globs->TagPending) + { + /* + * if we previously read a t value and does not processed it + * get this pending tag. + */ + t = (ULONG) globs->PendingTag; + globs->TagPending = FALSE; + } + else + { + /* + * read the information element identifier out of the bitstream. + * If the first bit (MSBit) of the t-component is set, it is + * a Tag of a TYPE1 or TYPE2 element. + */ + + t = (ULONG) bf_decodeByteNumber (8, globs); + + + + if (!asn1 AND !non_std_tag AND (t & 0x80) EQ 0x80 AND (t & 0xA0) NEQ 0xA0) + { + ULONG Tag4 = t & 0xf0; + /* + * MSBit is set. We have to check if the Tag value can + * be found as a 4 bit or 8 bit value in the IEI-table. + */ + if (cdc_search_table (ieTableIdx, Tag4, limitSearch, &nonTagged, globs) NEQ -127) + { + /* + * Tag found as a 4 bit value. Decrement the readpointer + * of the bitstream by 4, because we have read out 4 bits + * to much. + */ + bf_setBitpos (globs->bitpos-4, globs); + t = Tag4; + len_t =4; +#ifdef DEBUG_CCD + TRACE_CCD (globs, "4 bit Tag decrementing bitpos by 4 to %d", globs->bitpos); +#endif + } + } + } + +#ifdef DEBUG_CCD + TRACE_CCD (globs, "reading t = 0x%X", t); +#endif + + if (melem[e_ref].codingType EQ CCDTYPE_GSM5_TLV) + { + limitSearch = TRUE; + CR = (UBYTE) (((t & 0x80) EQ 0x80) ? TRUE : FALSE); + t &= 0x7f; + } + + + if (asn1 AND t EQ 0x00) + { + /* + * This is for ASN1 element coding the special + * End Of Component Tag (EOC). The following length must be zero. + */ + bf_setBitpos (globs->bitpos-8, globs); + +#ifdef DEBUG_CCD + TRACE_CCD (globs, "ASN1 End of Component found belongs to higher TLV"); + TRACE_CCD (globs, "leaving this level and decrementing bitpos by 8 to %d", globs->bitpos); +#endif + + return END_OF_COMPOSITION; /* skip the remaining elements in this level */ + } /* asn1 and EOC */ + else + { + if ((IdxOffset = (SHORT) cdc_search_table (ieTableIdx, t, limitSearch, &nonTagged, globs)) == -127) + { + /* + * t (iei) not defined in this composition (msg or submsg) + */ + if (asn1) + { + if (melem[mcomp[c_ref].componentRef + mcomp[c_ref].numOfComponents -1].codingType == CCDTYPE_GSM5_V) + { + /* Restore the old bitposition (before the 'TAG') and return + * IdxOffset to jump to last element of the composition. + * The coding type of this elements is CCDTYPE_GSM5_V + */ + bf_setBitpos (globs->bitpos-8, globs); + IdxOffset = (SHORT)(mcomp[c_ref].numOfComponents - ieTableIdx - 1); + return (IdxOffset); + } + + /* + * for recursive ASN.1 structs it is possible that the foreign + * tag belongs to a upper level composition of element. + * + * + * Restore the old bitposition (before the TAG) and return + * END_OF_COMPOSITION to leave this composition level + */ + bf_setBitpos (globs->bitpos-8, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "Unknown Tag. It may belong to upper ASN.1 comp -> dec. bitpos by 8 to %d", globs->bitpos); +#endif + + return END_OF_COMPOSITION; /* skip the remaining elements in this level */ + } + else if (nonTagged) + { + U16 actBitpos; + actBitpos = globs->bitpos-8; + + if (melem[mcomp[c_ref].componentRef + mcomp[c_ref].numOfComponents -1].codingType == CCDTYPE_GSM5_V && + melem[e_ref].codingType EQ CCDTYPE_GSM5_TLV) + { +#if defined (CCD_TEST) + currentTag = (T_UNKNOWN_TAG *) malloc(sizeof(T_UNKNOWN_TAG)); +#else + currentTag = (T_UNKNOWN_TAG *) D_ALLOC(sizeof(T_UNKNOWN_TAG)); +#endif + first = currentTag; + currentTag->bitpos = globs->bitpos-8; + currentTag->errCode = ERR_NO_MORE_ERROR; + currentTag->next = NULL; + + /* unknown GSM Type TLV -> skip 'l' bytes */ + /* at least 8 bits must remain for following expeceted tagged element */ + while (globs->maxBitpos - 8 - globs->bitpos >= 8) + { + currentTag->bitpos = globs->bitpos-8; + currentTag->tag = (UBYTE) t; + + /* + * Expecting a CCDTYPE_GSM5_TLV type we get an unknown tag with MSB set. + * Store bitpos and t for the application (SAT) for the handling of + * comprehension required elements. + */ + + if (CR) + { // save (ERR_COMPREH_REQUIRED; globs->bitpos-len_t) + currentTag->errCode = ERR_COMPREH_REQUIRED; + } + else + { // save (ERR_IE_NOT_EXPECTED; globs->bitpos-len_t) + currentTag->errCode = ERR_IE_NOT_EXPECTED; + } + + l = (ULONG) bf_decodeByteNumber (8, globs); + bf_incBitpos ((l << 3) , globs); + + t = (ULONG) bf_decodeByteNumber (8, globs); + + limitSearch = TRUE; + CR = (UBYTE) (((t & 0x80) EQ 0x80) ? TRUE : FALSE); + t &= 0x7f; + + if (cdc_search_table (ieTableIdx, t, limitSearch, &nonTagged, globs) != -127) + { + bf_setBitpos (globs->bitpos-8, globs); + // set all ccd Errors + do + { + currentTag = first; + ccd_setError (globs, currentTag->errCode, + CONTINUE, + (USHORT) currentTag->tag, + currentTag->bitpos, + (USHORT) -1); + first = currentTag->next; +#if defined (CCD_TEST) + free(currentTag); +#else + D_FREE(currentTag); +#endif + } + while (first != NULL ); + + return 0; + } + else + { +#if defined (CCD_TEST) + currentTag->next = (T_UNKNOWN_TAG *) malloc(sizeof(T_UNKNOWN_TAG)); +#else + currentTag->next = (T_UNKNOWN_TAG *) D_ALLOC(sizeof(T_UNKNOWN_TAG)); +#endif + currentTag = currentTag->next; + currentTag->next = NULL; + } + } + + do + { + currentTag = first; + first = currentTag->next; +#if defined (CCD_TEST) + free(currentTag); +#else + D_FREE(currentTag); +#endif + } + while (first != NULL ); + } + + /* + * a non tagged element is possible in the message. If the tag + * can not be found, the tag may be the beginning of the non tagged + * element. E.g. rest octetts in sysinfo 4 + * + * Restore the old bitposition (before the TAG) and return 1 to + * go to the next element. + */ + + bf_setBitpos (actBitpos, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "Unknown Tag but mand. IE possible -> dec. bitpos by 8 to %d", globs->bitpos); +#endif + + return 1; + } + + + /* + * Otherwise look if it is a type 1,2 or 4 Element + */ + if ((t & 0x80) EQ 0x80) + { + /* MSBit set -> GSM Type 1 or Type2 -> skip 1 byte */ + /* position already incremented by decoding the TAG value */ + } + /* Just another reason for getting IdxOffset equal to 0. */ + else if (globs->ccd_recurs_level >= MAX_RECURSIONS_PER_MSG) + { + ccd_setError (globs, ERR_INTERNAL_ERROR, BREAK, (USHORT) -1); + } + else + { + /* + * Expecting a CCDTYPE_GSM5_TLV type we get an unknown tag with MSB set. + * Store bitpos and t for the application (SAT) for the handling of + * comprehension required elements. + */ + if (CR) + { + ccd_setError (globs, ERR_COMPREH_REQUIRED, + CONTINUE, + (USHORT) t, + (USHORT) globs->bitpos-len_t, + (USHORT) -1); + } + /* + * Expecting other types than CCDTYPE_GSM5_TLV we get an unknown tag with + * comprehension required bits (5, 6, 7 and 8 of IEI according to GSM0407) + * are set to zero. + * Store bitpos and t for the application for the handling of comprehension + * required elements. + */ + else if ((t & 0x70) EQ 0 AND + melem[e_ref].codingType NEQ CCDTYPE_GSM5_TLV) + { + ccd_setError (globs, ERR_COMPREH_REQUIRED, + CONTINUE, + (USHORT) t, + (USHORT) globs->bitpos-len_t, + (USHORT) -1); + } + /* + * We get an unknown tag and any sort of comprehension required flag is set. + * Store bitpos and t for the application + */ + else + { + ccd_setError (globs, ERR_IE_NOT_EXPECTED, + CONTINUE, + (USHORT) t, + (USHORT) globs->bitpos-len_t, + (USHORT) -1); + } + + /* MSBit cleared -> GSM Type TLV -> skip 'l' bytes */ + if (globs->maxBitpos - globs->bitpos >= 8) + { + l = (ULONG) bf_decodeByteNumber (8, globs); + bf_incBitpos ((l << 3) , globs); + } + else + { + ccd_recordFault (globs, + ERR_ELEM_LEN, + BREAK, + (USHORT) e_ref, + globs->pstruct + globs->pstructOffs); + } + } + + /* + * return 0 -> that means try it again with this actual element + * referenced by e_ref + */ + return 0; + } /* tag not found */ + else + { + T_IEI_TABLE *iei_tbl = &globs->iei_ctx[globs->ccd_recurs_level].iei_table[ieTableIdx]; + /* + * element definition for this iei found + */ + if (IdxOffset NEQ 0) + { + /* + * found index differs from the actual index + */ + globs->TagPending = TRUE; + globs->PendingTag = (UBYTE) t; + + if (!asn1 AND IdxOffset < 0) + { + /* + * found an element in wrong sequence + * (for ASN1 elements the sequence order is not relevant) + */ + ccd_setError (globs, ERR_IE_SEQUENCE, + (UBYTE) ((asn1) ? BREAK : CONTINUE), + (USHORT) t, + (USHORT) globs->bitpos-len_t, + (USHORT) -1); + + globs->SequenceError = TRUE; + } + if (globs->SequenceError) + { + globs->RefBeforeError = (USHORT) e_ref; + } + if (asn1) + { + globs->iei_ctx[globs->ccd_recurs_level].countSkipped += IdxOffset; + } + /* + * skip to the found element + */ + return (IdxOffset); + } + else + { + globs->iei_ctx[globs->ccd_recurs_level].melemLast = (USHORT) e_ref; + + if (iei_tbl->act_amount == 0) + { + /* + * first apearance of this iei + * calculate the upper and lower boundaries and the + * facility of multiple appearance of this tagged element + * in the bitstream. + */ + + /* + * The element is repeatable. There are three kinds of + * repeat definitions valid for standard elements: + * [5] - The element is repeated 5 times. + * [0..5] - The element is repeated 0 to 5 times. + * [a..5] - The element is repeated "the value of a" times. + * + * For tagged elements the following processing is defined: + * + * [5] - The t-Component is decoded + * (maybe the l-Component too (if defined one). + * After this the V-component of the element + * is decoded 5 times. + * + * [0..5] - The t- and maybe the l-Component are decoded. + * After this one V-Component is decoded and it + * is stored as an array entry into + * the target C-Structure. In this case the + * parameter ieIndex gives the index into + * this array, where the element has to + * be written into. + * + * [a..5] - The t- and maybe the l-Component are decoded. + * After this one V-Component is decoded + * "a" times and is stored into the C-Structure + * as an array. + * + */ + switch (melem[e_ref+IdxOffset].repType) + { + case 'i': + /* + * multiapearance of this element. The V-component is + * repeated once + */ + is_variable = ccd_calculateRep (e_ref+IdxOffset, + &repeat, + &max_rep, + globs); + + iei_tbl->max_amount = (UBYTE) max_rep; + iei_tbl->multiple = TRUE; + break; + + case 'v': + case 'b': + default: + /* + * if this element is repeatable, and the number of + * repeats depends on another element, the valid amount + * of this element is 1 and the V-component will be + * repeated. + */ + iei_tbl->max_amount = 1; + iei_tbl->multiple = FALSE; + break; + } + iei_tbl->act_amount = 1; + } + + if (iei_tbl->act_amount <= iei_tbl->max_amount) + { + /* + * process only the max_amount appearances of each element. + * All additional IEs are ignored. + */ + ie_amount = (ULONG)(iei_tbl->act_amount)++; + } + else + { + if (asn1) + { + /* For ASN1 elements the sequence order is not relevant. + * It is possible that the tag belongs to an upper level + * composition of elements. + * Restore the old bitposition (before the TAG) and return + * END_OF_COMPOSITION to leave this composition level + */ + bf_setBitpos (globs->bitpos-8, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "Tag may belong to upper ASN.1 comp -> dec. bitpos by 8 to %d", globs->bitpos); +#endif + + return END_OF_COMPOSITION; /* skip the remaining elements in this level */ + } + else + { + ie_amount = 0; + ccd_setError (globs, ERR_MAX_IE_EXCEED, + CONTINUE, + (USHORT) t, + (USHORT) globs->bitpos-len_t, + (USHORT) -1); + } + } + + /* + * The t-component matches with the defined identifier for + * the actual element definition (e_ref). + */ + + if (globs->SequenceError) + { + globs->SequenceError = FALSE; + + if (asn1) + { + /* For ASN1 elements the sequence order is not relevant. + * It is possible that the tag belongs to an upper level + * composition of elements. + * Restore the old bitposition (before the TAG) and return + * END_OF_COMPOSITION to leave this composition level + */ + bf_setBitpos (globs->bitpos-8, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "Tag may belong to upper ASN.1 comp -> dec. bitpos by 8 to %d", globs->bitpos); +#endif + + return END_OF_COMPOSITION; /* skip the remaining elements in this level */ + } + else + { + /* found an element in wrong sequence */ + + cdc_skipElem (e_ref, (tlv_inf->gotLen ? len_l:0), globs); + return (SHORT)(globs->RefBeforeError - e_ref); + } + } + + /* + * if this element is conditional, check the condition + */ + if (calcidx[cix_ref].numCondCalcs NEQ 0 + AND ! ccd_conditionOK (e_ref, globs)) + { + /* + * if the condition for this element is not valid + * but this element appears in the message, generate + * an error and skip the element + */ + ccd_setError (globs, ERR_IE_NOT_EXPECTED, + CONTINUE, + (USHORT) t, + (USHORT) globs->bitpos-len_t, + (USHORT) -1); + + cdc_skipElem (e_ref, (tlv_inf->gotLen ? len_l:0), globs); + + return 0; + } + + /* + * check for a valid index + */ + if (ie_amount EQ 0) + { + /* + * The max number of repeats are reached + * In this case we must skip this element. + */ + cdc_skipElem (e_ref, (tlv_inf->gotLen ? len_l:0), globs); + + return 0; + } + + + if (iei_tbl->multiple) + { + if (melem[e_ref].elemType NEQ 'S') + { + /* + * Element is not a SPARE + * Setup the offset into the C-structure for this element + */ + globs->pstructOffs = melem[e_ref].structOffs; + } + ret = cdc_tagged_LV_decode (e_ref, ie_amount, + (tlv_inf->gotLen ? len_l:0), globs); + } + else + { + if (melem[e_ref].elemType NEQ 'S') + { /* + * Element is not a SPARE + * Setup the offset into the C-structure for this element + */ + globs->pstructOffs = melem[e_ref].structOffs; + } + ret = cdc_normal_LV_decode (e_ref, + (tlv_inf->gotLen ? len_l:0), globs); + } + globs->SeekTLVExt = TRUE; + iei_tbl->exhausted = TRUE; + + if (ret) + return END_OF_COMPOSITION; + + /* + * if more then one IE of this type are allowed, a ret of 0 + * indicates the calling function (ccd_decodeComposition()) + * to leave the pointer to the actual element definition on + * this element. If the value of ret is greater then 0 the + * calling function will increment the pointer by the value + * of ret. + * cdc_T_decode() has found the expected element definition. + * Go to the next definition or stay at this definition, + * if the occurance of this element is more than one. + */ + if (iei_tbl->act_amount > iei_tbl->max_amount) + { + iei_tbl->act_amount = 0; + } + if (iei_tbl->max_amount > 1) + { + return (0); + } + else + { + if (globs->iei_ctx[globs->ccd_recurs_level].countSkipped) + { + ret = (-1) * (globs->iei_ctx[globs->ccd_recurs_level].countSkipped); + (globs->iei_ctx[globs->ccd_recurs_level].countSkipped) = 0; + return (ret); + } + else + { + return (1); + } + } + } /* IdxOffset == 0 */ + } /* tag found */ + } /* no asn1, no EOC */ + } /* got tag */ + else + { + /* + * element has no t-component, process the l- and V-components + */ + if (melem[e_ref].elemType NEQ 'S') + { /* + * Element is not a SPARE + * Setup the offset into the C-structure for this element + */ + globs->pstructOffs = melem[e_ref].structOffs; + } + ret = cdc_normal_LV_decode (e_ref, len_l, globs) ? END_OF_COMPOSITION : 1; + globs->SeekTLVExt = TRUE; + return ret; + } +} +#endif /* !RUN_FLASH */ + +#ifndef RUN_FLASH +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : cdc_tlv_encode | ++--------------------------------------------------------------------+ + + PURPOSE : if T_len > 0 this function encodes the T-Component of + this element. If L_len > 0 it encodes the number + of bytes uses for this element. After all the function + encodes the V-component referenced by eRef from the + C-Structure (globs->pstruct) at position globs->pstructOffs + into the bitstream. + +*/ + +void cdc_tlv_encode (const ULONG e_ref, + UBYTE lenT, + UBYTE lenL, + T_CCD_Globs *globs) +{ + ULONG posL=0, t_repeat, v_repeat, repeat; + ULONG cSize, startOffset=0; + BOOL multAppear; + U8 *old_pstruct = NULL; + ULONG i; + ULONG cix_ref, num_prolog_steps, prolog_step_ref; + + cix_ref = melem[e_ref].calcIdxRef; + num_prolog_steps = calcidx[cix_ref].numPrologSteps; + prolog_step_ref = calcidx[cix_ref].prologStepRef; + + /* + * If this element is conditional, check the condition. + */ + if (calcidx[cix_ref].numCondCalcs NEQ 0 + AND ! ccd_conditionOK (e_ref, globs)) + return; + + /* + * If this element have a defined Prolog, + * we have to process it before decoding the bit stream. + */ + if (num_prolog_steps) + { + ccd_performOperations (num_prolog_steps, prolog_step_ref, globs); + } + + if (melem[e_ref].elemType NEQ 'S') + { + /* + * Element is not a SPARE. + * Setup the offset into the C-structure for this element. + * In case of pointer types, the pstructOffs must be + * the offset into the memory area pointed to. CCDGEN must + * ensure this holds true. + */ + globs->pstructOffs = melem[e_ref].structOffs; + + if ( ! cdc_isPresent(e_ref, globs) ) + return; + + if (melem[e_ref].repType EQ 'v' OR melem[e_ref].repType EQ 'i') + { + /* + * for variable sized elements read the amount + * of repeats out of the C-Structure (c_xxx). + * If the number of repeats given by the C-Structure + * exceeds the allowed value (maxRepeat) CCD gives a warning! + */ + if (melem[e_ref].maxRepeat > 255) + { + ULONG count = (ULONG) (* (USHORT *)(globs->pstruct + globs->pstructOffs++)); + repeat = MINIMUM (count, (ULONG) melem[e_ref].maxRepeat); + if (repeat < count) + ccd_recordFault (globs, ERR_MAX_REPEAT, CONTINUE, + (USHORT) e_ref, globs->pstruct + globs->pstructOffs); + } + else + { + repeat = (ULONG) MINIMUM (globs->pstruct[globs->pstructOffs], + melem[e_ref].maxRepeat); + if ( repeat < (ULONG) (globs->pstruct[globs->pstructOffs]) ) + ccd_recordFault (globs, ERR_MAX_REPEAT, CONTINUE, (USHORT) e_ref, + globs->pstruct + globs->pstructOffs); + } + + globs->pstructOffs++; + + multAppear = (melem[e_ref].repType EQ 'i'); + } + else + { + /* + * Field of constant length: repType EQ 'c' + * or bit-field allocated with + * given maximum length: repType EQ 'b' (often cType='X') + */ + repeat = (ULONG)((melem[e_ref].repType EQ 'c' + OR melem[e_ref].repType EQ 'b') + ? melem[e_ref].maxRepeat + : 1 ); + multAppear = FALSE; + } + + /* + * Perform pointer dereference for pointer types. + * Also, check optionality for these types. + */ +#ifdef DYNAMIC_ARRAYS + if ((melem[e_ref].elemType >= 'P' AND melem[e_ref].elemType <= 'R') OR + (melem[e_ref].elemType >= 'D' AND melem[e_ref].elemType <= 'F')) + { + U8 *deref_pstruct; + + /* Get pointer value */ + deref_pstruct = *(U8 **)(globs->pstruct + globs->pstructOffs); + + /* + * Strictly speaking the 'D' to 'F' types should not need this + * check (should have returned after the optionality check above), + * but it will catch stray NULL pointers (or uninitialized + * valid flags) + */ + if (ccd_check_pointer(deref_pstruct) != ccdOK) + { + ccd_recordFault (globs, ERR_INVALID_PTR, BREAK, (USHORT) e_ref, + &globs->pstruct[globs->pstructOffs]); + return; + } + + /* + * Pointer not NULL; + * 1. Save old globs->pstruct and assign pointer to globs->pstruct + * as new base. + * 2. Set pstructOffs to 0 (zero) as the next offset will start + * in the new memory area. + */ + old_pstruct = globs->pstruct; + globs->pstruct = deref_pstruct; + globs->pstructOffs = 0; + } +#endif + + /* + * 20010621 MVJ: Dynamic array addition. + * Types 'R' and 'F' point to base types (just as type 'V') and + * read sizes from the same table. + */ + cSize = (ULONG)((melem[e_ref].elemType EQ 'V' +#ifdef DYNAMIC_ARRAYS + OR melem[e_ref].elemType EQ 'R' + OR melem[e_ref].elemType EQ 'F' +#endif + ) ? mvar[melem[e_ref].elemRef].cSize + : mcomp[melem[e_ref].elemRef].cSize + ); + + startOffset = globs->pstructOffs; + } + else + { + repeat = (ULONG)((melem[e_ref].repType EQ 'c') + ? melem[e_ref].maxRepeat + : 1); + + multAppear = FALSE; + + cSize = 0; + } + + if (multAppear AND lenT) + { + /* + * multiple appearance of the repeated element is coded as + * TLV0 TLV1 TLV2 .... + */ + t_repeat = repeat; + v_repeat = 1; + } + else + { + t_repeat = 1; + v_repeat = repeat; + } + + /* + * single appearance of the repeated element is coded as + * TLV0V1V2V3 .... + */ + + for (i=0; i < t_repeat; i++) + { + if (lenT) + { + /* + * encode the T-component + */ + bf_codeByteNumber (lenT, (UBYTE) melem[e_ref].ident, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "encoding %d bits T-value (%x)", lenT, melem[e_ref].ident); +#endif + } + + /* + * if lenL > 0 remember the position of the L-component, because + * we know it after encoding the entire element. for GSM5TLV elements + * it could be necessary to use 2 bytes for the length information. + */ + if (lenL) + { + posL = (ULONG) globs->bitpos; + bf_incBitpos (lenL, globs); +#ifdef DEBUG_CCD + TRACE_CCD (globs, "skipping %d bits for L-value at byte %d.%d", lenL, globs->bytepos, globs->byteoffs); +#endif + } + + if (cSize) + { + /* + * calculate the offset if it is not a spare + */ + globs->pstructOffs = (ULONG)(startOffset + (i * cSize)); + } + + /* + * Encode the value. Keep caution with BER encoding of ASN1 integers. + * All other types can be encoded by a generic function. + */ + if (melem[e_ref].codingType EQ CCDTYPE_GSM1_ASN + AND + melem[e_ref].elemType EQ 'V' + AND melem[e_ref].repType EQ ' ' + ) + { +#ifdef DEBUG_CCD +#ifdef CCD_SYMBOLS + TRACE_CCD (globs, "BER encoding of ASN.1 integer %s", + ccddata_get_alias((USHORT) e_ref, 1)); +#else + TRACE_CCD (globs, "BER encoding of ASN.1 integer; e_ref= %d", melem[e_ref].elemRef); +#endif +#endif + + switch (mvar[melem[e_ref].elemRef].cType) + { + case 'B': bf_writeBits (8, globs); + break; + case 'S': + { + if (*(U16 *) (globs->pstruct+globs->pstructOffs) <= (U16)0xFF) + bf_writeBits (8, globs); + else + bf_writeBits (16, globs); + } + break; + case 'L': + { + U32 tmpVal= *(U32 *) (globs->pstruct+globs->pstructOffs); + + if ( tmpVal <= (U32)0xFF) + bf_writeBits (8, globs); + else if ( tmpVal <= (U32)0xFFFF) + bf_writeBits (16, globs); + else if ( tmpVal <= (U32)0xFFFFFF) + bf_writeBits (24, globs); + else + bf_writeBits (32, globs); + } + break; + case 'X': + { + U16 ValLen= *(U16 *) (globs->pstruct+globs->pstructOffs); + + if ( mvar[melem[e_ref].elemRef].bSize >= ValLen) + bf_writeBitChunk (ValLen, globs); + else + { +#ifdef DEBUG_CCD + TRACE_CCD (globs, "value length (%d) exceeds defined bSize!", ValLen); +#endif + } + + } + break; + } + } + else + { + cdc_encodeElemvalue (e_ref, v_repeat, globs); + } + + /* + * calculate the bitlen if it is an TLV element and write the + * L-value. + */ + + if (lenL) + { + switch (melem[e_ref].codingType) + { + case CCDTYPE_GSM5_TLV: + { + USHORT L = (((USHORT)((globs->bitpos - posL)-lenL)+7) >> 3); + + +#ifdef DEBUG_CCD + TRACE_CCD (globs, "recoding the 8 bit L-value (%d)", L); +#endif + + if (L > 127) + { + /* + * if the length is > 127 we code the first byte to + * 0x81, shift the whole stuff rightwise by 8 and + * encode the length in the next byte (16 bits for L) + */ + bf_rShift8Bit ((USHORT) (posL+8), (USHORT) (L<<3), globs); + bf_incBitpos (8, globs); + bf_recodeByteNumber ((USHORT) posL, lenL, (UBYTE) 0x81, globs); + bf_recodeByteNumber ((USHORT) (posL+8), lenL, (UBYTE) L, globs); + /* + * set the bitpos to a 8 bit aligned position + * corresponding the L value + */ + bf_setBitpos (posL+(L*8)+16, globs); + } + else + { + bf_recodeByteNumber ((USHORT) posL, lenL, (UBYTE) L, globs); + /* + * set the bitpos to a 8 bit aligned position + * corresponding the L value + */ + bf_setBitpos (posL+(L*8)+8, globs); + } + break; + } + + case CCDTYPE_GSM6_TLV: + { + USHORT L = ((USHORT)(((globs->bitpos - posL)-lenL)+7) >> 3); + +#ifdef DEBUG_CCD + TRACE_CCD (globs, "recoding the 16 bit L-value (%d)", L); +#endif + bf_recodeShortNumber ((USHORT)posL, lenL, L, globs); + /* + * set the bitpos to a 8 bit aligned position + * corresponding the L value + */ + bf_setBitpos (posL+(L*8)+16, globs); + break; + } + + case CCDTYPE_GSM7_LV: + { + USHORT L = (USHORT) ((globs->bitpos - posL)-lenL); + +#ifdef DEBUG_CCD + TRACE_CCD (globs, "recoding the 7 bit L-value (bitlength) (%d)", L); +#endif + bf_recodeShortNumber ((USHORT)posL, lenL, L, globs); + + bf_setBitpos (posL+L+7, globs); + break; + } + + default: + { + USHORT L = ((USHORT)(((globs->bitpos - posL)-lenL)+7) >> 3); + +#ifdef DEBUG_CCD + TRACE_CCD (globs, "recoding the 8 bit L-value (%d)", L); +#endif + bf_recodeByteNumber ((USHORT)posL, lenL, (UBYTE) L, globs); + /* + * Set the bitpos to a 8 bit aligned position + * corresponding the L value + */ + bf_setBitpos (posL+(L*8)+8, globs); + break; + } + } + } + } + + /* + * Restore globs->pstruct if overwritten by pointer dereference. + */ + if (old_pstruct) + globs->pstruct = old_pstruct; +} +#endif /* !RUN_FLASH */ + +#ifndef RUN_FLASH +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : cdc_GSM_start | ++--------------------------------------------------------------------+ + + PURPOSE : Initialize the GSM specific codec part for each msg. + +*/ + +void cdc_GSM_start (T_CCD_Globs *globs) +{ + globs->Swap1V_inProgress = FALSE; + globs->last_level = 255; + cdc_init_ctx_table (globs); +} +#endif /* !RUN_FLASH */ + +#ifndef RUN_INT_RAM +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : cdc_isPresent | ++--------------------------------------------------------------------+ + + PURPOSE : For optional elements check the valid-flag in the C-struct. + Spare elements in PER do not have a corresponding valid flag. + In case of Dynamic Arrays: + Postpone optional check for non-code transparent pointer + types ('P', 'Q', 'R'). + For these types, the optional flag is the pointer itself. + These types cannot be checked yet, as the pointer may be + preceeded by a counter octet, a union tag id octet etc. +*/ +U16 cdc_isPresent (const ULONG e_ref, T_CCD_Globs *globs) +{ + if (melem[e_ref].optional) + { +#ifdef DYNAMIC_ARRAYS + if (melem[e_ref].elemType < 'P' OR melem[e_ref].elemType > 'R') + { + if(globs->pstruct[globs->pstructOffs++] == FALSE) + return FALSE; +#ifdef DEBUG_CCD + else if (globs->pstruct [melem[e_ref].structOffs] != TRUE) + { + TRACE_CCD (globs, "Ambiguous value for valid flag!\n...assumed 1 for ccdID=%d", + e_ref); + } +#endif + } + else + { /*If elemType is P, Q or R - check the pointer value*/ + if(*(void**) &globs->pstruct[globs->pstructOffs] == NULL) + return FALSE; + } +#else + if (globs->pstruct[globs->pstructOffs++] == FALSE) + return FALSE; +#ifdef DEBUG_CCD + else if (globs->pstruct [melem[e_ref].structOffs] != TRUE) + { + TRACE_CCD (globs, "Ambiguous value for valid flag!\n...assumed 1 for ccdID=%d", + e_ref); + } +#endif +#endif + } + return TRUE; +} +#endif /* !RUN_INT_RAM */ + +#ifndef RUN_FLASH +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : is_pointer_type | ++--------------------------------------------------------------------+ + + PURPOSE : Return TRUE for pointer elements. + +*/ +BOOL is_pointer_type (const ULONG e_ref) +{ + return ((melem[e_ref].elemType >= 'P' AND melem[e_ref].elemType <= 'R') OR + (melem[e_ref].elemType >= 'D' AND melem[e_ref].elemType <= 'F')); +} +#endif /* !RUN_FLASH */ + +#ifndef RUN_FLASH +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : is_variable_type | ++--------------------------------------------------------------------+ + + PURPOSE : Return TRUE for elements with variable character. + +*/ +BOOL is_variable_type (const ULONG e_ref) +{ + return ((melem[e_ref].elemType == 'F') || ( melem[e_ref].elemType == 'R') || + (melem[e_ref].elemType == 'V')); +} +#endif /* !RUN_FLASH */ + +#ifndef RUN_INT_RAM +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : PER_CommonBegin | ++--------------------------------------------------------------------+ + + PURPOSE : Common settings done by most of the encoding or decoding + functions for UNALIGNED PER (UMTS). + It handles position of pointer to the C-structure, + valid flag for optional elements and length determinant + for array of elements. +*/ +SHORT PER_CommonBegin (const ULONG e_ref, ULONG *max_rep, T_CCD_Globs *globs) +{ + /* + * Set the offset in the C-structure on the value for this element + */ + globs->pstructOffs = melem[e_ref].structOffs; + + /* For optional elements we have already set the valid flag in the + * C-structure while processing ASN1_SEQ. + */ + if ( ! cdc_isPresent(e_ref, globs) ) + return (SHORT)ccdError; + + switch (melem[e_ref].repType) + { + case ' ': + /* + * Element is not an array. + */ + *max_rep = 1; + break; + case 'c': + case 'C': + /* + * Read the size for an array of fixed length. + */ + *max_rep = (ULONG) melem[e_ref].maxRepeat; + break; + case 'j': + case 'J': + { + /* + * Read the size for an array of variable length. + * Read the value of the last encoded element. It is the length + * indicator. + * Hint 1: globs->pstruct[melem[e_ref-1].structOffs is 0, since + * fields of variable length are projected on a COMP made of an + * ASN1_INTEGER for the lenght indicator and the field elements + * (sequences, integers, octets or bits). + * Hint 2: The current version of UMTS does not use length + * indicators larger than 64K. Hence the use of USHORT for repeat. + */ + switch (mvar[melem[e_ref-1].elemRef].cType) + { + case 'B': *max_rep = (ULONG) globs->pstruct[melem[e_ref-1].structOffs]; + break; + case 'S': *max_rep = (ULONG) *(USHORT *) (globs->pstruct+melem[e_ref-1].structOffs); + break; + default: *max_rep = 0; + break; + } + break; + } + default: + ccd_recordFault (globs, ERR_DEFECT_CCDDATA, BREAK, (USHORT) e_ref, + globs->pstruct + globs->pstructOffs); + break; + } + + /* + * There is nothing to be encoded. + */ + if (*max_rep EQ 0) + { + return (SHORT)ccdError; + } + /* + * Check the validity of the lenght information. + */ + else if (melem[e_ref].maxRepeat AND *max_rep > melem[e_ref].maxRepeat) + { + ccd_recordFault (globs, ERR_MAX_REPEAT, CONTINUE, (USHORT) e_ref, + globs->pstruct + globs->pstructOffs); + } + + return (SHORT)ccdOK; +} +#endif /* !RUN_INT_RAM */ + + +#ifdef DYNAMIC_ARRAYS +#ifndef RUN_INT_RAM +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : PER_allocmem | ++--------------------------------------------------------------------+ + + PURPOSE : Allocate memory for pointer types (dynamic array addition) + Returns address of freshly allocated memory + or ccdError in case no memory is available. +*/ +U8 *PER_allocmem(const ULONG e_ref, ULONG repeat, T_CCD_Globs *globs) +{ + /* + * Check for pointer types; allocate memory if necessary. + */ + if ( is_pointer_type(e_ref) ) { + ULONG cSize; + U8 *addr; + + /* + * Find size to allocate. + * Read from mcomp or mvar according to type. + */ + cSize = (ULONG)((melem[e_ref].elemType EQ 'V' OR + melem[e_ref].elemType EQ 'R' + OR melem[e_ref].elemType EQ 'F') + ? mvar[melem[e_ref].elemRef].cSize + : mcomp[melem[e_ref].elemRef].cSize + ); + +#ifdef DEBUG_CCD + TRACE_CCD (globs, "PER_allocmem(): alloc%5d x%5d bytes (type '%c'); " + "elem%5d ('%s')", + repeat, cSize, melem[e_ref].elemType, e_ref, +#ifdef CCD_SYMBOLS + mcomp[melem[e_ref].elemRef].name +#else + "" +#endif + ); +#endif + /* + * Allocate additional memory - append to existing mem chain + */ + + cSize *= repeat; + addr = (U8 *)DP_ALLOC( cSize, globs->alloc_head, DP_NO_FRAME_GUESS); + + /* If no memory, log error and return immediately */ + if (addr EQ NULL) { + ccd_setError (globs, ERR_NO_MEM, + BREAK, + (USHORT) -1); + return (U8 *)ccdError; + } + else + memset (addr, 0, (size_t)cSize); + return addr; + } + return (U8 *)ccdError; +} +#endif /* !RUN_INT_RAM */ + +#ifndef RUN_INT_RAM +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : PER_allocmem_and_update| ++--------------------------------------------------------------------+ + + PURPOSE : Allocate memory for pointer types (dynamic array addition) + Updates global variables after allocation + (globs->pstruct and globs->pstructOffs). + Assumes that these global variables are saved by the + calling function. + Returns ccdOK or ccdError in case no memory is available. +*/ +USHORT PER_allocmem_and_update(const ULONG e_ref, ULONG repeat, T_CCD_Globs *globs) +{ + U8 *addr; + + /* Allocate memory */ + addr = PER_allocmem(e_ref, repeat, globs); + + /* No memory ? */ + if ( addr != (U8 *)ccdError ) { + /* + * Memory allocated; + * 1. Store pointer to freshly allocated memory area in structure + * 2. Initialize pstruct to point to the freshly allocated memory area. + * 3. Initialize pstructOffs to 0 to start decoding at offset 0 + * in the new memory area. + * Assumes that globs->pstruct is saved in the calling function. + */ + *(U8 **)(globs->pstruct + globs->pstructOffs) = addr; + globs->pstruct = addr; + globs->pstructOffs = 0; + return ccdOK; + } else { + /* No memory - Return error */ + return ccdError; + } +} +#endif /* !RUN_INT_RAM */ +#endif + +#ifndef RUN_INT_RAM +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : Read_NormallySmallNonNegativeWholeNr| ++--------------------------------------------------------------------+ + + PURPOSE : Read a normally small non-negative whole number as defined + by ASN.1 PER. Function is used to read elements such as: + a) bit-map field of SEQUENCE extensions, + b) index of CHOICE extension or + c) extension value of extensible INTEGER or ENUMERATED. +*/ +U32 Read_NormallySmallNonNegativeWholeNr (T_CCD_Globs *globs) +{ + U32 value_length=0; + + /* Read the first bit. If set to 0 it means the value is encoded + * in the following five bits. Else read a normally small ...nr. + */ + if (bf_readBit (globs) EQ 0) + { + return ((U32) bf_getBits (6, globs)); + } + else + { + /* + * Do not handle the theoretical case that value length + * needs more than 63 bits. + */ + bf_incBitpos (1, globs); + + /* + * Read the value length first. + * Then use the length to read the value. + */ + value_length = (U32) bf_getBits (6, globs); + return ((U32) bf_getBits (value_length, globs)); + } +} +#endif /* !RUN_INT_RAM */ + +#ifndef RUN_INT_RAM +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : Write_NormallySmallNonNegativeWholeNr| ++--------------------------------------------------------------------+ + + PURPOSE : Write a normally small non-negative whole number as defined + by ASN.1 PER. Function is used to encode elements such as: + a) bit-map field of SEQUENCE extensions, + b) index of CHOICE extension or + c) extension value of extensible INTEGER or ENUMERATED. +*/ +void Write_NormallySmallNonNegativeWholeNr (U32 Value, T_CCD_Globs *globs) +{ + /* For small numbers write 0 in the first bit. + * Then encode that number in the succeeding five bits. + */ + if (Value < 64) + { + bf_writeBit (0, globs); + bf_writeVal (Value, 6, globs); + } + /* + * Encode the number under the assumption that its length is + * given by less than 63 bits. Hence encode also the length as a + * normally small... + */ + else + { + /* Set flag bits: + * 1 means "length determinant encoded before the value itself" + * 0 means "length determinant encoded only in five bits" + */ + bf_writeVal (2, 2, globs); + bf_writeVal (bitSize[Value], 5, globs); + + /* Encode the number itself */ + bf_writeVal (Value, bitSize[Value], globs); + } + + return; +} +#endif /* !RUN_INT_RAM */ + +#ifndef RUN_INT_RAM +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : Read_OpenTpye_Length | ++--------------------------------------------------------------------+ + + PURPOSE : Read length of an ASN.1 open type. + Open types are normally found in encoding of + parametrized information objects and extension types. +*/ +U32 Read_OpenTpye_Length (T_CCD_Globs *globs) +{ + U32 Value; + + /* + * Flag bit is 0 for "Value < 128" which means + * "encoding fits in the current octet" + */ + if (bf_readBit (globs) EQ 0) + { + Value = bf_getBits (7, globs); + } + /* + * Flag bits are 10 for 128 "< Value < 16K". + * 1 means "encoding does not fit in the current octet". + * 0 means "encoding needs only one further octet". + */ + else if (bf_readBit (globs) EQ 0) + { + Value = bf_getBits (14, globs); + } + /* Currently no support for bigger values is required. */ + else + { + /* force error detection */ + Value = 0; + } + + return Value; +} +#endif /* !RUN_INT_RAM */ + +#ifndef RUN_INT_RAM +/* ++--------------------------------------------------------------------+ +| PROJECT : CCD (6144) MODULE : CDC_COM | +| STATE : code ROUTINE : Write_OpenTpye_Length | ++--------------------------------------------------------------------+ + + PURPOSE : Write length of an ASN.1 open type. + Open types are normally found in encoding of + parametrized information objects and extension types. +*/ +void Write_OpenTpye_Length (U32 Value, T_CCD_Globs *globs) +{ + + if (Value < 128) + { + bf_writeVal (Value, 8, globs); + } + else if (Value < 0x8000) + { + /* Set flag bits: + * 1 means "encoding does not fit in the current octet" + * 0 means "encoding needs only one further octet" + */ + bf_writeVal (2, 2, globs); + bf_writeVal (Value, 14, globs); + } + /* Currently no support for bigger values is required. */ + else + {} + + return; +} +#endif /* !RUN_INT_RAM */