view src/g23m-gprs/sndcp/sndcp_sus.c @ 303:f76436d19a7a default tip

!GPRS config: fix long-standing AT+COPS chance hanging bug There has been a long-standing bug in FreeCalypso going back years: sometimes in the AT command bring-up sequence of an ACI-only MS, the AT+COPS command would produce only a power scan followed by cessation of protocol stack activity (only L1 ADC traces), instead of the expected network search sequence. This behaviour was seen in different FC firmware versions going back to Citrine, and seemed to follow some law of chance, not reliably repeatable. This bug has been tracked down and found to be specific to !GPRS configuration, stemming from our TCS2/TCS3 hybrid and reconstruction of !GPRS support that was bitrotten in TCS3.2/LoCosto version. ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3 version and had to be pulled from TCS2 - but as it turns out, there is a new field in the MMR_REG_REQ primitive that needs to be set correctly, and that psa_mms.c module is the place where this initialization needed to be added.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Jun 2023 08:23:37 +0000
parents fa8dc04885d8
children
line wrap: on
line source

/*
+-----------------------------------------------------------------------------
|  Project :  GPRS (8441)
|  Modul   :  sndcp_sus.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 :  This modul is part of the entity SNDCP and implements all
|             functions to handles the incoming process internal signals as
|             described in the SDL-documentation (SU-statemachine)
+-----------------------------------------------------------------------------
*/

/*---- HISTORY --------------------------------------------------------------*/
#define ENTITY_SNDCP

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

#include "typedefs.h"    /* to get Condat data types */
#include "vsi.h"         /* to get a lot of macros */
#include "macdef.h"
#include "gsm.h"        /* to get a lot of macros */
#include "prim.h"       /* to get the definitions of used SAP and directions */
#include <string.h>    /* to get memcpy() */
#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_suf.h"     /* to get internal functions of service su */
#include "sndcp_cias.h"     /* to get signal functions to service cia */
#include "sndcp_nus.h"     /* to get signal functions to service nu */
#include "sndcp_sus.h"



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

/*==== LOCAL VARS ===========================================================*/

