view src/g23m-gprs/sndcp/sndcp_f.c @ 695:530f71d65c20

uartfax.c: pull from Tourmaline (GTM900 RI output) In addition to the primary intent of bringing in GTM900 RI output support, pulling uartfax.c wholesale from Tourmaline also changes the initial_time argument in the two NU_Create_Timer() calls from 0 to 1. This change is required for the new version of Nucleus used in Tourmaline and Selenite (and apparently also used by TI in LoCosto), and it is harmless (no effect) for the original TCS211 version of Nucleus used in Magnetite. The new philosophical model being adopted is that Tourmaline is our new development head firmware, whereas Magnetite will now be maintained similarly to how Linux maintainers treat stable kernels: changes will be backported from Tourmaline if they are deemed appropriate for stable modem firmware.
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 24 Oct 2020 17:33:10 +0000
parents 219afcfc6250
children
line wrap: on
line source

/*
+-----------------------------------------------------------------------------
|  Project :  GPRS (8441)
|  Modul   :  sndcp_f.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 :  Contains global functions of SNDCP
+-----------------------------------------------------------------------------
*/

#define ENTITY_SNDCP

/*==== INCLUDES =============================================================*/

#include "typedefs.h"    /* to get Condat data types */
#include "vsi.h"        /* to get a lot of macros */
#include "gsm.h"        /* to get a lot of macros */
#include "prim.h"       /* to get the definitions of used SAP and directions */
#include "macdef.h"

#include "dti.h"
#include "sndcp.h"        /* to get the global entity definitions */
#include "sndcp_f.h"       /* to get the functions to access the global arrays*/

#include "sndcp_nup.h"      /* to get nu functions that will be called from
                               sndcp_sig_callback() */
#include "sndcp_ndp.h"      /* to get nu functions that will be called from
                               sndcp_sig_callback() */


#include <string.h>     /* to get memcpy() */


/*==== CONST ================================================================*/

#ifdef SNDCP_TRACE_IP_DATAGRAM
#ifndef CF_FAST_EXEC
static U8 bin_trace_ip_buf[1500];
#endif /* CF_FAST_EXEC */
#endif
/*==== LOCAL VARS ===========================================================*/




#ifdef TI_PS_OP_ICUT_SNDCP

/* PDP_TBR add SNDCP terminal loopback capability */
extern U8 SNDCP_LOOPBACK;
extern BOOL bufFull[SNDCP_NUMBER_OF_NSAPIS];
extern T_DTI2_DATA_IND *saveDti2_data_ind[SNDCP_NUMBER_OF_NSAPIS] ;

#endif /* TI_PS_OP_ICUT_SNDCP */





/*==== PRIVATE FUNCTIONS ====================================================*/

/*==== PUBLIC FUNCTIONS =====================================================*/


/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_ack
+------------------------------------------------------------------------------
| Description : gets nsapi_ack_ra[nsapi]
|
| Parameters  : UBYTE nsapi, BOOL* ack
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_ack(UBYTE nsapi,
                                  BOOL* ack)
{
  TRACE_FUNCTION("sndcp_get_nsapi_ack");
  {
    *ack = sndcp_data->nsapi_ack_ra[nsapi];
  }
}

#endif /* CF_FAST_EXEC */