/*==== PRIVATE FUNCTIONS ====================================================*/
#ifdef _SNDCP_DTI_2_
/*
+------------------------------------------------------------------------------
| Function    : su_add_ll_unitdesc_req_params
+------------------------------------------------------------------------------
| Description : sets the parameters of the given ll_unitdata_req
|
| Parameters  : nsapi, ll_unitdata_req*
|
+------------------------------------------------------------------------------
*/
LOCAL void su_add_ll_unitdesc_req_params (UBYTE nsapi,
                                           T_LL_UNITDESC_REQ* ll_unitdesc_req)
{
  T_snsm_qos snsm_qos; /* Initialized with getter later */

  TRACE_FUNCTION( "su_add_ll_unitdesc_req_params" );

  /*
   * Set quality of service.
   */
  sndcp_get_nsapi_qos(nsapi, &snsm_qos);
  sndcp_snsm_qos_to_ll_qos(snsm_qos, &ll_unitdesc_req->ll_qos);
  /*
   * Set radio prio.
   */
  sndcp_get_nsapi_prio(nsapi,
                       &ll_unitdesc_req->radio_prio);
#ifdef REL99
  sndcp_get_nsapi_pktflowid(nsapi,
                            (U16*)&ll_unitdesc_req->pkt_flow_id);
#endif /*REL99*/


} /* su_add_ll_unitdesc_req_params() */
#else /* _SNDCP_DTI_2_ */
/*
+------------------------------------------------------------------------------
| Function    : su_add_ll_unitdata_req_params
+------------------------------------------------------------------------------
| Description : sets the parameters of the given ll_unitdata_req
|
| Parameters  : nsapi, ll_unitdata_req*
|
+------------------------------------------------------------------------------
*/
LOCAL void su_add_ll_unitdata_req_params (UBYTE nsapi,
                                           T_LL_UNITDATA_REQ* ll_unitdata_req)
{
  T_snsm_qos snsm_qos; /* Initialized with getter later */

  TRACE_FUNCTION( "su_add_ll_unitdata_req_params" );

  /*
   * Set quality of service.
   */
  sndcp_get_nsapi_qos(nsapi, &snsm_qos);
  sndcp_snsm_qos_to_ll_qos(snsm_qos, &ll_unitdata_req->ll_qos);
  /*
   * Set radio prio.
   */
  sndcp_get_nsapi_prio(nsapi,
                       &ll_unitdata_req->radio_prio);
#ifdef REL99	
  sndcp_get_nsapi_pktflowid(nsapi,
                            &ll_unitdata_req->pkt_flow_id);
#endif /*REL99*/

} /* su_add_ll_unitdata_req_params() */
#endif /* _SNDCP_DTI_2_ */
#ifdef _SNDCP_DTI_2_
/*
+------------------------------------------------------------------------------
| Function    : su_add_sn_header
+------------------------------------------------------------------------------
| Description : sets the segment header in the given ll_unitdesc_req
|
| Parameters  : first and/or last segment , ll_unitdesc_req*, packet type
|
+------------------------------------------------------------------------------
*/
LOCAL void su_add_sn_header (UBYTE seg_pos,
                              T_pdu_ref pdu_ref,
                              T_LL_UNITDESC_REQ* ll_unitdesc_req,
                              UBYTE packet_type)
{
  USHORT offset = ENCODE_OFFSET_BYTE;
  BOOL compressed = FALSE;
  UBYTE sapi_index = 0;
  T_desc3* desc3 = NULL;
  U8* sndcp_header = NULL;

  TRACE_FUNCTION( "su_add_sn_header" );

  sndcp_get_sapi_index(ll_unitdesc_req->sapi, &sapi_index);
  sndcp_data->su = & sndcp_data->su_base[sapi_index];

  /* Get the descriptor describing the memory area with the sndcp header */
  desc3 = (T_desc3*)ll_unitdesc_req->desc_list3.first;
  sndcp_header = (U8*)desc3->buffer;
  sndcp_header[offset] = 0;
  /*
   * Octet 1, F bit.
   */
  if ((seg_pos & SEG_POS_FIRST) > 0)
  {
    sndcp_header[offset] += (1 << 6);
  }
  /*
   * Octet 1, 1 for SN_UNITDATA.
   */
  sndcp_header[offset] += (1 << 5);
  /*
   * Octet 1, M bit.
   */
  if ((seg_pos & SEG_POS_LAST) == 0)
  {
    sndcp_header[offset] += (1 << 4);
  }
  /*
   * Octet 1, NSAPI number.
   */
  sndcp_header[offset] += pdu_ref.ref_nsapi;

  offset ++;
  sndcp_header[offset] = 0;

  if ((seg_pos & SEG_POS_FIRST) > 0) {
    /*
     * This is the first bit.
     * Find d/pcomp values and set them.
     */
    /*
     * Octet 2, dcomp
     */
    sndcp_header[offset] +=
      (UBYTE)(sndcp_data->mg.cur_xid_block[sapi_index].v42.dcomp << 4);
    /*
     * Octet 2, pcomp
     */
    sndcp_is_nsapi_header_compressed(pdu_ref.ref_nsapi, &compressed);
    if (compressed) {
      if (packet_type == TYPE_UNCOMPRESSED_TCP)
      {
        /*
         * Uncompressed TCP.
         */
        sndcp_header[offset] =
          sndcp_data->mg.cur_xid_block[sapi_index].vj.pcomp1;
      } else if (packet_type == TYPE_IP)
      {
        /*
         * IP.
         */
        sndcp_header[offset] = 0;
      } else
      {
        /*
         * Compressed TCP.
         */
        sndcp_header[offset] =
          sndcp_data->mg.cur_xid_block[sapi_index].vj.pcomp2;
      }
    }

    offset ++;
  }
  /*
   * Octet 2 or 3, segment number
   */
  sndcp_header[offset] = 0;
  sndcp_header[offset] += (UBYTE)(pdu_ref.ref_seg_num << 4);
  /*
   * Octet 2 or 3, N-PDU number, MSB.
   */
  sndcp_header[offset] += ((pdu_ref.ref_npdu_num >> 8) & 0xf);

  offset ++;

  /*
   * Octet 3 or 4, N-PDU number, LSB.
   */
  sndcp_header[offset] = (pdu_ref.ref_npdu_num & 0xff);

} /* su_add_sn_header() */
#else /* _SNDCP_DTI_2_ */
/*
+------------------------------------------------------------------------------
| Function    : su_add_sn_header
+------------------------------------------------------------------------------
| Description : sets the segment header in the given ll_unitdata_req
|
| Parameters  : first and/or last segment , ll_unitdata_req*, packet type
|
+------------------------------------------------------------------------------
*/
LOCAL void su_add_sn_header (UBYTE seg_pos,
                              T_pdu_ref pdu_ref,
                              T_LL_UNITDATA_REQ* ll_unitdata_req,
                              UBYTE packet_type)
{
  USHORT offset = ll_unitdata_req->sdu.o_buf / 8;
  BOOL compressed = FALSE;
  UBYTE sapi_index = 0;

  TRACE_FUNCTION( "su_add_sn_header" );

  sndcp_get_sapi_index(ll_unitdata_req->sapi, &sapi_index);
  sndcp_data->su = & sndcp_data->su_base[sapi_index];

  ll_unitdata_req->sdu.buf[offset] = 0;
  /*
   * Octet 1, F bit.
   */
  if ((seg_pos & SEG_POS_FIRST) > 0) {
    ll_unitdata_req->sdu.buf[offset] += (1 << 6);
  }
  /*
   * Octet 1, 1 for SN_UNITDATA.
   */
  ll_unitdata_req->sdu.buf[offset] += (1 << 5);
  /*
   * Octet 1, M bit.
   */
  if ((seg_pos & SEG_POS_LAST) == 0) {
    ll_unitdata_req->sdu.buf[offset] += (1 << 4);
  }
  /*
   * Octet 1, NSAPI number.
   */
  ll_unitdata_req->sdu.buf[offset] += pdu_ref.ref_nsapi;

  offset ++;
  ll_unitdata_req->sdu.buf[offset] = 0;

  if ((seg_pos & SEG_POS_FIRST) > 0) {
    /*
     * This is the first bit.
     * Find d/pcomp values and set them.
     */
    /*
     * Octet 2, dcomp
     */
    ll_unitdata_req->sdu.buf[offset] +=
      (UBYTE)(sndcp_data->su->cur_xid_block.v42.dcomp << 4);
    /*
     * Octet 2, pcomp
     */
    sndcp_is_nsapi_header_compressed(pdu_ref.ref_nsapi, &compressed);
    if (compressed) {
      if (packet_type == TYPE_UNCOMPRESSED_TCP) {
        /*
         * Uncompressed TCP.
         */
        ll_unitdata_req->sdu.buf[offset] =
          sndcp_data->su->cur_xid_block.vj.pcomp1;
      } else if (packet_type == TYPE_IP) {
        /*
         * IP.
         */
        ll_unitdata_req->sdu.buf[offset] = 0;
      } else {
        /*
         * Compressed TCP.
         */
        ll_unitdata_req->sdu.buf[offset] =
          sndcp_data->su->cur_xid_block.vj.pcomp2;
      }
    }

    offset ++;
  }
  /*
   * Octet 2 or 3, segment number
   */
  ll_unitdata_req->sdu.buf[offset] = 0;
  ll_unitdata_req->sdu.buf[offset] += (UBYTE)(pdu_ref.ref_seg_num << 4);
  /*
   * Octet 2 or 3, N-PDU number, MSB.
   */
  ll_unitdata_req->sdu.buf[offset] += ((pdu_ref.ref_npdu_num >> 8) & 0xf);

  offset ++;

  /*
   * Octet 3 or 4, N-PDU number, LSB.
   */
  ll_unitdata_req->sdu.buf[offset] = (pdu_ref.ref_npdu_num & 0xff);

} /* su_add_sn_header() */
#endif /* _SNDCP_DTI_2_ */


/*==== PUBLIC FUNCTIONS =====================================================*/
#ifdef _SNDCP_DTI_2_
/*
+------------------------------------------------------------------------------
| Function    : sig_cia_su_cia_comp_ind
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_CIA_su_CIA_COMP_IND
|
| Parameters  : cia_comp_ind*
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_cia_su_cia_comp_ind (T_CIA_COMP_IND* cia_comp_ind)
{
  UBYTE sapi_index = 0;


  TRACE_ISIG( "sig_cia_su_cia_comp_ind" );

  /*
   * Set service instance according to sapi in signal.
   */
  sndcp_get_sapi_index(cia_comp_ind->sapi, &sapi_index);
  sndcp_data->su = & sndcp_data->su_base[sapi_index];

  switch( GET_STATE( SU ) )
  {
    case SU_LLC_RECEPTIVE_SUSPEND:
    case SU_LLC_NOT_RECEPTIVE:
    case SU_LLC_NOT_RECEPTIVE_SUSPEND:
      {

        /*
         * Save seg_pos and pdu_ref from cia_comp_ind.
         */
        UBYTE seg_pos = cia_comp_ind->seg_pos;
        T_pdu_ref pdu_ref = cia_comp_ind->pdu_ref;
        UBYTE nsapi = cia_comp_ind->pdu_ref.ref_nsapi;
        UBYTE packet_type = cia_comp_ind->packet_type;

        PALLOC(ll_unitdesc_req, LL_UNITDESC_REQ);
        ll_unitdesc_req->sapi = cia_comp_ind->sapi;
        ll_unitdesc_req->tlli = cia_comp_ind->tlli;
        ll_unitdesc_req->ll_qos.delay      = cia_comp_ind->cia_qos.delay;
        ll_unitdesc_req->ll_qos.relclass   = cia_comp_ind->cia_qos.relclass;
        ll_unitdesc_req->ll_qos.peak       = cia_comp_ind->cia_qos.peak;
        ll_unitdesc_req->ll_qos.preced     = cia_comp_ind->cia_qos.preced;
        ll_unitdesc_req->ll_qos.mean       = cia_comp_ind->cia_qos.mean;
        /* attached_counter not copied */
        /* cipher not copied */
        ll_unitdesc_req->reserved_unitdata_req1.ref_nsapi    = cia_comp_ind->pdu_ref.ref_nsapi;
        ll_unitdesc_req->reserved_unitdata_req1.ref_npdu_num = cia_comp_ind->pdu_ref.ref_npdu_num;
        ll_unitdesc_req->reserved_unitdata_req1.ref_seg_num  = cia_comp_ind->pdu_ref.ref_seg_num;
        ll_unitdesc_req->seg_pos = cia_comp_ind->seg_pos;
        ll_unitdesc_req->desc_list3.list_len = cia_comp_ind->desc_list3.list_len;
        ll_unitdesc_req->desc_list3.first    = cia_comp_ind->desc_list3.first;

        su_add_ll_unitdesc_req_params(nsapi,
                                      ll_unitdesc_req);
        su_add_sn_header(seg_pos, pdu_ref,
                         ll_unitdesc_req,
                         packet_type);

        /* All information has been transferred remove the compression primitive */
        MFREE(cia_comp_ind);

        /*
         * Write the ll_unitdesc_req prim to ll_unitdesc_q,
         * increment write pointer.
         */
        sndcp_data->su->ll_unitdesc_q[sndcp_data->su->ll_unitdesc_q_write] =
          ll_unitdesc_req;
        sndcp_data->su->ll_unitdesc_q_write =
          (sndcp_data->su->ll_unitdesc_q_write + 1) % SNDCP_SEGMENT_NUMBERS_UNACK;

      }
      break;
    case SU_LLC_RECEPTIVE:
      {
        /*
         * Save seg_pos and pdu_ref from cia_comp_ind.
         */
        UBYTE ll_unitdesc_sapi;
        UBYTE seg_pos = cia_comp_ind->seg_pos;
        T_pdu_ref pdu_ref = cia_comp_ind->pdu_ref;
        UBYTE nsapi = cia_comp_ind->pdu_ref.ref_nsapi;
        UBYTE packet_type = cia_comp_ind->packet_type;

        PALLOC(ll_unitdesc_req, LL_UNITDESC_REQ);
        ll_unitdesc_req->sapi = cia_comp_ind->sapi;
        ll_unitdesc_req->tlli = cia_comp_ind->tlli;
        ll_unitdesc_req->ll_qos.delay      = cia_comp_ind->cia_qos.delay;
        ll_unitdesc_req->ll_qos.relclass   = cia_comp_ind->cia_qos.relclass;
        ll_unitdesc_req->ll_qos.peak       = cia_comp_ind->cia_qos.peak;
        ll_unitdesc_req->ll_qos.preced     = cia_comp_ind->cia_qos.preced;
        ll_unitdesc_req->ll_qos.mean       = cia_comp_ind->cia_qos.mean;
        /* attached_counter not copied */
        /* cipher not copied */
        ll_unitdesc_req->reserved_unitdata_req1.ref_nsapi    = cia_comp_ind->pdu_ref.ref_nsapi;
        ll_unitdesc_req->reserved_unitdata_req1.ref_npdu_num = cia_comp_ind->pdu_ref.ref_npdu_num;
        ll_unitdesc_req->reserved_unitdata_req1.ref_seg_num  = cia_comp_ind->pdu_ref.ref_seg_num;
        ll_unitdesc_req->seg_pos = cia_comp_ind->seg_pos;
        ll_unitdesc_req->desc_list3.list_len = cia_comp_ind->desc_list3.list_len;
        ll_unitdesc_req->desc_list3.first    = cia_comp_ind->desc_list3.first;

        /* All information has been transferred remove the compression primitive */
        MFREE(cia_comp_ind);

        su_add_ll_unitdesc_req_params(nsapi,
                                      ll_unitdesc_req);
        su_add_sn_header(seg_pos, pdu_ref,
                         ll_unitdesc_req,
                         packet_type);


#ifdef SNDCP_TRACE_ALL
        TRACE_EVENT("uplink with sn header at LL SAP: ");
        TRACE_EVENT_P1("%d octets",
            ll_unitdesc_req->desc_list3.list_len);

        sndcp_trace_desc_list3_content(ll_unitdesc_req->desc_list3);
#endif

#ifdef FLOW_TRACE
        sndcp_trace_flow_control(FLOW_TRACE_SNDCP,
                                 FLOW_TRACE_UP,
                                 FLOW_TRACE_BOTTOM,
                                 FALSE);
#endif
        ll_unitdesc_sapi = ll_unitdesc_req->sapi;


#ifdef _SIMULATION_
#ifndef MULTI_LAYER
        su_send_ll_unitdata_req_test(ll_unitdesc_req);
#else
        PSEND(hCommLLC, ll_unitdesc_req);
#endif /* MULTI_LAYER */
#else /* _SIMULATION_ */
        PSEND(hCommLLC, ll_unitdesc_req);
#endif /* _SIMULATION_ */

        SET_STATE(SU, SU_LLC_NOT_RECEPTIVE);
        /*
         * If segment is the last of the N-PDU then send ready_ind to nsapi
         * and get next entry from sn q..
         */
        if ((seg_pos & SEG_POS_LAST) > 0) {
          sndcp_data->su->cia_state = CIA_IDLE;
          su_next_sn_unitdata_req( ll_unitdesc_sapi );
          sig_su_nu_ready_ind(nsapi);
        }

      }
      break;
    default:
      TRACE_ERROR( "SIG_CIA_SU_CIA_COMP_IND unexpected" );
      sndcp_cl_desc3_free((T_desc3*)cia_comp_ind->desc_list3.first);
      MFREE(cia_comp_ind);
      break;
  }
} /* sig_cia_su_cia_comp_ind() */
#else /* _SNDCP_DTI_2_ */
/*
+------------------------------------------------------------------------------
| Function    : sig_cia_su_cia_comp_ind
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_CIA_su_CIA_COMP_IND
|
| Parameters  : cia_comp_ind*
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_cia_su_cia_comp_ind (T_CIA_COMP_IND* cia_comp_ind)
{
  UBYTE sapi_index = 0;


  TRACE_ISIG( "sig_cia_su_cia_comp_ind" );

  /*
   * Set service instance according to sapi in signal.
   */
  sndcp_get_sapi_index(cia_comp_ind->sapi, &sapi_index);
  sndcp_data->su = & sndcp_data->su_base[sapi_index];

  switch( GET_STATE( SU ) )
  {
    case SU_LLC_RECEPTIVE_SUSPEND:
    case SU_LLC_NOT_RECEPTIVE:
    case SU_LLC_NOT_RECEPTIVE_SUSPEND:
      {

        /*
         * Save seg_pos and pdu_ref from cia_comp_ind.
         */
        UBYTE seg_pos = cia_comp_ind->seg_pos;
        T_pdu_ref pdu_ref = cia_comp_ind->pdu_ref;
        UBYTE nsapi = cia_comp_ind->pdu_ref.ref_nsapi;
        UBYTE packet_type = cia_comp_ind->packet_type;

        PPASS(cia_comp_ind, ll_unitdata_req, LL_UNITDATA_REQ);

        su_add_ll_unitdata_req_params(nsapi,
                                      ll_unitdata_req);
        su_add_sn_header(seg_pos, pdu_ref,
                         ll_unitdata_req,
                         packet_type);
        /*
         * Write the ll_unitdata_req prim to ll_unitdata_q,
         * increment write pointer.
         */
        sndcp_data->su->ll_unitdata_q[sndcp_data->su->ll_unitdata_q_write] =
          ll_unitdata_req;
        sndcp_data->su->ll_unitdata_q_write =
          (sndcp_data->su->ll_unitdata_q_write + 1) % SNDCP_SEGMENT_NUMBERS_UNACK;

      }
      break;
    case SU_LLC_RECEPTIVE:
      {
        /*
         * Save seg_pos and pdu_ref from cia_comp_ind.
         */
        UBYTE ll_unitdata_sapi;
        UBYTE seg_pos = cia_comp_ind->seg_pos;
        T_pdu_ref pdu_ref = cia_comp_ind->pdu_ref;
        UBYTE nsapi = cia_comp_ind->pdu_ref.ref_nsapi;
        UBYTE packet_type = cia_comp_ind->packet_type;

        PPASS(cia_comp_ind, ll_unitdata_req, LL_UNITDATA_REQ);

        su_add_ll_unitdata_req_params(nsapi,
                                      ll_unitdata_req);
        su_add_sn_header(seg_pos, pdu_ref,
                         ll_unitdata_req,
                         packet_type);


#ifdef SNDCP_TRACE_ALL
        TRACE_EVENT("uplink with sn header at LL SAP: ");
        TRACE_EVENT_P1("%d octets",
                       (ll_unitdata_req->sdu.l_buf + 7) / 8);

        sndcp_trace_sdu(& ll_unitdata_req->sdu);
#endif

#ifdef FLOW_TRACE
        sndcp_trace_flow_control(FLOW_TRACE_SNDCP,
                                 FLOW_TRACE_UP,
                                 FLOW_TRACE_BOTTOM,
                                 FALSE);
#endif
        ll_unitdata_sapi = ll_unitdata_req->sapi;

        PSEND(hCommLLC, ll_unitdata_req);

        SET_STATE(SU, SU_LLC_NOT_RECEPTIVE);
        /*
         * If segment is the last of the N-PDU then send ready_ind to nsapi
         * and get next entry from sn q..
         */
        if ((seg_pos & SEG_POS_LAST) > 0) {
          sndcp_data->su->cia_state = CIA_IDLE;
          su_next_sn_unitdata_req( ll_unitdata_sapi );
          sig_su_nu_ready_ind(nsapi);
        }

      }
      break;
    default:
      TRACE_ERROR( "SIG_CIA_SU_CIA_COMP_IND unexpected" );
      break;
  }
} /* sig_cia_su_cia_comp_ind() */
#endif /* _SNDCP_DTI_2_ */
/*
+------------------------------------------------------------------------------
| Function    : sig_mg_su_delete_pdus
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_MG_SU_DELETE_PDUS
|               The same as the one in service sua, but everything is in the
|               unacknowledged version here.
|
| Parameters  : UBYTE nsapi the affected nsapi, UBYTE sapi the affected sapi
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_mg_su_delete_pdus (UBYTE nsapi, UBYTE sapi)
{
  UBYTE sapi_index = 0;
  BOOL ll_q_affected = FALSE;

  TRACE_ISIG( "sig_mg_su_delete_pdus" );

  /*
   * Set service instance according to sapi in signal.
   */
  sndcp_get_sapi_index(sapi, &sapi_index);
  sndcp_data->su = & sndcp_data->su_base[sapi_index];
  sndcp_data->su->cia_state = CIA_IDLE;

  switch( GET_STATE( SU ) )
  {
    case SU_LLC_NOT_RECEPTIVE_SUSPEND:
    case SU_LLC_RECEPTIVE_SUSPEND:
    case SU_LLC_NOT_RECEPTIVE:
    case SU_LLC_RECEPTIVE:
      {
        /*
         * Delete affected N-PDUS from sn_unitdata_q.
         */
        BOOL still = TRUE;
        UBYTE index = sndcp_data->su->sn_unitdata_q_read;

        while (still) {
          if (index == sndcp_data->su->sn_unitdata_q_write) {
            break;
          }
          if (sndcp_data->su->sn_unitdata_q[index]->nsapi == nsapi) {
            /*
             * The index for the prims to be shifted when 1 entry is deleted.
             */
            UBYTE i = 0;

            if (sndcp_data->su->sn_unitdata_q[index] != NULL) {
#ifdef _SNDCP_DTI_2_
              MFREE_PRIM(sndcp_data->su->sn_unitdata_q[index]);
#else /*_SNDCP_DTI_2_*/ 
              PFREE_DESC(sndcp_data->su->sn_unitdata_q[index]);
#endif /*_SNDCP_DTI_2_*/
              sndcp_data->su->sn_unitdata_q[index] = NULL;
            }

            for (i = index;
                 i != sndcp_data->su->sn_unitdata_q_write;
                 i = (i + 1) % SN_UNITDATA_Q_LEN) {


              sndcp_data->su->sn_unitdata_q[i] =
                sndcp_data->su->sn_unitdata_q[(i + 1) % SN_UNITDATA_Q_LEN];

              sndcp_data->su->sn_unitdata_q[(i + 1) % SN_UNITDATA_Q_LEN] =
                NULL;

            }
            sndcp_data->su->sn_unitdata_q_write =
              (sndcp_data->su->sn_unitdata_q_write - 1
               + SN_UNITDATA_Q_LEN) % SN_UNITDATA_Q_LEN;
          } else {
            index = (index + 1) % SN_UNITDATA_Q_LEN;
          } /* else (sndcp_data->su->sn_unitdata_q[index]->nsapi == nsapi) */

        }
#ifdef _SNDCP_DTI_2_
        /*
         * Delete affected SN-PDUS from ll_unitdata_q.
         */
        still = TRUE;
        index = sndcp_data->su->ll_unitdesc_q_read;
        while (still) {
          if (index == sndcp_data->su->ll_unitdesc_q_write) {
            break;
          }
          if (su_get_nsapi(sndcp_data->su->ll_unitdesc_q[index]) == nsapi) {
            /*
             * The index for the prims to be shifted when 1 entry is deleted.
             */
            UBYTE i = 0;

            ll_q_affected = TRUE;
            /*
             * Free the deleted primitive.
             */
            if (sndcp_data->su->ll_unitdesc_q[index] != NULL) {
              T_desc3 *free_help, *help =
             (T_desc3 *)sndcp_data->su->ll_unitdesc_q[index]->desc_list3.first;
              while(help != NULL)
              {
                 sndcp_cl_desc3_free(help);
                 free_help = help;
                 help = (T_desc3 *)free_help->next;
                 MFREE(free_help);
              }
              sndcp_data->su->ll_unitdesc_q[index]->desc_list3.first = NULL;
              PFREE(sndcp_data->su->ll_unitdesc_q[index]);
              sndcp_data->su->ll_unitdesc_q[index] = NULL;
            }

            for (i = index;
                 i != sndcp_data->su->ll_unitdesc_q_write;
                 i = (i + 1) % SNDCP_SEGMENT_NUMBERS_UNACK) {

              sndcp_data->su->ll_unitdesc_q[i] =
                sndcp_data->su->ll_unitdesc_q
                  [(i + 1) % SNDCP_SEGMENT_NUMBERS_UNACK];
            }
            sndcp_data->su->ll_unitdesc_q_write =
              (sndcp_data->su->ll_unitdesc_q_write - 1
               + SNDCP_SEGMENT_NUMBERS_UNACK) % SNDCP_SEGMENT_NUMBERS_UNACK;

          } else {
            index = (index + 1) % SNDCP_SEGMENT_NUMBERS_UNACK;
          } /* else (sndcp_data->su->sn_unitdata_q[index]->nsapi == nsapi) { */


        }
#else /* _SNDCP_DTI_2_ */
        /*
         * Delete affected SN-PDUS from ll_unitdata_q.
         */
        still = TRUE;
        index = sndcp_data->su->ll_unitdata_q_read;
        while (still) {
          if (index == sndcp_data->su->ll_unitdata_q_write) {
            break;
          }
          if (su_get_nsapi(sndcp_data->su->ll_unitdata_q[index]) == nsapi) {
            /*
             * The index for the prims to be shifted when 1 entry is deleted.
             */
            UBYTE i = 0;

            ll_q_affected = TRUE;
            /*
             * Free the deleted primitive.
             */
            if (sndcp_data->su->ll_unitdata_q[index] != NULL) {
              PFREE(sndcp_data->su->ll_unitdata_q[index]);
              sndcp_data->su->ll_unitdata_q[index] = NULL;
            }

            for (i = index;
                 i != sndcp_data->su->ll_unitdata_q_write;
                 i = (i + 1) % SNDCP_SEGMENT_NUMBERS_UNACK) {

              sndcp_data->su->ll_unitdata_q[i] =
                sndcp_data->su->ll_unitdata_q
                  [(i + 1) % SNDCP_SEGMENT_NUMBERS_UNACK];
            }
            sndcp_data->su->ll_unitdata_q_write =
              (sndcp_data->su->ll_unitdata_q_write - 1
               + SNDCP_SEGMENT_NUMBERS_UNACK) % SNDCP_SEGMENT_NUMBERS_UNACK;

          } else {
            index = (index + 1) % SNDCP_SEGMENT_NUMBERS_UNACK;
          } /* else (sndcp_data->su->sn_unitdata_q[index]->nsapi == nsapi) { */


        }
#endif /* _SNDCP_DTI_2_ */
      }
      /*
       * if the segments in LL queue were from the affected nsapi then the
       * next N-PDU is directed to cia.
       */
      if (ll_q_affected) {
        su_next_sn_unitdata_req (sapi);
      }
      break;
    default:
      TRACE_ERROR( "SIG_MG_SU_DELETE_PDUS unexpected" );
      break;
  }
} /* sig_mg_su_delete_pdus() */