#ifdef _SNDCP_DTI_2_
/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_direction
+------------------------------------------------------------------------------
| Description : gets nsapi_ack_direction[nsapi]
|               Values: HOME or NEIGHBOR from dti.h.
|
| Parameters  : UBYTE nsapi, BOOL* direction
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_direction(UBYTE nsapi,
                                      U8* direction)
{
  TRACE_FUNCTION("sndcp_get_nsapi_direction");
  {
    *direction = (U8)sndcp_data->nsapi_direction_ra[nsapi];
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_interface
+------------------------------------------------------------------------------
| Description : gets nsapi_interface_ra[nsapi]
|
| Parameters  : UBYTE nsapi, U8 interface
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_interface(UBYTE nsapi,
                                      U8* interfac)
{
  TRACE_FUNCTION("sndcp_get_nsapi_interface");
  {
    *interfac = sndcp_data->nsapi_interface_ra[nsapi];
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_linkid
+------------------------------------------------------------------------------
| Description : gets nsapi_linkid_ra[nsapi]
|
| Parameters  : UBYTE nsapi, ULONG* linkid
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_linkid(UBYTE nsapi,
                                   ULONG* linkid)
{
  TRACE_FUNCTION("sndcp_get_nsapi_linkid");
  {
    *linkid = sndcp_data->nsapi_linkid_ra[nsapi];
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_neighbor
+------------------------------------------------------------------------------
| Description : gets nsapi_neighbor_ra[nsapi]
|
| Parameters  : UBYTE nsapi, UBYTE** neighbor
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_neighbor(UBYTE nsapi,
                                     UBYTE** neighbor)
{
  TRACE_FUNCTION("sndcp_get_nsapi_neighbor");
  {
    *neighbor = sndcp_data->nsapi_neighbor_ra[nsapi];
  }
}
#endif /* CF_FAST_EXEC */

#else /*_SNDCP_DTI_2_*/
/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_direction
+------------------------------------------------------------------------------
| Description : gets nsapi_ack_direction[nsapi]
|               Values: HOME or NEIGHBOR from dti.h.
|
| Parameters  : UBYTE nsapi, BOOL* direction
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_direction(UBYTE nsapi,
                                      BOOL* direction)
{
  TRACE_FUNCTION("sndcp_get_nsapi_direction");
  {
    *direction = sndcp_data->nsapi_direction_ra[nsapi];
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_interface
+------------------------------------------------------------------------------
| Description : gets nsapi_interface_ra[nsapi]
|
| Parameters  : UBYTE nsapi, U8 interface
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_interface(UBYTE nsapi,
                                      U8* interfac)
{
  TRACE_FUNCTION("sndcp_get_nsapi_interface");
  {
    *interfac = sndcp_data->nsapi_interface_ra[nsapi];
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_linkid
+------------------------------------------------------------------------------
| Description : gets nsapi_linkid_ra[nsapi]
|
| Parameters  : UBYTE nsapi, ULONG* linkid
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_linkid(UBYTE nsapi,
                                   ULONG* linkid)
{
  TRACE_FUNCTION("sndcp_get_nsapi_linkid");
  {
    *linkid = sndcp_data->nsapi_linkid_ra[nsapi];
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_neighbor
+------------------------------------------------------------------------------
| Description : gets nsapi_neighbor_ra[nsapi]
|
| Parameters  : UBYTE nsapi, UBYTE** neighbor
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_neighbor(UBYTE nsapi,
                                     UBYTE** neighbor)
{
  TRACE_FUNCTION("sndcp_get_nsapi_neighbor");
  {
    *neighbor = sndcp_data->nsapi_neighbor_ra[nsapi];
  }
}

#endif /* CF_FAST_EXEC */

#endif /*_SNDCP_DTI_2_*/

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_sapi_ack
+------------------------------------------------------------------------------
| Description : gets sapi_ack_ra["index of sapi"]
|
| Parameters  : UBYTE sapi, BOOL* ack
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_sapi_ack(UBYTE sapi,
                                  BOOL* ack)
{
  TRACE_FUNCTION("sndcp_get_sapi_ack");
  {
    UBYTE sapi_index = 0;

    sndcp_get_sapi_index(sapi, &sapi_index);
    *ack = sndcp_data->sapi_ack_ra[sapi_index];
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_sapi_stat
+------------------------------------------------------------------------------
| Description : gets sapi_state_ra[sapi]
|
| Parameters  : UBYTE sapi, UBYTE* stat
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_sapi_state(UBYTE sapi,
                                 USHORT* stat)
{
  TRACE_FUNCTION("sndcp_get_sapi_state");
  {
    UBYTE sapi_index = 0;

    sndcp_get_sapi_index(sapi, &sapi_index);
    *stat = sndcp_data->sapi_state_ra[sapi_index];
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_sapi_index
+------------------------------------------------------------------------------
| Description : gets the index (0, 1, 2, 3) for the given sapi (3, 5, 9, 11).
| This function is used when a sapi number serves as a key for one of the 4
| possible instances of services su and sd.
|
| Parameters  : UBYTE sapi, UBYTE* index
|
+------------------------------------------------------------------------------
*/
/*#if defined(CF_FAST_EXEC) || defined(_SIMULATION_) || \
   defined(SNDCP_2to1) */

GLOBAL void sndcp_get_sapi_index(UBYTE sapi,
                                 UBYTE* index)
{
  TRACE_FUNCTION("sndcp_get_sapi_index");
  {
    if (sapi == 3) {
      *index = 0;
    } else if (sapi == 5) {
      *index = 1;
    } else if (sapi == 9) {
      *index = 2;
    } else if (sapi == 11) {
      *index = 3;
    }
  }
}

/*#endif */ /* CF_FAST_EXEC || _SIMULATION_ || !REL99 || SNDCP_2to1 */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_prio
+------------------------------------------------------------------------------
| Description : sets prio to nsapi_prio_ra[nsapi]
|
| Parameters  : UBYTE nsapi, UBYTE* prio
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_prio(UBYTE nsapi,
                                 UBYTE* prio)
{
  TRACE_FUNCTION("sndcp_get_nsapi_prio");
  {
    *prio = sndcp_data->nsapi_prio_ra[nsapi];
  }
}

#endif /* CF_FAST_EXEC */

#ifdef REL99 
/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_pktflowid
+------------------------------------------------------------------------------
| Description : gets packet flow id form nsapi_pktflowid_ra[nsapi]
|
| Parameters  : UBYTE nsapi, UBYTE* pkt_flow_id
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_pktflowid(U8 nsapi, U16* pkt_flow_id)

{
  TRACE_FUNCTION("sndcp_get_nsapi_pktflowid");
  {
    *pkt_flow_id = sndcp_data->nsapi_pktflowid_ra[nsapi];
  }
}

#endif /* CF_FAST_EXEC */

#endif /*REL99*/

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_qos
+------------------------------------------------------------------------------
| Description : gets nsapi_qos_ra[nsapi]
|
| Parameters  : UBYTE nsapi, T_snsm_qos* qos
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_qos(UBYTE nsapi,
                                 T_snsm_qos* qos)
{
  TRACE_FUNCTION("sndcp_get_nsapi_qos");
  {
    qos->delay = sndcp_data->nsapi_qos_ra[nsapi].delay;
    qos->relclass = sndcp_data->nsapi_qos_ra[nsapi].relclass;
    qos->peak = sndcp_data->nsapi_qos_ra[nsapi].peak;
    qos->preced = sndcp_data->nsapi_qos_ra[nsapi].preced;
    qos->mean = sndcp_data->nsapi_qos_ra[nsapi].mean;
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_sapi
+------------------------------------------------------------------------------
| Description : gets nsapi_sapi_ra[nsapi]
|
| Parameters  : UBYTE nsapi, UBYTE* sapi
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_sapi(UBYTE nsapi,
                                 UBYTE* sapi)
{
  TRACE_FUNCTION("sndcp_get_nsapi_sapi");
  {
    *sapi = sndcp_data->nsapi_sapi_ra[nsapi];
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_state
+------------------------------------------------------------------------------
| Description : gets nsapi_state_ra[nsapi]
|
| Parameters  : UBYTE nsapi, USHORT* state
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_get_nsapi_state(UBYTE nsapi,
                                  USHORT* state)
{
  TRACE_FUNCTION("sndcp_get_nsapi_state");
  {
    *state = sndcp_data->nsapi_state_ra[nsapi];
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_is_nsapi_data_compressed
+------------------------------------------------------------------------------
| Description : If nsapi uses data compression then compressed is set to TRUE,
|               else to FALSE.
|
| Parameters  : UBYTE nsapi, BOOL* compressed
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_is_nsapi_data_compressed(UBYTE nsapi,
                                           BOOL* compressed)
{
  USHORT nsapis = sndcp_data->cia.cur_xid_block.v42.nsapis;

  TRACE_FUNCTION("sndcp_is_nsapi_data_compressed");

  *compressed = (nsapis & (1 << nsapi)) > 0;

}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_is_nsapi_used
+------------------------------------------------------------------------------
| Description : sets b to TRUE if the nsapi is already in use, otherwise to
|               FALSE
|
| Parameters  : UBYTE nsapi, BOOL* b
|
+------------------------------------------------------------------------------
*/
/*#if defined(CF_FAST_EXEC) || defined(_SIMULATION_) || \
   defined (SNDCP_2to1) */

GLOBAL void sndcp_is_nsapi_used(UBYTE nsapi,
                                BOOL* b)
{
  TRACE_FUNCTION("sndcp_is_nsapi_used");
  {
    *b = sndcp_data->nsapi_used_ra[nsapi];
  }
}

/*#endif */ /* CF_FAST_EXEC || _SIMULATION_ || !REL99 || SNDCP_2to1 */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_is_nsapi_header_compressed
+------------------------------------------------------------------------------
| Description : If nsapi uses header compression then compressed is set to TRUE,
|               else to FALSE.
|
| Parameters  : UBYTE nsapi, BOOL* compressed
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_is_nsapi_header_compressed(UBYTE nsapi,
                                             BOOL* compressed)
{
  USHORT nsapis = sndcp_data->cia.cur_xid_block.vj.nsapis;

  TRACE_FUNCTION("sndcp_is_nsapi_header_compressed");

  *compressed = ((nsapis & (1 << nsapi)) > 0) &&
    sndcp_data->cia.cur_xid_block.vj.is_set;

}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_mean_trace
+------------------------------------------------------------------------------
| Description : traces the mean thruput for given
|
| Parameters  : nsapi, direction, ack_mode
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_mean_trace(UBYTE nsapi,
                             UBYTE direction,
                             UBYTE ack_mode,
                             USHORT len)
{
  T_TIME* start_time_ra = NULL;
  T_TIME* cur_time_ra = NULL;
  ULONG* cur_num_ra = NULL;
  ULONG* cur_pac_ra = NULL;

  TRACE_FUNCTION("sndcp_mean_trace");

  if (direction == SNDCP_MEAN_UP) {
    if (ack_mode == SNDCP_MEAN_ACK) {
      start_time_ra = sndcp_data->start_time_uplink_ack;
      cur_time_ra = sndcp_data->cur_time_uplink_ack;
      cur_num_ra = sndcp_data->cur_num_uplink_ack;
      cur_pac_ra = sndcp_data->cur_pac_uplink_ack;
    } else {
      start_time_ra = sndcp_data->start_time_uplink_unack;
      cur_time_ra = sndcp_data->cur_time_uplink_unack;
      cur_num_ra = sndcp_data->cur_num_uplink_unack;
      cur_pac_ra = sndcp_data->cur_pac_uplink_unack;
    }
  } else {
    if (ack_mode == SNDCP_MEAN_ACK) {
      start_time_ra = sndcp_data->start_time_downlink_ack;
      cur_time_ra = sndcp_data->cur_time_downlink_ack;
      cur_num_ra = sndcp_data->cur_num_downlink_ack;
      cur_pac_ra = sndcp_data->cur_pac_downlink_ack;
    } else {
      start_time_ra = sndcp_data->start_time_downlink_ack;
      cur_time_ra = sndcp_data->cur_time_downlink_ack;
      cur_num_ra = sndcp_data->cur_num_downlink_unack;
      cur_pac_ra = sndcp_data->cur_pac_downlink_unack;
    }
  }

  /*
   * Increment number of packets.
   */
  cur_pac_ra[nsapi] ++;


  if (start_time_ra[nsapi] == 0) {
    vsi_t_time(VSI_CALLER  &start_time_ra[nsapi]);
    cur_num_ra[nsapi] += len;
  } else {

    ULONG mean = 0;
    ULONG delta_millis = 0;

    vsi_t_time(VSI_CALLER  &cur_time_ra[nsapi]);
    cur_num_ra[nsapi] += len;

    delta_millis = cur_time_ra[nsapi] -
                   start_time_ra[nsapi];
    if (direction == SNDCP_MEAN_UP) {
      if (delta_millis > 0) {
        mean = (cur_num_ra[nsapi] * 1000) / delta_millis;
        TRACE_EVENT_P4(
          "nsapi %d  up. %d octets in %d ms. %d octets per sec.",
          nsapi,
          cur_num_ra[nsapi],
          delta_millis,
          mean
        );
      } else {
        TRACE_EVENT_P3(
          "nsapi %d  up. %d octets in %d ms.",
          nsapi,
          cur_num_ra[nsapi],
          delta_millis
        );
      }

    } else { /* not (direction == SNDCP_MEAN_UP) */
      if (delta_millis > 0) {
        mean = (cur_num_ra[nsapi] * 1000) / delta_millis;
        TRACE_EVENT_P4(
          "nsapi %d  down. %d octets in %d ms. %d octets per sec.",
          nsapi,
          cur_num_ra[nsapi],
          delta_millis,
          mean
        );
      } else {
        TRACE_EVENT_P3(
          "nsapi %d  down. %d octets in %d ms.",
          nsapi,
          cur_num_ra[nsapi],
          delta_millis
        );
      }
    } /* not (direction == SNDCP_MEAN_UP) */

  }

}

#endif /* CF_FAST_EXEC */


/*
+------------------------------------------------------------------------------
| Function    : sndcp_reset_xid_block
+------------------------------------------------------------------------------
| Description : Resets the given T_XID_BLOCK to default values.
|
| Parameters  : T_XID_BLOCK* xid_block
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_reset_xid_block (T_XID_BLOCK* xid_block)
{
  TRACE_FUNCTION( "sndcp_reset_xid_block" );

  /*
   * Reset all flags for optional compression field parameters.
   */
  xid_block->version_set = FALSE;
  xid_block->v42.is_set = FALSE;
  xid_block->vj.is_set = FALSE;

  xid_block->v42.nsapis_set = FALSE;
  xid_block->v42.p0_set = FALSE;
  xid_block->v42.p1_set = FALSE;
  xid_block->v42.p2_set = FALSE;
  xid_block->vj.nsapis_set = FALSE;
  xid_block->vj.s0_m_1_set = FALSE;
  /*
   * Set fields to default values.
   */
  xid_block->v42.nsapis = SNDCP_NSAPIS_DEFAULT;
  xid_block->v42.p0 = SNDCP_V42_DEFAULT_DIRECTION;
  xid_block->v42.p1 = SNDCP_V42_DEFAULT_P1;
  xid_block->v42.p2 = SNDCP_V42_DEFAULT_P2;

  xid_block->vj.nsapis = SNDCP_NSAPIS_DEFAULT;
  xid_block->vj.s0_m_1 = SNDCP_VJ_DEFAULT_S0_M_1;


} /* sndcp_reset_xid_block() */

#endif /* CF_FAST_EXEC */

#ifdef _SIMULATION_
/*
+------------------------------------------------------------------------------
| Function    : sndcp_sdu_to_desc_list
+------------------------------------------------------------------------------
| Description : copies the given sdu to the given desc_list
|
| Parameters  : T_sdu* sdu,
|               T_desc_list* desc_list
|
+------------------------------------------------------------------------------
*/
#ifdef _SNDCP_DTI_2_
GLOBAL void sndcp_sdu_to_desc_list(T_sdu* sdu, T_desc_list2* desc_list) {
  T_desc2           *desc = NULL;
  T_desc2           *last_desc = NULL;
#else /*_SNDCP_DTI_2_*/
GLOBAL void sndcp_sdu_to_desc_list(T_sdu* sdu, T_desc_list* desc_list) {
  T_desc            *desc = NULL;
  T_desc            *last_desc = NULL;
#endif /*_SNDCP_DTI_2_*/
  USHORT               sdu_index;
  USHORT               length;


  /*
   * Begin at the first relevant octet.
   */
  sdu_index = sdu->o_buf/8;

  /*
   * Initialise descriptor list length.
   */
  desc_list->list_len = 0;


  /*
   * Copy complete SDU to descriptor list using descriptors of max. 10 bytes.
   */
  while (sdu_index < sdu->l_buf / 8)
  {
    /*
     * Calculate length of descriptor data (= length of remaining sdu buffer
     * with a maximum of 10)
     */
    length = (sdu_index + 10 < sdu->l_buf / 8) ?
                      10 : (sdu->l_buf / 8 - sdu_index);

    /*
     * Allocate the necessary size for the data descriptor. The size is
     * calculated as follows:
     * - take the size of a descriptor structure
     * - subtract one because of the array buffer[1] to get the size of
     *   descriptor control information
     * - add number of octets of descriptor data
     */
#ifdef _SNDCP_DTI_2_
    MALLOC (desc, (USHORT)(sizeof(T_desc2) - 1 + length));
#else /*_SNDCP_DTI_2_*/
    MALLOC (desc, (USHORT)(sizeof(T_desc) - 1 + length));
#endif /*_SNDCP_DTI_2_*/
    /*
     * Fill descriptor control information.
     */
    desc->next  = (ULONG)NULL;
    desc->len   = length;
#ifdef _SNDCP_DTI_2_
    desc->offset = 0;
    desc->size = desc->len;
#endif
    /*
     * Add length of descriptor data to list length.
     */
    desc_list->list_len += length;

    /*
     * Copy user data from SDU to descriptor.
     */
    if (length>0)
    {
      memcpy (desc->buffer, &sdu->buf[sdu_index], length);
    }
    sdu_index += length;

    if (last_desc)
    {
      /*
       * Add this descriptor (not the first) to the descriptor list.
       */
      last_desc->next = (ULONG)desc;
    }
    else
    {
      /*
       * Insert first descriptor in descriptor list.
       */
      desc_list->first     = (ULONG)desc;
    }

    /*
     * Store this descriptor for later use.
     */
    last_desc = desc;
  }

 }
#endif /* _SIMULATION_ */



/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_nsapi_ack
+------------------------------------------------------------------------------
| Description : sets nsapi_ack_ra[nsapi] to ack
|
| Parameters  : UBYTE nsapi, BOOL ack
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_set_nsapi_ack(UBYTE nsapi,
                                 BOOL ack)
{
  TRACE_FUNCTION(" sndcp_set_nsapi_ack ");
  {
    sndcp_data->nsapi_ack_ra[nsapi] = ack;
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_nsapi_direction
+------------------------------------------------------------------------------
| Description : sets nsapi_direction_ra[nsapi] to direction
|
| Parameters  : UBYTE nsapi, BOOL direction
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_set_nsapi_direction(UBYTE nsapi,
                                      BOOL direction)
{
  TRACE_FUNCTION(" sndcp_set_nsapi_direction ");
#ifdef _SNDCP_DTI_2_
  if (direction == DTI_CHANNEL_TO_LOWER_LAYER) {
    sndcp_data->nsapi_direction_ra[nsapi] = DTI_CHANNEL_TO_LOWER_LAYER;
  } else {
    sndcp_data->nsapi_direction_ra[nsapi] = DTI_CHANNEL_TO_HIGHER_LAYER;
#else /*_SNDCP_DTI_2_*/
  if (direction == SN_HOME) {
    sndcp_data->nsapi_direction_ra[nsapi] = HOME;
  } else {
    sndcp_data->nsapi_direction_ra[nsapi] = NEIGHBOR;
#endif /*_SNDCP_DTI_2_*/
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_nsapi_interface
+------------------------------------------------------------------------------
| Description : sets nsapi_interface_ra[nsapi] to interfac
|
| Parameters  : UBYTE nsapi, U8 interfac
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_set_nsapi_interface(UBYTE nsapi,
                                      U8 interfac)
{
  TRACE_FUNCTION(" sndcp_set_nsapi_interface ");
  {
    sndcp_data->nsapi_interface_ra[nsapi] = interfac;
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_nsapi_linkid
+------------------------------------------------------------------------------
| Description : sets nsapi_linkid_ra[nsapi] to linkid
|
| Parameters  : UBYTE nsapi, U32 linkid
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_set_nsapi_linkid(UBYTE nsapi,
                                   U32 linkid)
{
  TRACE_FUNCTION(" sndcp_set_nsapi_linkid ");
  {
    sndcp_data->nsapi_linkid_ra[nsapi] = linkid;
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_nsapi_neighbor
+------------------------------------------------------------------------------
| Description : sets nsapi_neighbor_ra[nsapi] to neighbor
|
| Parameters  : UBYTE nsapi, U8* neighbor
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_set_nsapi_neighbor(UBYTE nsapi,
                                     U8* neighbor)
{
  TRACE_FUNCTION(" sndcp_set_nsapi_neighbor ");
  {
    sndcp_data->nsapi_neighbor_ra[nsapi] = neighbor;
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_no_xid
+------------------------------------------------------------------------------
| Description : XID negotiation during each context (default in our
|               implementation) is switched off.
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_no_xid(void)
{
  TRACE_FUNCTION("sndcp_no_xid");
  {
    sndcp_data->always_xid = FALSE;
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_nsapi_prio
+------------------------------------------------------------------------------
| Description : sets nsapi_prio_ra[nsapi] to prio - 1:
|               SNSM prio val is mapped to LL prio val, which is the internal
|               representation.
|
| Parameters  : UBYTE nsapi, UBYTE prio
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_set_nsapi_prio(UBYTE nsapi,
                                 UBYTE prio)
{
  TRACE_FUNCTION("sndcp_set_nsapi_prio");
  {
    sndcp_data->nsapi_prio_ra[nsapi] = prio - 1;
  }
}

#endif /* CF_FAST_EXEC */

#ifdef REL99
/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_nsapi_pktflowid
+------------------------------------------------------------------------------
| Description : sets pktflowid_ra[nsapi] to packet_flow_identifier:
|               SNSM packet flow identifier is mapped to LL pkt_flow_id, which is the internal
|               representation.
|
| Parameters  : UBYTE nsapi, UBYTE packet_flow_identifier
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_set_nsapi_pktflowid(UBYTE nsapi,
                                 U16 packet_flow_identifier)
{
  TRACE_FUNCTION("sndcp_set_nsapi_pktflowid");
  {
    sndcp_data->nsapi_pktflowid_ra[nsapi] = packet_flow_identifier;
  }
}
#endif /* CF_FAST_EXEC */

#endif /*REL99*/

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_nsapi_qos
+------------------------------------------------------------------------------
| Description : sets nsapi_qos_ra[nsapi] to qos
|
| Parameters  : UBYTE nsapi, T_snsm_qos qos
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_set_nsapi_qos(UBYTE nsapi,
                                T_snsm_qos qos)
{
  TRACE_FUNCTION("sndcp_set_nsapi_qos");
  {
    sndcp_data->nsapi_qos_ra[nsapi].delay = qos.delay;
    sndcp_data->nsapi_qos_ra[nsapi].relclass = qos.relclass;
    sndcp_data->nsapi_qos_ra[nsapi].peak = qos.peak;
    sndcp_data->nsapi_qos_ra[nsapi].preced = qos.preced;
    sndcp_data->nsapi_qos_ra[nsapi].mean = qos.mean;
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_nsapi_sapi
+------------------------------------------------------------------------------
| Description : sets nsapi_sapi_ra[nsapi] to sapi
|
| Parameters  : UBYTE nsapi, UBYTE sapi
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_set_nsapi_sapi(UBYTE nsapi,
                                 UBYTE sapi)
{
  TRACE_FUNCTION("sndcp_set_nsapi_sapi");
  {
    sndcp_data->nsapi_sapi_ra[nsapi] = sapi;
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_nsapi_state
+------------------------------------------------------------------------------
| Description : adds stat to nsapi_state_ra[nsapi]
|
| Parameters  : UBYTE nsapi, UBYTE stat
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC
GLOBAL void sndcp_set_nsapi_state(UBYTE nsapi,
                                 USHORT stat)
{
  TRACE_FUNCTION("sndcp_set_nsapi_state");
  {
    sndcp_data->nsapi_state_ra[nsapi] |= stat;
  }
}

#endif /* CF_FAST_EXEC */


/*
+------------------------------------------------------------------------------
| Function    : sndcp_ip_packet_filter
+------------------------------------------------------------------------------
| Description : The function filters TCP and UDP packets on certain ports
|
| Parameters  : T_desc_list2 *desc_list, BOOL *discard
|
+------------------------------------------------------------------------------
*/
#ifdef _SNDCP_DTI_2_
LOCAL void sndcp_ip_packet_filter(T_desc_list2 *desc_list, BOOL *discard)
{
  T_desc2 *desc = (T_desc2 *)desc_list->first;
  UBYTE *pack_hdr = &desc->buffer[desc->offset];
  UBYTE *tcp_hdr = NULL, 
        *udp_hdr = NULL;
  USHORT offset = 0;
  USHORT src_port   = 0;
  USHORT dest_port  = 0;

  TRACE_FUNCTION("sndcp_ip_packet_filter");

  if(desc_list == NULL || desc_list->first == NULL || desc_list->list_len == 0){
    *discard = TRUE; /* discard packet */
    return; 
  }

  offset = (pack_hdr[0] & 0x0f) * 4; /* IP header length in bytes*/
  /* Verify, that the desc has a proper length */
  if(desc->len < (offset + 4)){
    return;
  }

  switch(pack_hdr[9]){
    /* ICMP Protocol */
    case 1:
      *discard = FALSE; /* don't discard ICMP packets */
      /* TRACE_EVENT("INFO IP FILTER: ICMP packet is sent"); */
     return;
    /* TCP Protocol */
    case 6:
      tcp_hdr = &pack_hdr[offset];
      src_port  |= tcp_hdr[0] << 8;
      src_port  |= tcp_hdr[1];
      dest_port |= tcp_hdr[2] << 8;
      dest_port |= tcp_hdr[3];
      if(src_port  == 42   || /* Host Name Server */
         dest_port == 42   || 
         src_port  == 111  || /* Remote Procedure Call */
         dest_port == 111  || 
         ((src_port  > 134) && (src_port  < 140))  || /* NetBIOS */
         ((dest_port > 134) && (dest_port < 140))  || /* NetBIOS */
         src_port  == 445   || /* Microsoft-DS */
         dest_port == 445   || 
         src_port  == 1025  || /* network blackjack */
         dest_port == 1025  || 
         src_port  == 1196  || /* listener RFS */
         dest_port == 1196  || 
         src_port  == 1433  || /* Microsoft-SQL-Server */
         dest_port == 1433  || 
         src_port  == 1434  || /* Microsoft-SQL-Monitor */
         dest_port == 1434   
       ){
        *discard = TRUE; /* discard this TCP packet */
        /*TRACE_EVENT_P2("INFO IP FILTER: TCP packet on dest_port %d, src_port %d is discarded",
                                                                   dest_port, src_port);*/
      } else {                                                             
        *discard = FALSE; /* dont't discard this TCP packet */
        /*TRACE_EVENT_P2("INFO IP FILTER: TCP packet on dest_port %d, src_port %d is sent",
                                                                   dest_port, src_port);*/
      }
     return;
    /* UDP Protocol */
    case 17:
      udp_hdr = &pack_hdr[offset];
      src_port  |= udp_hdr[0] << 8;
      src_port  |= udp_hdr[1];
      dest_port |= udp_hdr[2] << 8;
      dest_port |= udp_hdr[3];
      if(src_port  == 42  || /* Host Name Server */
         dest_port == 42  || 
         src_port  == 67  || /* DHCP BOOTP Protocol Server */
         dest_port == 67  || 
         src_port  == 68  || /* DHCP BOOTP Protocol Client */
         dest_port == 68  || 
         src_port  == 69  || /* Trivial FTP */
         dest_port == 69  || 
         src_port  == 111  || /* Remote Procedure Call */
         dest_port == 111  || 
         src_port  == 135  || /* NetBIOS & co */
         dest_port == 135  || 
         src_port  == 137  || /* NetBIOS & co*/
         dest_port == 137  || 
         src_port  == 138  || /* NetBIOS & co*/
         dest_port == 138  || 
         src_port  == 139  || /* NetBIOS & co*/
         dest_port == 139  || 
         src_port  == 389  || /* LDAP */
         dest_port == 389  ||
         src_port  == 445  || /* Microsoft-DS */
         dest_port == 445  || 
         src_port  == 1023 || /* network blackjack & co */
         dest_port == 1023 || 
         src_port  == 1026 || /* network blackjack & co */
         dest_port == 1026 || 
         src_port  == 1027 || /* network blackjack & co */
         dest_port == 1027 || 
         src_port  == 1028 || /* network blackjack & co */
         dest_port == 1028 || 
         src_port  == 1029 || /* network blackjack & co */
         dest_port == 1029 
       ){
        *discard = TRUE; /* discard this UDP packet */
        /*TRACE_EVENT_P2("INFO IP FILTER: UDP packet on dest_port %d, src_port %d is discarded",
                                                                   dest_port, src_port);*/
      } else {                                                             
        *discard = FALSE; /* dont't discard this UDP packet */
        /*TRACE_EVENT_P2("INFO IP FILTER: UDP packet on dest_port %d, src_port %d is sent",
                                                                   dest_port, src_port);*/
    }
    return;
    default:
      *discard = TRUE; /* discard all other packets */
      TRACE_EVENT_P1("INFO IP FILTER: protocol type %d is discarded", pack_hdr[9]);
      return;
  }
}
#endif /* _SNDCP_DTI_2_ */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_sig_callback
+------------------------------------------------------------------------------
| Description : callback function for dti lib.
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
#ifdef _SNDCP_DTI_2_
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_sig_callback(U8 instance,
                               U8 interfac,
                               U8 channel,
                               U8 reason,
                               T_DTI2_DATA_IND *dti2_data_ind)
{
  T_SN_DATA_REQ* sn_data_req = NULL;
  T_SN_UNITDATA_REQ* sn_unitdata_req = NULL;
  BOOL ack = FALSE;

  TRACE_FUNCTION("sndcp_sig_callback");

  
  switch(reason)
  {
    case DTI_REASON_CONNECTION_OPENED:
      /*
       * set rx and tx state machine of the given interface to idle state
       */
      /*
       * The nsapi is given here with the parameter 'channel'.
       */
      nu_connection_state(channel, TRUE);
      break;
    case DTI_REASON_CONNECTION_CLOSED:
      /*
       * set the given interface to closed state
       */
      break;
    case DTI_REASON_DATA_RECEIVED:
      /*
       * process received data
       */
      /*
       * Trace p_id.
       */



#ifdef TI_PS_OP_ICUT_SNDCP

      /* PDP_TBR added SNDCP terminal loopback */
      if ( SNDCP_LOOPBACK == 1)
      {
        if (bufFull[channel] == FALSE)
        {
          TRACE_EVENT_P1("LOOPBACK len=%d", dti2_data_ind->desc_list2.list_len);

          dti_send_data(sndcp_data->hDTI,
                    instance, // U8 instance,
                    SNDCP_INTERFACE_UNACK, // U8 interface,
                    channel,// U8 channel,
                    dti2_data_ind // T_DTI2_DATA_IND *dti_data_ind)
                    );
        }
        else
        {
          saveDti2_data_ind[channel] = dti2_data_ind;
        }
        return;
      }
      


#endif /* TI_PS_OP_ICUT_SNDCP */





#ifdef SNDCP_TRACE_ALL
      switch (dti2_data_ind->parameters.p_id) {
      case DTI_PID_IP:
        TRACE_EVENT_P2("dti2_data_ind->parameters.p_id: %02x (%s)",
                       dti2_data_ind->parameters.p_id,
                       "DTI_PID_IP");
        break;
      case DTI_PID_CTCP:
        TRACE_EVENT_P2("dti2_data_ind->parameters.p_id: %02x (%s)",
                       dti2_data_ind->parameters.p_id,
                       "DTI_PID_CTCP");
        break;
      case DTI_PID_UTCP:
        TRACE_EVENT_P2("dti2_data_ind->parameters.p_id: %02x (%s)",
                       dti2_data_ind->parameters.p_id,
                       "DTI_PID_UTCP");
        break;
      case DTI_PID_UOS:
        TRACE_EVENT_P2("dti2_data_ind->parameters.p_id: %02x (%s)",
                       dti2_data_ind->parameters.p_id,
                       "DTI_PID_UOS");
        break;
      default:
        TRACE_EVENT_P2("dti2_data_ind->parameters.p_id: %02x (%s)",
                       dti2_data_ind->parameters.p_id,
                       "unknown");


      }
#endif /* SNDCP_TRACE_ALL */
      /*
       * Discard DTI primitive if the config prim "DISCARD" was received
       */
      sndcp_data->nu = &sndcp_data->nu_base[channel];
      if(sndcp_data->nu->discard){
        TRACE_EVENT_P1("INFO DISCARD: UL packet with length %d is discarded",
                                        dti2_data_ind->desc_list2.list_len );
        sndcp_data->nu->discarded_data += dti2_data_ind->desc_list2.list_len;
        PFREE_DESC2(dti2_data_ind);
        dti2_data_ind = NULL;
        break;
      }
      /*
       * If the IP filter is enabled (config prim "IP_FILTER_ON" was received), 
       * filter the packets.
       */
      if(sndcp_data->ip_filter){
        BOOL discard;
        /* Statistics Trace */
        TRACE_EVENT_P3("INFO NSAPI[%d]: sent bytes: %d, discarded bytes: %d",
          channel, sndcp_data->nu->sent_data, sndcp_data->nu->discarded_data);
        sndcp_ip_packet_filter(&dti2_data_ind->desc_list2, &discard);
        if(discard){
          sndcp_data->nu->discarded_data += dti2_data_ind->desc_list2.list_len;
          PFREE_DESC2(dti2_data_ind);
          dti2_data_ind = NULL;
          break;
        } else {
          sndcp_data->nu->sent_data += dti2_data_ind->desc_list2.list_len;
        }
      } 
      /*
       * Copy dti_data_ind to sn_[unit]data_ind and enter nu service the
       * old way.
       */
      sndcp_get_nsapi_ack(channel, &ack);
      if (ack) {
        /*
         * Allocate a "normal" SN_DATA_REQ primitive and copy the data
         * of the test primitive to that one
         */
        MALLOC(sn_data_req, sizeof(T_SN_DATA_REQ));
        sn_data_req->nsapi = channel;
        sn_data_req->p_id = dti2_data_ind->parameters.p_id;
        sn_data_req->desc_list2 = dti2_data_ind->desc_list2;

        /*
         * Free the received dti primitive.
         */
        PFREE (dti2_data_ind);
        dti2_data_ind = NULL;

        nu_sn_data_req(sn_data_req);

      } else {
        /*
         * Allocate a "normal" SN_UNITDATA_REQ primitive and copy the data
         * of the test primitive to that one
         */
        MALLOC(sn_unitdata_req, sizeof(T_SN_UNITDATA_REQ));

        sn_unitdata_req->nsapi = channel;
        sn_unitdata_req->p_id = dti2_data_ind->parameters.p_id;
        sn_unitdata_req->desc_list2 = dti2_data_ind->desc_list2;

        /*
         * Free the received dti 2 primitive.
         */
        PFREE (dti2_data_ind);
        dti2_data_ind = NULL;

        nu_sn_unitdata_req(sn_unitdata_req);

      }

      break;
    case DTI_REASON_TX_BUFFER_FULL:
      /*
       * set tx state machine of the given interface to TX_IDLE state
       */



#ifdef TI_PS_OP_ICUT_SNDCP

     /* PDP_TBR added SNDCP terminal loopback */
      if (SNDCP_LOOPBACK == 1)
      {
        dti_stop(sndcp_data->hDTI,
                    instance,
                    interfac,
                    channel);
        bufFull[channel] = TRUE;
        TRACE_EVENT("SNDCP BUFFER IS FULL");
      }
      
#endif /* TI_PS_OP_ICUT_SNDCP */



      /*
       * Will be ignored.
       */
      break;
    case DTI_REASON_TX_BUFFER_READY:
      /*
       * set tx state machine of the given interface to TX_READY state
       */




#ifdef TI_PS_OP_ICUT_SNDCP
    /* PDP_TBR added SNDCP terminal loopback */
      if ( SNDCP_LOOPBACK == 1)
      {
        dti_start(sndcp_data->hDTI,
                    instance,
                    interfac,
                    channel);
        bufFull[channel] = FALSE;
        TRACE_ERROR("SNDCP BUFFER IS READY");
        if (saveDti2_data_ind[channel] != NULL)
        {
            TRACE_EVENT_P1("LOOPBACK len=%d", dti2_data_ind->desc_list2.list_len);

            dti_send_data(sndcp_data->hDTI,
                      instance, // U8 instance,
                      SNDCP_INTERFACE_UNACK, // U8 interface,
                      channel,// U8 channel,
                      saveDti2_data_ind[channel] // T_DTI2_DATA_IND *dti_data_ind)
                      );
            saveDti2_data_ind[channel] = NULL;

        }
        break;
      }
#endif /* TI_PS_OP_ICUT_SNDCP */




      /*
       * Reaction will be like reaction to SN_GET[UNIT]DATA_REQ.
       */
      nd_dti_buffer_ready(channel);
      break;
    default:
      TRACE_ERROR("sndcp_sig_callback called with undefined reason");
  }
}

#endif /* CF_FAST_EXEC */


#else /*_SNDCP_DTI_2_*/

#ifndef CF_FAST_EXEC

GLOBAL void sndcp_sig_callback(U8 instance,
                               U8 interfac,
                               U8 channel,
                               U8 reason,
                               T_DTI_DATA_IND *dti_data_ind)
{
  TRACE_FUNCTION("sndcp_sig_callback");

  switch(reason)
  {
    case DTI_REASON_CONNECTION_OPENED:
      /*
       * set rx and tx state machine of the given interface to idle state
       */
      /*
       * The nsapi is given here with the parameter 'channel'.
       */
      nu_connection_state(channel, TRUE);
      break;
    case DTI_REASON_CONNECTION_CLOSED:
      /*
       * set the given interface to closed state
       */
      break;
    case DTI_REASON_DATA_RECEIVED:
      /*
       * process received data
       */
      /*
       * Trace p_id.
       */
#ifdef SNDCP_TRACE_ALL
      switch (dti_data_ind->p_id) {
      case DTI_PID_IP:
        TRACE_EVENT_P2("dti_data_ind->p_id: %02x (%s)",
                       dti_data_ind->p_id,
                       "DTI_PID_IP");
        break;
      case DTI_PID_CTCP:
        TRACE_EVENT_P2("dti_data_ind->p_id: %02x (%s)",
                       dti_data_ind->p_id,
                       "DTI_PID_CTCP");
        break;
      case DTI_PID_UTCP:
        TRACE_EVENT_P2("dti_data_ind->p_id: %02x (%s)",
                       dti_data_ind->p_id,
                       "DTI_PID_UTCP");
        break;
      case DTI_PID_FRAME:
        TRACE_EVENT_P2("dti_data_ind->p_id: %02x (%s)",
                       dti_data_ind->p_id,
                       "DTI_PID_FRAME");
        break;
      default:
        TRACE_EVENT_P2("dti_data_ind->p_id: %02x (%s)",
                       dti_data_ind->p_id,
                       "unknown");


      }
#endif /* SNDCP_TRACE_ALL */
      /*
       * Copy dti_data_ind to sn_[unit]data_ind and enter nu service the
       * old way.
       */
      if (interfac == SNDCP_INTERFACE_ACK) {
        /*
         * Allocate a "normal" SN_DATA_REQ primitive and copy the data
         * of the test primitive to that one
         */
        PALLOC_DESC (sn_data_req, SN_DATA_REQ);

        sn_data_req->nsapi = channel;
        sn_data_req->p_id = dti_data_ind->p_id;
        sn_data_req->desc_list = dti_data_ind->desc_list;

        /*
         * Free the received dti primitive.
         */
        PFREE (dti_data_ind);
        dti_data_ind = NULL;

        nu_sn_data_req(sn_data_req);

      } else {
        /*
         * Allocate a "normal" SN_UNITDATA_REQ primitive and copy the data
         * of the test primitive to that one
         */
        PALLOC_DESC (sn_unitdata_req, SN_UNITDATA_REQ);

        sn_unitdata_req->nsapi = channel;
        sn_unitdata_req->p_id = dti_data_ind->p_id;
        sn_unitdata_req->desc_list = dti_data_ind->desc_list;

        /*
         * Free the received test primitive.
         */
        PFREE (dti_data_ind);
        dti_data_ind = NULL;

        nu_sn_unitdata_req(sn_unitdata_req);

      }

      break;
    case DTI_REASON_TX_BUFFER_FULL:
      /*
       * set tx state machine of the given interface to TX_IDLE state
       */
      /*
       * Will be ignored.
       */
      break;
    case DTI_REASON_TX_BUFFER_READY:
      /*
       * set tx state machine of the given interface to TX_READY state
       */
      /*
       * Reaction will be like reaction to SN_GET[UNIT]DATA_REQ.
       */
      nd_dti_buffer_ready(channel);
      break;
    default:
      TRACE_ERROR("sndcp_sig_callback called with undefined reason");
  }
}
#endif /* CF_FAST_EXEC */

#endif /*_SNDCP_DTI_2_*/

/*
+------------------------------------------------------------------------------
| Function    : sndcp_unset_nsapi_state
+------------------------------------------------------------------------------
| Description : subtracts stat from nsapi_state_ra[nsapi]
|
| Parameters  : UBYTE nsapi, UBYTE stat
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_unset_nsapi_state(UBYTE nsapi,
                                 USHORT stat)
{
  TRACE_FUNCTION("sndcp_unset_nsapi_state");
  {
    sndcp_data->nsapi_state_ra[nsapi] &= ~ stat;
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_nsapi_used
+------------------------------------------------------------------------------
| Description : sets nsapi_used_ra[nsapi] to b
|
| Parameters  : UBYTE nsapi, BOOL b
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_set_nsapi_used(UBYTE nsapi,
                                 BOOL b)
{
  TRACE_FUNCTION("sndcp_set_nsapi_used");
  {
    sndcp_data->nsapi_used_ra[nsapi] = b;
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_sapi_ack
+------------------------------------------------------------------------------
| Description : sets sapi_ack_ra[sapi] to ack
|
| Parameters  : UBYTE sapi, BOOL ack
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_set_sapi_ack(UBYTE sapi,
                                 BOOL ack)
{
  TRACE_FUNCTION(" sndcp_set_sapi_ack ");
  {
    UBYTE sapi_index = 0;

    sndcp_get_sapi_index(sapi, &sapi_index);
    sndcp_data->sapi_ack_ra[sapi_index] = ack;
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_snsm_qos_to_ll_qos
+------------------------------------------------------------------------------
| Description : transfers an snsm_qos to an ll_qos
|
| Parameters  : T_snsm_qos, T_ll_qos*
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_snsm_qos_to_ll_qos(T_snsm_qos snsm_qos,
                                     T_ll_qos* ll_qos)
{
  TRACE_FUNCTION("sndcp_snsm_qos_to_ll_qos");
  {
    ll_qos->delay = snsm_qos.delay;
    ll_qos->relclass = snsm_qos.relclass;
    ll_qos->peak = snsm_qos.peak;
    ll_qos->preced = snsm_qos.preced;
    ll_qos->mean = snsm_qos.mean;
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_sapi_state
+------------------------------------------------------------------------------
| Description : adds stat to sapi_state_ra[sapi] bitwise
|
| Parameters  : UBYTE sapi, UBYTE stat
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_set_sapi_state(UBYTE sapi,
                                 USHORT stat)
{
  TRACE_FUNCTION(" sndcp_set_sapi_state ");
  {
    UBYTE sapi_index = 0;
    sndcp_get_sapi_index(sapi, &sapi_index);
    sndcp_data->sapi_state_ra[sapi_index] |= stat;
  }
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_unset_sapi_state
+------------------------------------------------------------------------------
| Description : subtracts stat from sapi_state_ra[sapi] bitwise
|
| Parameters  : UBYTE sapi, UBYTE stat
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_unset_sapi_state(UBYTE sapi,
                                   USHORT stat)
{
  TRACE_FUNCTION(" sndcp_unset_sapi_state ");
  {
    UBYTE sapi_index = 0;
    sndcp_get_sapi_index(sapi, &sapi_index);
    sndcp_data->sapi_state_ra[sapi_index] &= ~ stat;
  }
}

#endif /* CF_FAST_EXEC */

#ifdef FLOW_TRACE
/*
+------------------------------------------------------------------------------
| Function    : sndcp_trace_flow_control
+------------------------------------------------------------------------------
| Description : traces flow control
|
| Parameters  : UBYTE entity, UBYTE uplink, UBYTE sent, BOOL close
|
+------------------------------------------------------------------------------
*/
/*
 * 0 GRR
 * 1 LLC
 * 2 SNDCP
 * 3 PPP
 * 4 UART
 */

/*
#define FLOW_TRACE_GRR    0
#define FLOW_TRACE_LLC    1
#define FLOW_TRACE_SNDCP  2
#define FLOW_TRACE_PPP    3
#define FLOW_TRACE_UART   4

direction of data transfer

#define FLOW_TRACE_UP     0
#define FLOW_TRACE_DOWN   1

is sap sitting on top of entity or is lower entity sap used?

#define FLOW_TRACE_TOP    0
#define FLOW_TRACE_BOTTOM 1
*/


#ifndef CF_FAST_EXEC

GLOBAL void sndcp_trace_flow_control(UBYTE entity, UBYTE transfer, UBYTE position, BOOL opened)
{
  TRACE_FUNCTION(" sndcp_trace_flow_control ");
#ifdef SNDCP_TRACE_ALL
  TRACE_EVENT_P4("sndcp_trace_flow_control[%d][%d][%d] = %d",
                 entity,
                 transfer,
                 position,
                 opened);
#endif
  {
    sndcp_data->flow_control_ra[entity][transfer][position] = opened;
  }
}

#endif /* CF_FAST_EXEC */

#endif /* FLOW_TRACE */


#ifdef _SNDCP_DTI_2_

#ifdef SNDCP_TRACE_ALL

/*
+------------------------------------------------------------------------------
| Function    : sndcp_trace_desc_list3_content
+------------------------------------------------------------------------------
| Description : traces content of a desc3 descriptor list
|
| Parameters  : desc_list3 descriptor list
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_trace_desc_list3_content(T_desc_list3 desc_list3)
{
  U16 current_pos = 0;  /*  */
  U16 data_len = 0;     /* The length of the data to be traced including data offset */
  U8* p_data = NULL;    /* Pointer to byte data element */
  T_desc3* p_desc3 = (T_desc3*)desc_list3.first; /* Pointer to the actual desc3 descriptor element */

  while(p_desc3 != NULL)
  {
    current_pos = p_desc3->offset; /* In case it is the sndcp header allocation, ENCODE_OFFSET has been considered*/
    p_data = (U8*)p_desc3->buffer;
    data_len = current_pos + p_desc3->len; /* p_desc3->len is the total allocation length for sndcp header description */
    while(current_pos <= data_len)
    {
      TRACE_EVENT_P1
        ("%02x",
          p_data[current_pos]
        );
      current_pos ++;
    }

    p_desc3 = (T_desc3*)p_desc3->next;
  }
}

#endif /* CF_FAST_EXEC */

#endif /* SNDCP_TRACE_ALL */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_cl_desc2_attach
+------------------------------------------------------------------------------
| Description : This function attaches a decriptor list to already allocated
|               memory. There is no return value. In case an attempt is made
|               to attach to freed or invalid memory, then the FRAME generates
|               a trace SYSTEM ERROR. This function does not allocate any new
|               memory.
|
| Parameters  : T_desc2* pointer to desc2 descriptor.
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

void sndcp_cl_desc2_attach(T_desc2* p_desc2)
{

  MATTACH(p_desc2);

}

#endif /* CF_FAST_EXEC */
/*
+------------------------------------------------------------------------------
| Function    : sndcp_cl_desc3_free
+------------------------------------------------------------------------------
| Description : Frees the descriptor connected to the desc3 descriptor. This
|               free will when applicable cause the frame to decrease a
|               connected counter attached to the allocation or really free
|               the memory in case the counter is zero.
|
| Parameters  : T_desc3* pointer to desc3 descriptor.
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

void sndcp_cl_desc3_free(T_desc3* p_desc3)
{

  MFREE(p_desc3->buffer);
  p_desc3->buffer = NULL;
}

#endif /* CF_FAST_EXEC */

#endif /* _SNDCP_DTI_2_ */


#ifdef SNDCP_TRACE_ALL

/*
+------------------------------------------------------------------------------
| Function    : sndcp_trace_sdu
+------------------------------------------------------------------------------
| Description : traces content of one sdu
|
| Parameters  : pointer to sdu
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_trace_sdu(T_sdu* sdu)
{

  USHORT pos = sdu->o_buf >> 3;
  USHORT  frame_len = (sdu->l_buf + 7) / 8;


  TRACE_FUNCTION("sndcp_trace_sdu");

  while(pos < (frame_len + (sdu->o_buf >> 3)))
  {
    if (pos + 8 <= (frame_len + (sdu->o_buf >> 3))) {
      TRACE_EVENT_P8
        ("%02x %02x %02x %02x %02x %02x %02x %02x",
          sdu->buf[pos],
          sdu->buf[pos + 1],
          sdu->buf[pos + 2],
          sdu->buf[pos + 3],
          sdu->buf[pos + 4],
          sdu->buf[pos + 5],
          sdu->buf[pos + 6],
          sdu->buf[pos + 7]
        );
      pos += 8;
    } else if (pos + 7 <= (frame_len + (sdu->o_buf >> 3))){
      TRACE_EVENT_P7
        ("%02x %02x %02x %02x %02x %02x %02x",
          sdu->buf[pos],
          sdu->buf[pos + 1],
          sdu->buf[pos + 2],
          sdu->buf[pos + 3],
          sdu->buf[pos + 4],
          sdu->buf[pos + 5],
          sdu->buf[pos + 6]
        );
      pos += 7;
    } else if (pos + 6 <= (frame_len + (sdu->o_buf >> 3))){
      TRACE_EVENT_P6
        ("%02x %02x %02x %02x %02x %02x",
          sdu->buf[pos],
          sdu->buf[pos + 1],
          sdu->buf[pos + 2],
          sdu->buf[pos + 3],
          sdu->buf[pos + 4],
          sdu->buf[pos + 5]
        );
      pos += 6;
    } else if (pos + 5 <= (frame_len + (sdu->o_buf >> 3))){
      TRACE_EVENT_P5
        ("%02x %02x %02x %02x %02x",
          sdu->buf[pos],
          sdu->buf[pos + 1],
          sdu->buf[pos + 2],
          sdu->buf[pos + 3],
          sdu->buf[pos + 4]
        );
      pos += 5;
    } else if (pos + 4 <= (frame_len + (sdu->o_buf >> 3))){
      TRACE_EVENT_P4
        ("%02x %02x %02x %02x",
          sdu->buf[pos],
          sdu->buf[pos + 1],
          sdu->buf[pos + 2],
          sdu->buf[pos + 3]
        );
      pos += 4;
    } else if (pos + 3 <= (frame_len + (sdu->o_buf >> 3))){
      TRACE_EVENT_P3
        ("%02x %02x %02x",
          sdu->buf[pos],
          sdu->buf[pos + 1],
          sdu->buf[pos + 2]
        );
      pos += 3;
    } else if (pos + 2 <= (frame_len + (sdu->o_buf >> 3))){
      TRACE_EVENT_P2
        ("%02x %02x",
          sdu->buf[pos],
          sdu->buf[pos + 1]
        );
      pos += 2;
    } else if (pos + 1 <= (frame_len + (sdu->o_buf >> 3))){
      TRACE_EVENT_P1
        ("%02x",
          sdu->buf[pos]
        );
      pos++;
    }

  }
}

#endif /* CF_FAST_EXEC */


#endif /* SNDCP_TRACE_ALL */

#ifdef  SNDCP_TRACE_BUFFER

/*
+------------------------------------------------------------------------------
| Function    : sndcp_trace_desc_list
+------------------------------------------------------------------------------
| Description : traces content of one desc_list
|
| Parameters  : pointer to desc_list
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

#ifdef _SNDCP_DTI_2_
GLOBAL void sndcp_trace_desc_list(T_desc_list2* desc_list)
{
#else /*_SNDCP_DTI_2_*/
GLOBAL void sndcp_trace_desc_list(T_desc_list* desc_list)
{
#endif /*_SNDCP_DTI_2_*/
  USHORT  frame_len = desc_list->list_len;
#ifdef _SNDCP_DTI_2_
  T_desc2* desc = (T_desc2*)desc_list->first;
  USHORT  desc_pos  = desc->offset;
  USHORT  desc_end  = desc->len + desc->offset;
#else /*_SNDCP_DTI_2_*/
  T_desc* desc = (T_desc*)desc_list->first;
  USHORT  desc_pos = 0;
  USHORT  desc_end  = desc->len;
#endif /*_SNDCP_DTI_2_*/
  USHORT  list_pos = 0;

  TRACE_FUNCTION("sndcp_trace_desc_list");

  while(list_pos < frame_len)
  {
    if (desc != NULL) {
      if (desc_pos >= desc_end) {
#ifdef _SNDCP_DTI_2_
        desc = (T_desc2*)desc->next;
        desc_pos = desc->offset;
        desc_end = desc->len + desc->offset;
#else /*_SNDCP_DTI_2_*/
        desc = (T_desc*)desc->next;
        desc_pos = 0;
        desc_end = desc->len;
#endif /*_SNDCP_DTI_2_*/
      }
    }
    if (desc == NULL) {
      return;
    }
    if (desc_pos + 8 <= desc_end) {
      TRACE_EVENT_P8 ("%02x %02x %02x %02x %02x %02x %02x %02x ",
                      desc->buffer[desc_pos],
                      desc->buffer[desc_pos + 1],
                      desc->buffer[desc_pos + 2],
                      desc->buffer[desc_pos + 3],
                      desc->buffer[desc_pos + 4],
                      desc->buffer[desc_pos + 5],
                      desc->buffer[desc_pos + 6],
                      desc->buffer[desc_pos + 7]
                     );
      list_pos+= 8;
      desc_pos+= 8;
    } else if (desc_pos + 7 <= desc_end) {
      TRACE_EVENT_P7 ("%02x %02x %02x %02x %02x %02x %02x ",
                      desc->buffer[desc_pos],
                      desc->buffer[desc_pos + 1],
                      desc->buffer[desc_pos + 2],
                      desc->buffer[desc_pos + 3],
                      desc->buffer[desc_pos + 4],
                      desc->buffer[desc_pos + 5],
                      desc->buffer[desc_pos + 6]
                     );
      list_pos+= 7;
      desc_pos+= 7;
    } else if (desc_pos + 6 <= desc_end) {
      TRACE_EVENT_P6 ("%02x %02x %02x %02x %02x %02x ",
                      desc->buffer[desc_pos],
                      desc->buffer[desc_pos + 1],
                      desc->buffer[desc_pos + 2],
                      desc->buffer[desc_pos + 3],
                      desc->buffer[desc_pos + 4],
                      desc->buffer[desc_pos + 5]
                     );
      list_pos+= 6;
      desc_pos+= 6;
    } else if (desc_pos + 5 <= desc_end) {
      TRACE_EVENT_P5 ("%02x %02x %02x %02x %02x ",
                      desc->buffer[desc_pos],
                      desc->buffer[desc_pos + 1],
                      desc->buffer[desc_pos + 2],
                      desc->buffer[desc_pos + 3],
                      desc->buffer[desc_pos + 4]
                     );
      list_pos+= 5;
      desc_pos+= 5;
    } else if (desc_pos + 4 <= desc_end) {
      TRACE_EVENT_P4 ("%02x %02x %02x %02x ",
                      desc->buffer[desc_pos],
                      desc->buffer[desc_pos + 1],
                      desc->buffer[desc_pos + 2],
                      desc->buffer[desc_pos + 3]
                     );
      list_pos+= 4;
      desc_pos+= 4;
    } else if (desc_pos + 3 <= desc_end) {
      TRACE_EVENT_P3 ("%02x %02x %02x ",
                      desc->buffer[desc_pos],
                      desc->buffer[desc_pos + 1],
                      desc->buffer[desc_pos + 2]
                     );
      list_pos+= 3;
      desc_pos+= 3;
    } else if (desc_pos + 2 <= desc_end) {
      TRACE_EVENT_P2 ("%02x %02x ",
                      desc->buffer[desc_pos],
                      desc->buffer[desc_pos + 1]
                     );
      list_pos+= 2;
      desc_pos+= 2;
    } else if (desc_pos + 1 <= desc_end) {
      TRACE_EVENT_P1 ("%02x ",
                      desc->buffer[desc_pos]
                     );
      list_pos++;
      desc_pos++;
    }

    /* break tracing if payload shall not be traced*/
    if(!sndcp_data->trace_ip_datagram && (list_pos >= 40))
      break;

  } /* while(list_pos < frame_len) */

}

#endif /* CF_FAST_EXEC */

#endif /* SNDCP_TRACE_BUFFER */



#ifdef _SNDCP_MEAN_TRACE_
/*
+------------------------------------------------------------------------------
| Function    : sndcp_sn_count_req
+------------------------------------------------------------------------------
| Description : reaction to prim SN_COUNT_REQ
|
| Parameters  : primitive payload
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sndcp_sn_count_req(T_SN_COUNT_REQ* sn_count_req)
{
  TRACE_FUNCTION("sndcp_sn_count_req");

  {
    BOOL ack = FALSE;
    PALLOC(sn_count_cnf, SN_COUNT_CNF);

    sn_count_cnf->nsapi = sn_count_req->nsapi;

    sndcp_get_nsapi_ack(sn_count_req->nsapi, &ack);
    if (ack) {
      sn_count_cnf->octets_uplink =
        sndcp_data->cur_num_uplink_ack[sn_count_req->nsapi];
      sn_count_cnf->octets_downlink =
        sndcp_data->cur_num_downlink_ack[sn_count_req->nsapi];

      sn_count_cnf->packets_uplink =
        sndcp_data->cur_pac_uplink_ack[sn_count_req->nsapi];
      sn_count_cnf->packets_downlink =
        sndcp_data->cur_pac_downlink_ack[sn_count_req->nsapi];

#ifdef SNDCP_UPM_INCLUDED 
      if (sn_count_req->reset == NAS_RESET_YES) {
#else 
      if (sn_count_req->reset == SN_RESET_YES) { 
#endif   /*SNDCP_UPM_INCLUDED*/
        sndcp_data->cur_num_uplink_ack[sn_count_req->nsapi] = 0;
        sndcp_data->cur_num_downlink_ack[sn_count_req->nsapi] = 0;
        sndcp_data->cur_pac_uplink_ack[sn_count_req->nsapi] = 0;
        sndcp_data->cur_pac_downlink_ack[sn_count_req->nsapi] = 0;
      }

    } else {

      sn_count_cnf->octets_uplink =
        sndcp_data->cur_num_uplink_unack[sn_count_req->nsapi];
      sn_count_cnf->octets_downlink =
        sndcp_data->cur_num_downlink_unack[sn_count_req->nsapi];

      sn_count_cnf->packets_uplink =
        sndcp_data->cur_pac_uplink_unack[sn_count_req->nsapi];
      sn_count_cnf->packets_downlink =
        sndcp_data->cur_pac_downlink_unack[sn_count_req->nsapi];

#ifdef SNDCP_UPM_INCLUDED 
      if (sn_count_req->reset == NAS_RESET_YES) {
#else 
      if (sn_count_req->reset == SN_RESET_YES) {
#endif  /*SNDCP_UPM_INCLUDED*/
        sndcp_data->cur_num_uplink_unack[sn_count_req->nsapi] = 0;
        sndcp_data->cur_num_downlink_unack[sn_count_req->nsapi] = 0;
        sndcp_data->cur_pac_uplink_unack[sn_count_req->nsapi] = 0;
        sndcp_data->cur_pac_downlink_unack[sn_count_req->nsapi] = 0;
      }
    }

#ifdef SNDCP_UPM_INCLUDED 
	PSEND(hCommUPM, sn_count_cnf);  /*count_cnf goes via UPM*/
#else
    PSEND(hCommMMI, sn_count_cnf);
#endif  /*SNDCP_UPM_INCLUDED*/

  }

  PFREE(sn_count_req);
}

#endif /* CF_FAST_EXEC */

#endif /*_SNDCP_MEAN_TRACE */

#ifdef SNDCP_TRACE_IP_DATAGRAM

/*
+------------------------------------------------------------------------------
| Function    : sndcp_trace_ip_datagram
+------------------------------------------------------------------------------
| Description : traces content of one desc_list
|
| Parameters  : pointer to desc_list
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

#ifdef _SNDCP_DTI_2_
GLOBAL void sndcp_trace_ip_datagram(T_desc_list2* desc_list)
{
#else /*_SNDCP_DTI_2_*/
GLOBAL void sndcp_trace_ip_datagram(T_desc_list* desc_list)
{
#endif /*_SNDCP_DTI_2_*/
  USHORT  frame_len = desc_list->list_len;
#ifdef _SNDCP_DTI_2_
  T_desc2* desc = (T_desc2*)desc_list->first;
  USHORT  desc_pos = desc->offset;
  USHORT  desc_end  = desc->len + desc->offset;
#else /*_SNDCP_DTI_2_*/
  T_desc* desc = (T_desc*)desc_list->first;
  USHORT  desc_pos = 0;
  USHORT  desc_end  = desc->len;
#endif /*_SNDCP_DTI_2_*/
  USHORT  list_pos = 0;
  UBYTE   *pack_hdr, *ip_hdr;
  USHORT  t_length   = 0;
  USHORT  length     = 0;
  USHORT  pid        = 0;
  USHORT  f_offset   = 0;
  USHORT  h_checksum = 0;
  USHORT  src_port   = 0;
  USHORT  dest_port  = 0;
  ULONG   seq_num    = 0;
  ULONG   ack_num    = 0;
  USHORT  window     = 0;
  USHORT  checksum   = 0;
  USHORT  urg_ptr    = 0;
  USHORT  ip_hlen    = 0; /* IP header length */
  USHORT  tcp_hlen   = 0; /* TCP header length */
  UBYTE   tmp_flag   = 0;
  UBYTE   type       = 0;
  UBYTE   code       = 0;
  /*TRACE_FUNCTION("sndcp_trace_ip_datagram");*/

  if(!sndcp_data->trace_ip_datagram && !sndcp_data->trace_ip_header){
    return;
  }

  while(list_pos < frame_len)
  {
    if (desc != NULL) {
      if (desc_pos >= desc_end) {
#ifdef _SNDCP_DTI_2_
        desc = (T_desc2*)desc->next;
        desc_pos = desc->offset;
        desc_end = desc->len + desc->offset;
#else /*_SNDCP_DTI_2_*/
        desc = (T_desc*)desc->next;
        desc_pos = 0;
        desc_end = desc->len;
#endif /*_SNDCP_DTI_2_*/
        if (desc == NULL) {
          break;
        }
      }
    } else {
      return;
    }
    if((list_pos == 0) || (list_pos >= t_length))
    {
      ip_hdr = &desc->buffer[desc_pos];
      if((ip_hdr[9] != 1) && (ip_hdr[9] != 6) && (ip_hdr[9] != 17)) {
        TRACE_EVENT_P1("INFO TRACE: Tracing of protocol type %d not supported",
                                                                    ip_hdr[9]);
        return;
      }

      /* Trace IP Header */
      ip_hlen = (ip_hdr[0] & 0x0F) << 2;
      if ((desc_pos + ip_hlen) <= desc_end){
        TRACE_EVENT("IP Header");
        TRACE_EVENT_P1("  Protocol Version:         %d",
                      ((ip_hdr[0] & 0xF0) >> 4));
        TRACE_EVENT_P1("  Header Length:            %d", (ip_hlen >> 2));
        TRACE_EVENT_P1("  Type Of Service:          %d", ip_hdr[1]);
        t_length |= ip_hdr[2] << 8;
        t_length |= ip_hdr[3];
        TRACE_EVENT_P1("  Total Length:             %d", t_length);
        pid |= ip_hdr[4] << 8;
        pid |= ip_hdr[5];
        TRACE_EVENT_P1("  Packet ID:                %d", pid);
        TRACE_EVENT_P2("  MF|DF:                    %d|%d",
                            (ip_hdr[6] & 0x20) >> 5,
                            (ip_hdr[6] & 0x40) >> 6);
        f_offset |= (ip_hdr[6] & 0x1F) << 8;
        f_offset |= ip_hdr[7];
        TRACE_EVENT_P1("  Fragment offset:          %d", f_offset);
        TRACE_EVENT_P1("  Time To Live:             %d", ip_hdr[8]);
        if(ip_hdr[9] == 17) {
          TRACE_EVENT_P1("  Protocol:                 UDP(%d)",
                                             ip_hdr[9]);
        } else if (ip_hdr[9] == 6) {
          TRACE_EVENT_P1("  Protocol:                 TCP(%d)",
                                             ip_hdr[9]);
        } else {
          TRACE_EVENT_P1("  Protocol:                 %d",
                                             ip_hdr[9]);
        }
        h_checksum |= ip_hdr[10] << 8;
        h_checksum |= ip_hdr[11];
        TRACE_EVENT_P1("  Header Checksum:          %d", h_checksum);
        TRACE_EVENT_P4("  Source Address:           %d.%d.%d.%d",
                          ip_hdr[12], ip_hdr[13],
                          ip_hdr[14], ip_hdr[15]);
        TRACE_EVENT_P4("  Destination Address:      %d.%d.%d.%d",
                          ip_hdr[16], ip_hdr[17],
                          ip_hdr[18], ip_hdr[19]);
        list_pos+= ip_hlen;
        desc_pos+= ip_hlen;
      }
      /* Trace TCP Header */
      if((ip_hdr[9] == 6) && ((desc_pos + 20) <= desc_end))
      {
        TRACE_EVENT("TCP Header");
        pack_hdr = &ip_hdr[ip_hlen];
        tcp_hlen = (pack_hdr[12] & 0xF0) >> 2; /* the same as (x>>4)*4 */
        src_port |= pack_hdr[0] << 8;
        src_port |= pack_hdr[1];
        TRACE_EVENT_P1("  Source Port:              %d", src_port);
        dest_port |= pack_hdr[2] << 8;
        dest_port |= pack_hdr[3];
        TRACE_EVENT_P1("  Destination Port:         %d", dest_port);
        seq_num |= pack_hdr[4] << 24;
        seq_num |= pack_hdr[5] << 16;
        seq_num |= pack_hdr[6] << 8;
        seq_num |= pack_hdr[7];
        TRACE_EVENT_P1("  Sequence Number:          %u", seq_num);
        ack_num |= pack_hdr[8] << 24;
        ack_num |= pack_hdr[9] << 16;
        ack_num |= pack_hdr[10] << 8;
        ack_num |= pack_hdr[11];
        TRACE_EVENT_P1("  Acknowledgment Number:    %u", ack_num);
        TRACE_EVENT_P1("  Data Offset:              %d", (tcp_hlen >> 2));
        TRACE_EVENT_P6("  URG|ACK|PSH|RST|SYN|FIN:  %d|%d|%d|%d|%d|%d",
                                       (pack_hdr[13] & 0x20) >> 5,
                                       (pack_hdr[13] & 0x10) >> 4,
                                       (pack_hdr[13] & 0x08) >> 3,
                                       (pack_hdr[13] & 0x04) >> 2,
                                       (pack_hdr[13] & 0x02) >> 1,
                                       (pack_hdr[13] & 0x01)    );
        window |= pack_hdr[14] << 8;
        window |= pack_hdr[15];
        TRACE_EVENT_P1("  Window Size:              %d", window);
        checksum |= pack_hdr[16] << 8;
        checksum |= pack_hdr[17];
        TRACE_EVENT_P1("  Checksum:                 %d", checksum);
        urg_ptr |= pack_hdr[18] << 8;
        urg_ptr |= pack_hdr[19];
        TRACE_EVENT_P1("  Ungent Pointer:           0x%04x", urg_ptr);
        list_pos+= tcp_hlen;
        desc_pos+= tcp_hlen;
      }
      /* Trace UDP Header */
      else if((ip_hdr[9] == 17) && ((desc_pos + 8) <= desc_end))
      {
        TRACE_EVENT("UDP Header");
        pack_hdr = &ip_hdr[ip_hlen];
        src_port |= pack_hdr[0] << 8;
        src_port |= pack_hdr[1];
        TRACE_EVENT_P1("  Source Port:              %d", src_port);
        dest_port |= pack_hdr[2] << 8;
        dest_port |= pack_hdr[3];
        TRACE_EVENT_P1("  Destination Port:         %d", dest_port);
        length |= pack_hdr[4] << 8;
        length |= pack_hdr[5];
        TRACE_EVENT_P1("  Length:                   %d", length);
        checksum |= pack_hdr[6] << 8;
        checksum |= pack_hdr[7];
        TRACE_EVENT_P1("  Checksum:                 %d", checksum);
        list_pos+= 8;
        desc_pos+= 8;
      }
      /* Trace ICMP Header */
      else if((ip_hdr[9] == 1) && ((desc_pos + 8) <= desc_end))
      {
        TRACE_EVENT("ICMP Header");
        pack_hdr = &ip_hdr[ip_hlen];
        type = pack_hdr[0];
        TRACE_EVENT_P1("  Message Type:             %d", type);
        code = pack_hdr[1];
        TRACE_EVENT_P1("  Message Code:             %d", code);
        checksum |= pack_hdr[2] << 8;
        checksum |= pack_hdr[3];
        TRACE_EVENT_P1("  Checksum:                 %d", checksum);
        list_pos+= 8;
        desc_pos+= 8;
      }
    }/* if((list_pos == 0) || (list_pos >= t_length)) */
    /* Shall payload be traced? */
    if(!sndcp_data->trace_ip_datagram){
      break;
    }
  /* Trace Payload */
    if(!tmp_flag && (desc_pos < frame_len)){
      TRACE_EVENT("Payload");
      tmp_flag = 1;
    }
    /*lint -e661 -e662 possible access/creation of out-of-bounds pointer*/	
    if (desc_pos + 16 <= desc_end) {
      TRACE_EVENT_P16 ("  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ",
        desc->buffer[desc_pos+0], desc->buffer[desc_pos+1], desc->buffer[desc_pos+2], 
        desc->buffer[desc_pos+3], desc->buffer[desc_pos+4], desc->buffer[desc_pos+5], 
        desc->buffer[desc_pos+6], desc->buffer[desc_pos+7], desc->buffer[desc_pos+8], 
        desc->buffer[desc_pos+9], desc->buffer[desc_pos+10], desc->buffer[desc_pos+11], 
        desc->buffer[desc_pos+12], desc->buffer[desc_pos+13], desc->buffer[desc_pos+14],
        desc->buffer[desc_pos+15]);
      list_pos+= 16;
      desc_pos+= 16;
    } else if (desc_pos + 14 <= desc_end) {
      TRACE_EVENT_P14 ("  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
        desc->buffer[desc_pos+0], desc->buffer[desc_pos+1], desc->buffer[desc_pos+2], 
        desc->buffer[desc_pos+3], desc->buffer[desc_pos+4], desc->buffer[desc_pos+5], 
        desc->buffer[desc_pos+6], desc->buffer[desc_pos+7], desc->buffer[desc_pos+8], 
        desc->buffer[desc_pos+9], desc->buffer[desc_pos+10], desc->buffer[desc_pos+11], 
        desc->buffer[desc_pos+12], desc->buffer[desc_pos+13]);
      list_pos+= 14;
      desc_pos+= 14;
    } else if (desc_pos + 12 <= desc_end) {
      TRACE_EVENT_P12("  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ",
        desc->buffer[desc_pos+0], desc->buffer[desc_pos+1], desc->buffer[desc_pos+2], 
        desc->buffer[desc_pos+3], desc->buffer[desc_pos+4], desc->buffer[desc_pos+5], 
        desc->buffer[desc_pos+6], desc->buffer[desc_pos+7], desc->buffer[desc_pos+8], 
        desc->buffer[desc_pos+9], desc->buffer[desc_pos+10], desc->buffer[desc_pos+11]);
      list_pos+= 12;
      desc_pos+= 12;
    } else if (desc_pos + 10 <= desc_end) {
      TRACE_EVENT_P10("  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
        desc->buffer[desc_pos+0], desc->buffer[desc_pos+1], desc->buffer[desc_pos+2], 
        desc->buffer[desc_pos+3], desc->buffer[desc_pos+4], desc->buffer[desc_pos+5], 
        desc->buffer[desc_pos+6], desc->buffer[desc_pos+7], desc->buffer[desc_pos+8], 
        desc->buffer[desc_pos+9]);
      list_pos+= 10;
      desc_pos+= 10;
    } else if (desc_pos + 8 <= desc_end) {
      TRACE_EVENT_P8 ("  %02x %02x %02x %02x %02x %02x %02x %02x ",
        desc->buffer[desc_pos+0], desc->buffer[desc_pos+1], desc->buffer[desc_pos+2], 
        desc->buffer[desc_pos+3], desc->buffer[desc_pos+4], desc->buffer[desc_pos+5], 
        desc->buffer[desc_pos+6], desc->buffer[desc_pos+7]);
      list_pos+= 8;
      desc_pos+= 8;
    } else if (desc_pos + 7 <= desc_end) {
      TRACE_EVENT_P7 ("  %02x %02x %02x %02x %02x %02x %02x ",
        desc->buffer[desc_pos+0], desc->buffer[desc_pos+1], desc->buffer[desc_pos+2], 
        desc->buffer[desc_pos+3], desc->buffer[desc_pos+4], desc->buffer[desc_pos+5], 
        desc->buffer[desc_pos+6]);
      list_pos+= 7;
      desc_pos+= 7;
    } else if (desc_pos + 6 <= desc_end) {
      TRACE_EVENT_P6 ("  %02x %02x %02x %02x %02x %02x ",
        desc->buffer[desc_pos+0], desc->buffer[desc_pos+1], desc->buffer[desc_pos+2], 
        desc->buffer[desc_pos+3], desc->buffer[desc_pos+4], desc->buffer[desc_pos+5]);
      list_pos+= 6;
      desc_pos+= 6;
    } else if (desc_pos + 5 <= desc_end) {
      TRACE_EVENT_P5 ("  %02x %02x %02x %02x %02x ",
        desc->buffer[desc_pos+0], desc->buffer[desc_pos+1], desc->buffer[desc_pos+2], 
        desc->buffer[desc_pos+3], desc->buffer[desc_pos+4]);
      list_pos+= 5;
      desc_pos+= 5;
    } else if (desc_pos + 4 <= desc_end) {
      TRACE_EVENT_P4 ("  %02x %02x %02x %02x ",
        desc->buffer[desc_pos+0], desc->buffer[desc_pos+1], 
        desc->buffer[desc_pos+2], desc->buffer[desc_pos+3]);
      list_pos+= 4;
      desc_pos+= 4;
    } else if (desc_pos + 3 <= desc_end) {
      TRACE_EVENT_P3 ("  %02x %02x %02x ",
        desc->buffer[desc_pos+0], desc->buffer[desc_pos+1], 
        desc->buffer[desc_pos+2]);
      list_pos+= 3;
      desc_pos+= 3;
    } else if (desc_pos + 2 <= desc_end) {
      TRACE_EVENT_P2 ("  %02x %02x ",
        desc->buffer[desc_pos+0], desc->buffer[desc_pos+1]);
      list_pos+= 2;
      desc_pos+= 2;
    } else if (desc_pos + 1 <= desc_end) {
      TRACE_EVENT_P1 ("  %02x ", desc->buffer[desc_pos+0]);
      list_pos++;
      desc_pos++;
    }
  } /* while(list_pos < frame_len) */
    /*lint -e661 -e662 possible access/creation of out-of-bounds pointer*/
}
/*
+------------------------------------------------------------------------------
| Function    : sndcp_bin_trace_ip
+------------------------------------------------------------------------------
| Description : traces content of one desc_list using TRACE_IP macro
|
| Parameters  : pointer to desc_list
|               direction: SNDCP_UL_PACKET (0x1)
|                          SNDCP_DL_PACKET (0x2)
|
+------------------------------------------------------------------------------
*/
#ifdef _SNDCP_DTI_2_
GLOBAL void sndcp_bin_trace_ip(T_desc_list2* desc_list, U8 direction)
{
#else /*_SNDCP_DTI_2_*/
GLOBAL void sndcp_bin_trace_ip(T_desc_list* desc_list, U8 direction)
{
#endif /*_SNDCP_DTI_2_*/
  USHORT  frame_len = desc_list->list_len;
#ifdef _SNDCP_DTI_2_
  T_desc2* desc = (T_desc2*)desc_list->first;
#else /*_SNDCP_DTI_2_*/
  T_desc* desc = (T_desc*)desc_list->first;
#endif /*_SNDCP_DTI_2_*/

  U16 pid = 0;
  U16 pos = 0;

  TRACE_FUNCTION("sndcp_bin_trace_ip");

  if(frame_len > 1500){
    TRACE_EVENT("TRACE IP ERROR: IP packet too long.");
    return;
  }

  while(desc != NULL)
  {
#ifdef _SNDCP_DTI_2_
    memcpy(&bin_trace_ip_buf[pos], (U8*)&desc->buffer[desc->offset], desc->len );
    pos += desc->len;
    desc = (T_desc2*)desc->next;
#else /*_SNDCP_DTI_2_*/
    memcpy(&bin_trace_ip_buf[pos], (U8*)&desc->buffer[0], desc->len );
    pos += desc->len;
    desc = (T_desc*)desc->next;
#endif /*_SNDCP_DTI_2_*/
  }

#ifdef TRACE_IP
  if(direction == SNDCP_DL_PACKET){
    TRACE_IP(SNDCP_handle, SNDCP_handle, DOWNLINK_OPC, \
                    (U8*)&bin_trace_ip_buf[0], frame_len);
    pid = bin_trace_ip_buf[5] | (bin_trace_ip_buf[4] << 8); 
    TRACE_EVENT_P1("TRACE IP INFO: Downlink IP Packet, ID: %d", pid);
  } else if (direction == SNDCP_UL_PACKET){
    TRACE_IP(SNDCP_handle, SNDCP_handle, UPLINK_OPC, \
                  (U8*)&bin_trace_ip_buf[0], frame_len);
    pid = bin_trace_ip_buf[5] | (bin_trace_ip_buf[4] << 8); 
    TRACE_EVENT_P1("TRACE IP INFO: Uplink IP Packet, ID: %d", pid);
  } else {
    TRACE_EVENT("TRACE IP ERROR: unknown transfer direction.");
  }
#else /*TRACE_IP*/
  TRACE_EVENT("SNDCP WARNING: TRACE_IP macro not defined");
#endif /*TRACE_IP*/ 
}


/*
+------------------------------------------------------------------------------
| Function    : sndcp_default_ip_trace
+------------------------------------------------------------------------------
| Description : traces TCP, UDP or ICMP header
|
| Parameters  : pointer to desc_list
|               direction: SNDCP_UL_PACKET (0x1)
|                          SNDCP_DL_PACKET (0x2)
|
+------------------------------------------------------------------------------
*/
#ifdef _SNDCP_DTI_2_
GLOBAL void sndcp_default_ip_trace(T_desc_list2 *desc_list, U8 direction)
#else
GLOBAL void sndcp_default_ip_trace(T_desc_list *desc_list, U8 direction)
#endif
{
#ifdef _SNDCP_DTI_2_  
  T_desc2 *desc = (T_desc2 *)desc_list->first;
  U8  *ip_hdr = &desc->buffer[desc->offset];
#else
  T_desc *desc  = (T_desc *)desc_list->first;
  U8  *ip_hdr = &desc->buffer[0];
#endif
  U8  *pk_hdr = NULL; 
  U16  ip_len   = 0;
  U16  icmp_seq = 0;
  U32  seq_num  = 0,
       ack_num  = 0;
  U16  t_length = 0;
  U16  pid      = 0;
  U8   type, code;
  U16  win_size = 0;

  TRACE_FUNCTION("sndcp_default_ip_trace");

  if(desc_list == NULL || desc_list->first == NULL || desc_list->list_len == 0){
    return; 
  }

  ip_len = (ip_hdr[0] & 0x0f) * 4; /* IP header length in bytes*/
  if(desc->len < ip_len){
    TRACE_EVENT("IP TRACE: can not trace ip header, desc too small");
    return;
  }

  pk_hdr = &ip_hdr[ip_len];        /* Pointer to the header on top of IP hdr */  
  t_length |= ip_hdr[2] << 8;      /* Total packet length */
  t_length |= ip_hdr[3];    
  pid |= ip_hdr[4] << 8;           /* Unequal packet ID */
  pid |= ip_hdr[5];

  switch(ip_hdr[9]){
    /* ICMP Protocol */
    case 1:
      if(desc->len < (ip_len + 8)){
        TRACE_EVENT("IP TRACE: can not trace icmp header, desc to small");
        return;
      }
      /* Trace ICMP Header */
      type  = pk_hdr[0];
      if(type == 8 || type == 0){
        icmp_seq |= pk_hdr[6];
        icmp_seq |= pk_hdr[7] << 8;
        TRACE_EVENT_P4("ICMP Echo: type %d, len %d, pid %d, icmp_seq %d", 
                                          type, t_length, pid, icmp_seq);
      } else {
        code = pk_hdr[1];
        TRACE_EVENT_P5("ICMP Packet: dir %d, len %d, pid %d, type: %d, code: %d", 
                                           direction, t_length, pid, type, code);
      }      
     break;
    /* TCP Protocol */
    case 6:
      if(desc->len < (ip_len + 20)){
        TRACE_EVENT("IP TRACE: can not trace tcp header, desc to small");
        return;
      }
      seq_num |= pk_hdr[4] << 24;
      seq_num |= pk_hdr[5] << 16;
      seq_num |= pk_hdr[6] << 8;
      seq_num |= pk_hdr[7];
      ack_num |= pk_hdr[8] << 24;
      ack_num |= pk_hdr[9] << 16;
      ack_num |= pk_hdr[10] << 8;
      ack_num |= pk_hdr[11];
      win_size |= pk_hdr[14] << 8;
      win_size |= pk_hdr[15];

      TRACE_EVENT_P14("TCP Packet: dir %d, len %d, pid %d, seq_num %u, ack_num %u, src_ip %d.%d.%d.%d, dst_ip %d.%d.%d.%d, win_size %d", 
                                      direction, t_length, pid, seq_num, ack_num, 
                                      ip_hdr[12], ip_hdr[13], ip_hdr[14], ip_hdr[15],
                                      ip_hdr[16], ip_hdr[17], ip_hdr[18], ip_hdr[19], win_size);
        break;
    /* UDP Protocol */
    case 17:
      if(desc->len < (ip_len + 8)){
        TRACE_EVENT("IP TRACE: can not trace udp header, desc to small");
        return;
      }
      TRACE_EVENT_P3("UDP Packet: dir %d, len %d, pid %d", 
                                 direction, t_length, pid);
     break;
    default:
        TRACE_EVENT_P1("INFO TRACE: Tracing of protocol type %d not supported",
                                                                    ip_hdr[9]);
      break;
  }

  return;
}

#endif /* CF_FAST_EXEC */
#endif /* SNDCP_TRACE_IP_DATAGRAM */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_swap2
+------------------------------------------------------------------------------
| Description : This routine converts (2 byte) short n from network byte order
|               to host byte order.
|
| Parameters  : USHORT n
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL USHORT sndcp_swap2(USHORT n)
{
  USHORT tmp = n;
  return n = (((tmp & 0xff00) >> 8) | ((tmp & 0x00ff) << 8) );
}

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_swap4
+------------------------------------------------------------------------------
| Description : This routine converts (4 byte) long n from network byte order
|               to host byte order.
|
| Parameters  : ULONG n
|
+------------------------------------------------------------------------------
*/

#ifndef CF_FAST_EXEC

GLOBAL ULONG sndcp_swap4(ULONG n) {
  ULONG tmp = n;
  return n = ((tmp & 0xff000000) >> 24) | ((tmp & 0x00ff0000) >> 8 ) |
             ((tmp & 0x0000ff00) << 8 ) | ((tmp & 0x000000ff) << 24);
}

#endif /* CF_FAST_EXEC */
/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_nsapi_rec_state
+------------------------------------------------------------------------------
| Description : The function returns the receiving state for given NSAPI
|
| Parameters  : IN  : nsapi
|               OUT : state 
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC
GLOBAL U8 sndcp_get_nsapi_rec_state (U8 nsapi)
{
  TRACE_FUNCTION( "sndcp_get_nsapi_rec_state" );

  return sndcp_data->rec_states[nsapi];

} /* sndcp_get_nsapi_rec_state() */
#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_nsapi_rec_state
+------------------------------------------------------------------------------
| Description : The function sets the receiving state for given NSAPI
|
| Parameters  : IN : nsapi
|               IN : state 
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC
GLOBAL void sndcp_set_nsapi_rec_state (U8 nsapi, U8 state)
{
  TRACE_FUNCTION( "sndcp_set_nsapi_rec_state" );

  sndcp_data->rec_states[nsapi] = state;

} /* sndcp_set_nsapi_rec_state() */
#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_npdu_num
+------------------------------------------------------------------------------
| Description : E X T R A convenience function, not in SDL.
|               Gets the N-PDU number from the segment header.
|
| Parameters  :  ll_unitdata_ind T_LL_UNITDATA_IND*, npdu_num*
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC
LOCAL void sndcp_get_npdu_num (T_LL_UNITDATA_IND* ll_unitdata_ind, USHORT* npdu_num)
{ 
  USHORT msn_off = 1;
  USHORT lsb_off = 2;
  UBYTE msn = 0;
  UBYTE lsb = 0;

  if ((ll_unitdata_ind->sdu.buf[ll_unitdata_ind->sdu.o_buf / 8]) & 0x40) {
    msn_off = 2;
    lsb_off = 3;
  }

  msn =
    ll_unitdata_ind->sdu.buf[(ll_unitdata_ind->sdu.o_buf / 8) + msn_off];
  lsb = 
    ll_unitdata_ind->sdu.buf[(ll_unitdata_ind->sdu.o_buf / 8) + lsb_off];

  *npdu_num = ((msn & 0xf) << 8) + lsb;
} /* sndcp_get_npdu_num() */
#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_get_seg_num
+------------------------------------------------------------------------------
| Description : E X T R A convenience function, not in SDL.
|               Gets the NSAPI from the segment header.
|
| Parameters  :  ll_unitdata_ind T_LL_UNITDATA_IND*, seg_num*
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC
LOCAL void sndcp_get_seg_num (T_LL_UNITDATA_IND* ll_unitdata_ind, UBYTE* seg_num)
{ 
  *seg_num = (ll_unitdata_ind->sdu.buf[(ll_unitdata_ind->sdu.o_buf / 8) + 2] >> 4);
} /* sd_get_seg_num() */
#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_unack_transfer_params
+------------------------------------------------------------------------------
| Description : There is one N-PDU, whose segments are sent to CIA one by one,
| and that is expected reassembled and decompressed back from CIA. Some
| informations are only given in the first segment. 
| This procedure stores the needed elements in service variables that can
| be read before sending a SIG_SD_CIA_TRANSFER_REQ.
|
| Parameters  : ll_unitdata_req*
| Pre         : Correct instance of sd service must be activated.
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC
GLOBAL void sndcp_set_unack_transfer_params (T_LL_UNITDATA_IND* ll_unitdata_ind) 
{ 

  UBYTE nsapi = 
           (ll_unitdata_ind->sdu.buf[(ll_unitdata_ind->sdu.o_buf / 8)]) & 0xf;

  /*
   * The dcomp value in the first segment of the currently reassembled N-PDU.
   */
  sndcp_data->cur_dcomp[nsapi] = 
   (ll_unitdata_ind->sdu.buf[ll_unitdata_ind->sdu.o_buf / 8 + 1] & 0xf0) >> 4 ;
  /*
   * The pcomp value in the first segment of the currently reassembled N-PDU.
   */
  sndcp_data->cur_pcomp[nsapi] = 
          (ll_unitdata_ind->sdu.buf[ll_unitdata_ind->sdu.o_buf / 8 + 1]) & 0xf;
  /*
   * Reference to N-PDU.
   */
  sndcp_data->cur_pdu_ref[nsapi].ref_nsapi = nsapi;
  sndcp_get_npdu_num(ll_unitdata_ind, &sndcp_data->cur_pdu_ref[nsapi].ref_npdu_num);
  sndcp_get_seg_num(ll_unitdata_ind, &sndcp_data->cur_pdu_ref[nsapi].ref_seg_num);
  /*
   * First and/or last segment?
   */
  sndcp_data->cur_seg_pos[nsapi] = 0;
  /* 
   * if f bit is set 
   */
  if ((ll_unitdata_ind->sdu.buf[ll_unitdata_ind->sdu.o_buf / 8] & 0x40)) {
    sndcp_data->cur_seg_pos[nsapi] += SEG_POS_FIRST;
  }
  /* 
   * if m bit is not set 
   */
  if (!(ll_unitdata_ind->sdu.buf[ll_unitdata_ind->sdu.o_buf / 8] & 0x10)) {
    sndcp_data->cur_seg_pos[nsapi] += SEG_POS_LAST;
  }
} /* sndcp_set_unack_transfer_params() */
#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sndcp_set_ack_transfer_params
+------------------------------------------------------------------------------
| Description : There is one N-PDU, whose segments are sent to CIA one by one,
| and that is expected reassembled and decompressed back from CIA. Some
| informations are only given in the first segment. 
| This procedure stores the needed elements in service variables that can
| be read before sending a SIG_SDA_CIA_TRANSFER_REQ.
|
| Parameters  : ll_data_ind*
| Pre         : Correct instance of sda service must be activated.
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC
GLOBAL void sndcp_set_ack_transfer_params (T_LL_DATA_IND* ll_data_ind) 
{ 
  UBYTE nsapi = (ll_data_ind->sdu.buf[(ll_data_ind->sdu.o_buf / 8)]) & 0xf;

  /*
   * The dcomp value in the first segment of the currently reassembled N-PDU.
   */
  sndcp_data->cur_dcomp[nsapi] = 
         (ll_data_ind->sdu.buf[ll_data_ind->sdu.o_buf / 8 + 1] & 0xf0) >> 4 ;
  /*
   * The pcomp value in the first segment of the currently reassembled N-PDU.
   */
  sndcp_data->cur_pcomp[nsapi] = 
                  ll_data_ind->sdu.buf[ll_data_ind->sdu.o_buf / 8 + 1] & 0xf;
  /*
   * Reference to N-PDU.
   */
  sndcp_data->cur_pdu_ref[nsapi].ref_nsapi = nsapi;
  sndcp_data->cur_pdu_ref[nsapi].ref_npdu_num = 
                     ll_data_ind->sdu.buf[(ll_data_ind->sdu.o_buf >> 3) + 2];

  
  /*
   * First and/or last segment?
   */
  sndcp_data->cur_seg_pos[nsapi] = 0;
  /*
   * if f bit is set
   */ 
  if ((ll_data_ind->sdu.buf[ll_data_ind->sdu.o_buf / 8]) & 0x40) {
    sndcp_data->cur_seg_pos[nsapi] += SEG_POS_FIRST;
  }
  /*
   * if m bit is not set
   */
  if (!((ll_data_ind->sdu.buf[ll_data_ind->sdu.o_buf / 8]) & 0x10)) {
    sndcp_data->cur_seg_pos[nsapi] += SEG_POS_LAST;
  }
} /* sndcp_set_ack_transfer_params() */
#endif /* CF_FAST_EXEC */