/*
+------------------------------------------------------------------------------
| Function    : sig_mg_su_n201
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_MG_SU_N201
|
| Parameters  : UBYTE sapi the affected sapi, USHORT n201
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_mg_su_n201 (UBYTE sapi,
                            USHORT n201)
{
  UBYTE sapi_index = 0;

  TRACE_ISIG( "sig_mg_su_n201" );

  /*
   * Set service instance according to sapi in signal.
   */
  sndcp_get_sapi_index(sapi, &sapi_index);
  sndcp_data->su = & sndcp_data->su_base[sapi_index];

  switch( GET_STATE( SU ) )
  {
    case SU_LLC_NOT_RECEPTIVE_SUSPEND:
    case SU_LLC_RECEPTIVE_SUSPEND:
    case SU_LLC_NOT_RECEPTIVE:
    case SU_LLC_RECEPTIVE:
      sndcp_data->su->n201_u = n201;
      break;
    default:
      TRACE_ERROR( "SIG_MG_SU_N201 unexpected" );
      break;
  }
} /* sig_mg_su_n201() */



/*
+------------------------------------------------------------------------------
| Function    : sig_mg_su_suspend
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_MG_SU_SUSPEND
|
| Parameters  : UBYTE sapi the affected sapi
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_mg_su_suspend (UBYTE sapi)
{
  UBYTE sapi_index = 0;

  TRACE_ISIG( "sig_mg_su_suspend" );

  /*
   * Set service instance according to sapi in signal.
   */
  sndcp_get_sapi_index(sapi, &sapi_index);
  sndcp_data->su = & sndcp_data->su_base[sapi_index];

  switch( GET_STATE( SU ) )
  {
    case SU_LLC_NOT_RECEPTIVE_SUSPEND:
      break;
    case SU_LLC_RECEPTIVE_SUSPEND:
      break;
    case SU_LLC_NOT_RECEPTIVE:
      SET_STATE (SU, SU_LLC_NOT_RECEPTIVE_SUSPEND);
      break;
    case SU_LLC_RECEPTIVE:
      SET_STATE (SU, SU_LLC_RECEPTIVE_SUSPEND);
      break;
    default:
      TRACE_ERROR( "SIG_MG_SU_SUSPEND unexpected" );
      break;
  }
} /* sig_mg_su_suspend() */

/*
+------------------------------------------------------------------------------
| Function    : sig_mg_su_reset_ind
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_MG_SU_RESET_IND
|
| Parameters  : UBYTE sapi the affected sapi
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_mg_su_reset_ind (UBYTE sapi)
{
  UBYTE sapi_index = 0;

  TRACE_ISIG( "sig_mg_su_reset_ind" );

  /*
   * Set service instance according to sapi in signal.
   */
  sndcp_get_sapi_index(sapi, &sapi_index);
  sndcp_data->su = & sndcp_data->su_base[sapi_index];

  switch( GET_STATE( SU ) )
  {
    case SU_LLC_NOT_RECEPTIVE_SUSPEND:
    case SU_LLC_RECEPTIVE_SUSPEND:
    case SU_LLC_NOT_RECEPTIVE:
    case SU_LLC_RECEPTIVE:
      break;
    default:
      TRACE_ERROR( "SIG_MG_SU_RESET_IND unexpected" );
      break;
  }
} /* sig_mg_su_reset_ind() */

#ifdef _SNDCP_DTI_2_
/*
+------------------------------------------------------------------------------
| Function    : sig_mg_su_resume
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_MG_SU_RESUME
|
| Parameters  : UBYTE sapi the affected sapi
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_mg_su_resume (UBYTE sapi)
{
  UBYTE sapi_index = 0;


  TRACE_ISIG( "sig_mg_su_resume" );
  /*
   * Set service instance according to sapi in signal.
   */
  sndcp_get_sapi_index(sapi, &sapi_index);
  sndcp_data->su = & sndcp_data->su_base[sapi_index];

  switch( GET_STATE( SU ) )
  {
    case SU_LLC_NOT_RECEPTIVE_SUSPEND:
      SET_STATE (SU, SU_LLC_NOT_RECEPTIVE);
      break;
    case SU_LLC_RECEPTIVE_SUSPEND:
      /*
       * Is queue with LL_UNITDESC_REQ empty?
       */
      if (sndcp_data->su->ll_unitdesc_q_write ==
          sndcp_data->su->ll_unitdesc_q_read) {
        SET_STATE(SU, SU_LLC_RECEPTIVE);
      } else {
        /*
         * Get next segment from queue and send it.
         */
        U8 ll_unitdesc_seg_pos;
        U8 ll_unitdesc_nsapi;
        U8 ll_unitdesc_sapi;

        T_LL_UNITDESC_REQ* ll_unitdesc_req =
          sndcp_data->su->ll_unitdesc_q[sndcp_data->su->ll_unitdesc_q_read];

        sndcp_data->su->ll_unitdesc_q[sndcp_data->su->ll_unitdesc_q_read] =
          NULL;

        sndcp_data->su->ll_unitdesc_q_read =
            (sndcp_data->su->ll_unitdesc_q_read + 1) %
              SNDCP_SEGMENT_NUMBERS_UNACK;


        /*
         * trace output
         */
#ifdef SNDCP_TRACE_ALL
        TRACE_EVENT("uplink with sn header at LL SAP: ");
        TRACE_EVENT_P1("%d octets",
                       ll_unitdesc_req->desc_list3.list_len);

        sndcp_trace_desc_list3_content(ll_unitdesc_req->desc_list3);
#endif
#ifdef FLOW_TRACE
        sndcp_trace_flow_control(FLOW_TRACE_SNDCP,
                                 FLOW_TRACE_UP,
                                 FLOW_TRACE_BOTTOM,
                                 FALSE);
#endif
        ll_unitdesc_seg_pos = ll_unitdesc_req->seg_pos;
        ll_unitdesc_nsapi   = su_get_nsapi(ll_unitdesc_req);
        ll_unitdesc_sapi    = ll_unitdesc_req->sapi;

#ifdef _SIMULATION_
        su_send_ll_unitdata_req_test(ll_unitdesc_req);
#else /* _SIMULATION_ */
        PSEND(hCommLLC, ll_unitdesc_req);
#endif /* _SIMULATION_ */

        SET_STATE(SU, SU_LLC_NOT_RECEPTIVE);
        /*
         * If segment is the last of the N-PDU then send ready_ind to nsapi
         * and get next entry from sn q..
         */
        if ((ll_unitdesc_seg_pos & SEG_POS_LAST) > 0) {
          sndcp_data->su->cia_state = CIA_IDLE;
          su_next_sn_unitdata_req( ll_unitdesc_sapi );
          sig_su_nu_ready_ind( ll_unitdesc_nsapi );
        }
      }

      break;
    case SU_LLC_NOT_RECEPTIVE:
      break;
    case SU_LLC_RECEPTIVE:
      break;
    default:
      TRACE_ERROR( "SIG_MG_SU_RESUME unexpected" );
      break;
  }
} /* sig_mg_su_resume() */
#else /* _SNDCP_DTI_2_ */
/*
+------------------------------------------------------------------------------
| Function    : sig_mg_su_resume
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_MG_SU_RESUME
|
| Parameters  : UBYTE sapi the affected sapi
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_mg_su_resume (UBYTE sapi)
{
  UBYTE sapi_index = 0;


  TRACE_ISIG( "sig_mg_su_resume" );
  /*
   * Set service instance according to sapi in signal.
   */
  sndcp_get_sapi_index(sapi, &sapi_index);
  sndcp_data->su = & sndcp_data->su_base[sapi_index];

  switch( GET_STATE( SU ) )
  {
    case SU_LLC_NOT_RECEPTIVE_SUSPEND:
      SET_STATE (SU, SU_LLC_NOT_RECEPTIVE);
      break;
    case SU_LLC_RECEPTIVE_SUSPEND:
      /*
       * Is queue with LL_UNITDATA_REQ empty?
       */
      if (sndcp_data->su->ll_unitdata_q_write ==
          sndcp_data->su->ll_unitdata_q_read) {
        SET_STATE(SU, SU_LLC_RECEPTIVE);
      } else {
        /*
         * Get next segment from queue and send it.
         */
        UBYTE ll_unitdata_seg_pos;
        UBYTE ll_unitdata_nsapi;
        UBYTE ll_unitdata_sapi;

        T_LL_UNITDATA_REQ* ll_unitdata_req =
          sndcp_data->su->ll_unitdata_q[sndcp_data->su->ll_unitdata_q_read];

        sndcp_data->su->ll_unitdata_q[sndcp_data->su->ll_unitdata_q_read] =
          NULL;

        sndcp_data->su->ll_unitdata_q_read =
            (sndcp_data->su->ll_unitdata_q_read + 1) %
              SNDCP_SEGMENT_NUMBERS_UNACK;


        /*
         * trace output
         */
#ifdef SNDCP_TRACE_ALL
        TRACE_EVENT("uplink with sn header at LL SAP: ");
        TRACE_EVENT_P1("%d octets",
                       (ll_unitdata_req->sdu.l_buf + 7) / 8);
        sndcp_trace_sdu(& ll_unitdata_req->sdu);


#endif
#ifdef FLOW_TRACE
        sndcp_trace_flow_control(FLOW_TRACE_SNDCP,
                                 FLOW_TRACE_UP,
                                 FLOW_TRACE_BOTTOM,
                                 FALSE);
#endif
        ll_unitdata_seg_pos = ll_unitdata_req->seg_pos;
        ll_unitdata_nsapi   = su_get_nsapi(ll_unitdata_req);
        ll_unitdata_sapi    = ll_unitdata_req->sapi;

        PSEND(hCommLLC, ll_unitdata_req);

        SET_STATE(SU, SU_LLC_NOT_RECEPTIVE);
        /*
         * If segment is the last of the N-PDU then send ready_ind to nsapi
         * and get next entry from sn q..
         */
        if ((ll_unitdata_seg_pos & SEG_POS_LAST) > 0) {
          sndcp_data->su->cia_state = CIA_IDLE;
          su_next_sn_unitdata_req( ll_unitdata_sapi );
          sig_su_nu_ready_ind( ll_unitdata_nsapi );
        }
      }

      break;
    case SU_LLC_NOT_RECEPTIVE:
      break;
    case SU_LLC_RECEPTIVE:
      break;
    default:
      TRACE_ERROR( "SIG_MG_SU_RESUME unexpected" );
      break;
  }
} /* sig_mg_su_resume() */
#endif /* _SNDCP_DTI_2_ */
/*
+------------------------------------------------------------------------------
| Function    : sig_nu_su_unitdata_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_NU_SU_UNITDATA_REQ
|
| Parameters  : T_SN_UNITDATA_REQ ,  N-PDU to be sent to sapiup in form of
|                                    prim struct
|                                    USHORT,  the send N-PDU number of this N-PDU
|                                    UBYTE, the number of the NSAPI who sent the N-PDU
|                                    UBYTE), the SAPI that is supposed to compute the N-PDU
|
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_nu_su_unitdata_req (T_SN_UNITDATA_REQ* sn_unitdata_req,
                                    USHORT npdu_number,
                                    UBYTE nsapi,
                                    UBYTE sapi
                                    )
{
  UBYTE sapi_index = 0;

#ifdef _SNDCP_MEAN_TRACE_
#ifdef _SNDCP_DTI_2_
  sndcp_mean_trace(nsapi,
                   SNDCP_MEAN_UP,
                   SNDCP_MEAN_UNACK,
                   sn_unitdata_req->desc_list2.list_len);
#else /*_SNDCP_DTI_2_*/
  sndcp_mean_trace(nsapi,
                   SNDCP_MEAN_UP,
                   SNDCP_MEAN_UNACK,
                   sn_unitdata_req->desc_list.list_len);
#endif /*_SNDCP_DTI_2_*/
#endif /* _SNDCP_MEAN_TRACE_ */

  TRACE_ISIG( "sig_nu_su_unitdata_req" );


  /*
   * set service instance according to sapi in signal
   */
  sndcp_get_sapi_index(sapi, &sapi_index);
  sndcp_data->su = & sndcp_data->su_base[sapi_index];

  switch( GET_STATE( SU ) )
  {
    case SU_LLC_RECEPTIVE_SUSPEND:
    case SU_LLC_NOT_RECEPTIVE_SUSPEND:
    case SU_LLC_NOT_RECEPTIVE:
    case SU_LLC_RECEPTIVE:
      /*
       * If queue with NPDUs is empty, and cia is not busy,
       * send the NPDU to cia, else
       * add it to the queue.
       */
      if ((sndcp_data->su->sn_unitdata_q_read ==
           sndcp_data->su->sn_unitdata_q_write) &&
          (sndcp_data->su->ll_unitdesc_q_read ==
           sndcp_data->su->ll_unitdesc_q_write) &&
          sndcp_data->su->cia_state == CIA_IDLE) {
        /*
         * Send the NPDU to cia.
         */
        sndcp_data->su->cia_state = CIA_BUSY;
        sig_su_cia_cia_comp_req(sn_unitdata_req,
                            npdu_number,
                            nsapi,
                            sapi);
      } else { /* Queue with NPDUs is not empty or cia is busy. */
        /*
         * Write the sn_unitdata_req prim to sn_unitdata_q,
         * increment write pointer.
         */
        sndcp_data->su->sn_unitdata_q[sndcp_data->su->sn_unitdata_q_write] =
          sn_unitdata_req;
        sndcp_data->su->npdu_number_q[sndcp_data->su->sn_unitdata_q_write] =
          npdu_number;
        sndcp_data->su->sn_unitdata_q_write =
          (sndcp_data->su->sn_unitdata_q_write + 1) % SN_UNITDATA_Q_LEN;
      } /* Queue with NPDUs is not empty or cia is busy. */
      break;
    default:
      TRACE_ERROR( "SIG_NU_SU_UNITDATA_REQ unexpected" );
#ifdef _SNDCP_DTI_2_
      MFREE_PRIM(sn_unitdata_req);
#else /*_SNDCP_DTI_2_*/
      PFREE_DESC(sn_unitdata_req);
#endif /*_SNDCP_DTI_2_*/
      break;
  }
} /* sig_nu_su_unitdata_req() */

#ifdef _SIMULATION_
#ifdef  _SNDCP_DTI_2_
/*
+------------------------------------------------------------------------------
| Function    : su_send_ll_unitdata_req_test
+------------------------------------------------------------------------------
| Description : Only for test purposes.
|               The given LL_UNITDESC_REQ is copied to an
|               LL_UNITDATA_REQ and sent for the simulated test environment.
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
void su_send_ll_unitdata_req_test(T_LL_UNITDESC_REQ* ll_unitdesc_req)
{
  T_desc3* descriptor = NULL;
  U8* p_data = NULL;
  U16 offset = ENCODE_OFFSET_BYTE;

  PALLOC_SDU(ll_unitdata_req, LL_UNITDATA_REQ, (U16)( ll_unitdesc_req->desc_list3.list_len* 8));

  /*
   * Set parameters in ll_unitdata_req primitive
   */
  ll_unitdata_req->sapi = ll_unitdesc_req->sapi;
  ll_unitdata_req->tlli = ll_unitdesc_req->tlli;
  ll_unitdata_req->ll_qos = ll_unitdesc_req->ll_qos;
  ll_unitdata_req->radio_prio = ll_unitdesc_req->radio_prio;
  ll_unitdata_req->cipher = ll_unitdesc_req->cipher;
  ll_unitdata_req->reserved_unitdata_req1 = ll_unitdesc_req->reserved_unitdata_req1;
  ll_unitdata_req->seg_pos = ll_unitdesc_req->seg_pos;
  ll_unitdata_req->attached_counter = ll_unitdesc_req->attached_counter;
  ll_unitdata_req->reserved_unitdata_req4 = ll_unitdesc_req->reserved_unitdata_req4;
#ifdef REL99
  ll_unitdata_req->pkt_flow_id = ll_unitdesc_req->pkt_flow_id;
#endif /*REL99*/
  /*
   * Set the ENCODE_OFFSET in the uplink sdu, set sdu.l_buf
   */
  ll_unitdata_req->sdu.o_buf = ENCODE_OFFSET;
  ll_unitdata_req->sdu.l_buf = ll_unitdesc_req->desc_list3.list_len* 8;
  /*
   * Copy the data.
   */
  descriptor = (T_desc3*)ll_unitdesc_req->desc_list3.first;
  while (descriptor != NULL)
  {
    T_desc3* help = descriptor;
    p_data = (U8*)descriptor->buffer;
    if (descriptor->len>0)
    {
      memcpy(&ll_unitdata_req->sdu.buf[offset],
             &p_data[descriptor->offset],
             descriptor->len);
    }
    offset += descriptor->len;
    descriptor = (T_desc3*)descriptor->next;
    sndcp_cl_desc3_free(help);
    MFREE(help);
    help = NULL;
  }

  PSEND(hCommLLC, ll_unitdata_req);

  PFREE(ll_unitdesc_req); // MAYBE REMEMBER is this the correct free?

} /* su_send_ll_unitdata_req_test */

#endif /* _SNDCP_DTI_2_ */
#endif /* _SIMULATION_ */