view gsm-fw/g23m-gsm/sms/sms_tls.c @ 962:f4da3071dd61

doc/High-speed-serial write-up and Linux kernel patch added
author Mychaela Falconia <falcon@ivan.Harhan.ORG>
date Fri, 06 Nov 2015 21:46:05 +0000
parents d10585d665b4
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  GSM-F&D (8411)
|  Modul   :  SMS_TLP
+----------------------------------------------------------------------------- 
|  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 defines the functions for the transfer layer
|             capability of the module Short Message Service.
+----------------------------------------------------------------------------- 
*/ 
 
#ifndef SMS_TLS_C
#define SMS_TLS_C

#include "config.h"
#include "fixedconf.h"
#include "condat-features.h"

#define ENTITY_SMS

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

#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include "typedefs.h"
#include "pcm.h"
#include "vsi.h"
#include "custom.h"
#include "gsm.h"
#include "message.h"
#include "ccdapi.h"
#include "prim.h"
#include "cus_sms.h"
#include "cnf_sms.h"
#include "mon_sms.h"
#include "pei.h"
#include "tok.h"
#include "sms.h"
#include "gdi.h"
#include "sms_em.h"

/*==== EXPORT ======================================================*/

/*==== PRIVAT ======================================================*/

/*==== VARIABLES ===================================================*/

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

LOCAL BOOL tl_modify_is_all (UBYTE modify)
{
  switch (modify)
  {
  case SMS_MODIFY_NON:
  case SMS_MODIFY_SCA:
  case SMS_MODIFY_TPOA:
  case SMS_MODIFY_TPOA_SCA:
    return FALSE;
  default:
    break;
  }
  return TRUE;  /* MODIFY_ALL: complete message is given */
}

LOCAL void tl_send_failure(USHORT cause)
{
  GET_INSTANCE_DATA;
           
  /*
   * release connection
   */
   rl_release_req(SMS_INST.ti);

  /* 
   * Send MNSMS_REPORT_IND indicating the cmms_mode value to ACI
   * if CMMS_MODE is equal to 1or 2.
   */
   if(CMMS_ACTIVE)
   {
      tl_cmms_end();
   }
  /*
   * SUBMIT_CNF
   */
   tl_mnsms_submit_cnf (SMS_SEL_MEM(sms_data),
                        SMS_SEL_REC(sms_data),
                        NOT_PRESENT_8BIT,
                        cause,
                        NULL);
}

/*---- SIGNALS -----------------------------------------------------*/

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_TLS                    |
| STATE   : code                ROUTINE : tl_establish_cnf           |
+--------------------------------------------------------------------+

  PURPOSE : Process the signal TL_ESTABLISH_CNF.

*/

GLOBAL void tl_establish_cnf (
                              BOOL          success)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("tl_establish_cnf()");

#ifdef GPRS
  if (success EQ FALSE) 
  {
     /*
      * Establishment Failed.
      */ 
     if (SMS_INST.downlink EQ SMS_DOWNLINK_LL_CHECK)
     {
        if (sms_data->mo_dst_pref EQ GPRS_SMS_GPRS_PREF)
        {
           /*
             * using the preferred downlink LL failed, use CSD
             */
           TRACE_EVENT("Establishment failed on LL link, try gsm path instead");
           /* 
             * set downlink type MMSMS
             */
           TRACE_EVENT("downlink = SMS_DOWNLINK_MMSMS");
           SMS_INST.downlink = SMS_DOWNLINK_MMSMS;
           /*
             * try again
             */
           rl_establish_req(SMS_INST.ti);
           return;
        }
        else
        {
           /*
             * unsing the preferred downlink LL failed
             */
           TRACE_EVENT("Establishment failed on LL link, stop working");
           /*
             * handle event in report ind
             */
           tl_report_ind(NULL,SMS_CAUSE_NO_SERVICE);
           return;
        }
     }
     
     else if (SMS_INST.downlink EQ SMS_DOWNLINK_MMSMS)
     {
       if(sms_data->mo_dst_pref EQ GPRS_SMS_CCT_PREF)
       {
          /*
            * using the preferred downlink MM failed, use PS
            */
          TRACE_EVENT("Establishment failed on MM link, try gprs path instead");

          /* 
            * set downlink type LL
            */
          TRACE_EVENT("downlink = SMS_DOWNLINK_LL");
          SMS_INST.downlink = SMS_DOWNLINK_LL_CHECK;
          /* 
           * If CMMS_ACTIVE then send the MNSMS_REPORT_IND to ACI informing about
           * the current cmms_mode value as GSM connection is failed.
           */
          if(CMMS_ACTIVE)
          {
            tl_cmms_end();
          }
        
          /*
            * try again
            */
          rl_establish_req(SMS_INST.ti);
          return;
       }
       /*
         * else
         *    <<PS PREF failed CS fallback also failed>> case covered in cp layer.
         */
     }
}
#endif /* #ifdef GPRS */

  switch (SMS_INST_GET_STATE (STATE_TL))
  {
  case TL_ESTABLISH:
     switch (GET_STATE (STATE_EST))
     {
     case EST_SEND:

        tl_establish_cnf_send();
        break;

     case EST_RTX:

        tl_establish_cnf_rtx();
        break;

     case EST_CMD:

        tl_establish_cnf_cmd();
        break;

     case EST_SMMA:

       /*
        * TL state transition: TL_OTHER
        */
        SMS_INST_SET_STATE (STATE_TL, TL_OTHER);
        if (!rl_mem_avail_req ())
        {
          TRACE_EVENT("could not send SMMA");
         /*
          * TL  state transition TL_OTHER
          */
          SMS_INST_SET_STATE (STATE_TL, TL_OTHER);
         /*
          * handle event in report ind
          */
          tl_report_ind(NULL,SMS_CAUSE_ENTITY_BUSY);
        }

        break;
     }
     break;

  default:
    TRACE_ERROR("TL_ESTABLISH_CNF in wrong state received");
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_TLS                    |
| STATE   : code                ROUTINE : tl_establish_cnf_send      |
+--------------------------------------------------------------------+

  PURPOSE : Process the signal TL_ESTABLISH_CNF 
                     in state  TL_SEND_ESTABLISH.

*/

GLOBAL void tl_establish_cnf_send (void)
{
  GET_INSTANCE_DATA;
  drv_Return_Type pcm_result;
  T_SIM_PDU      *sim_pdu;

  TRACE_FUNCTION ("tl_establish_cnf_send()");

    if ( (SMS_SEL_REC(sms_data) NEQ SMS_RECORD_NOT_EXIST) AND
         (!tl_modify_is_all (SMS_MODIFY(sms_data))) )
    {
      /*
       * SEND - MODIFY
       */
       switch (SMS_SEL_MEM(sms_data))
       {
       case MEM_SM:

         if (SMS_SEL_REC(sms_data) <= SMS_SIM_PROP(sms_data).max_record)
         {
            tl_set_access_fifo (ACCESS_BY_MMI);
           /*
            * TL state transition: TL_SEND
            */
            SET_STATE (STATE_MMI, MMI_READ);
            SMS_INST_SET_STATE (STATE_TL, TL_SEND);
            tl_sim_read_record_req (SMS_SEL_REC(sms_data));
         }
         else
         {
            tl_send_failure(SMS_CAUSE_INV_INDEX);
           /*
            * TL state transition: TL_IDLE
            */
            SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
         }
         break;

       case MEM_ME:

         if (SMS_SEL_REC(sms_data) <= SMS_ME_PROP(sms_data).max_record)
         {
            USHORT max_record;
            UBYTE  misc;
            UBYTE  sim_msg[SIZE_EF_SMS];
            MCAST (cp_data, U_CP_DATA);

/* Implements Measure#32: Row 109 */
            pcm_result = pcm_ReadRecord ((UBYTE *)ef_sms_id,
                                         (USHORT)SMS_SEL_REC(sms_data),
                                         SIZE_EF_SMS,
                                         sim_msg, &misc, &max_record);
            if (pcm_result NEQ PCM_OK)
            {
                SMS_ME_PROP(sms_data).max_record = 0;
               /*
                * stop sending
                */
                tl_send_failure(SMS_CAUSE_MEM_FAIL);
               /*
                * TL state transition: TL_IDLE
                */
                SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
                break;
            }
            MALLOC (sim_pdu, sizeof(T_SIM_PDU));
            CCD_START;
           /*
            * modify, prepare submit
            */
            if (tl_modify_submit (sim_pdu, SMS_MODIFY(sms_data),
                                  SMS_SDU(sms_data), sim_msg) AND
                tl_prepare_submit (sim_pdu, cp_data))
            {
              /*  
               *   RL_DATA_REQ
               */
               if (!rl_data_req (SMS_INST.tp_mr, cp_data))
               {
                 /*
                  * stop sending
                  */
                  tl_send_failure(SMS_CAUSE_ENTITY_BUSY);
                 /*
                  * TL state transition: TL_IDLE
                  */
                  SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
               }
               else
               {
                  SMS_EM_MO_SHORT_MESSAGE;
                 /*
                  * TL state transition: TL_SEND
                  */
                  SMS_INST_SET_STATE (STATE_TL, TL_SEND);
               }
            }
            else
            {
               /*
                * stop sending
                */
                tl_send_failure(SMS_CAUSE_PARAM_WRONG);
               /*
                * TL state transition: TL_IDLE
                */
                SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
            }
            CCD_END;
            MFREE (sim_pdu);
         }
         else
         {
           /*
            * stop sending
            */
            tl_send_failure(SMS_CAUSE_INV_INDEX);
           /*
            * TL state transition: TL_IDLE
            */
            SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
         }
         break;

       default:
         /*
          * stop sending
          */
          tl_send_failure(SMS_CAUSE_PARAM_WRONG);
         /*
          * TL state transition: TL_IDLE
          */
          SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
       }
    }
    else  /* no record given, or no previous mem read */
    {
      /*
       * SEND - STRAIGHT
       */
       USHORT cause = SMS_NO_ERROR;

       switch (SMS_SEL_MEM(sms_data))
       {
       case MEM_SM:
         if (SMS_SEL_REC(sms_data) > SMS_SIM_PROP(sms_data).max_record)
         {
            cause = SMS_CAUSE_INV_INDEX;
         }
         break;

       case MEM_ME:
         if (SMS_SEL_REC(sms_data) > SMS_ME_PROP(sms_data).max_record)
         {
            cause = SMS_CAUSE_INV_INDEX;
         }
         break;

       default:
         if (SMS_SEL_REC(sms_data) NEQ SMS_RECORD_NOT_EXIST)
         {
            cause = SMS_CAUSE_PARAM_WRONG;
         }
         break;
       }

       if (cause EQ SMS_NO_ERROR)
       {
          /* Do some additional tests on the SMS SDU */
          if (SMS_SDU(sms_data)->l_buf EQ 0)
          {
             TRACE_ERROR ("MNSMS_SUBMIT_REQ: sms_sdu empty");
             cause = SMS_CAUSE_PARAM_WRONG;
          }
          if ((SMS_SDU(sms_data)->l_buf >> 3) + 
              (SMS_SDU(sms_data)->o_buf >> 3) > SIM_PDU_LEN)
          {
             TRACE_ERROR ("MNSMS_SUBMIT_REQ: sms_sdu out of range");
             cause = SMS_CAUSE_PARAM_WRONG;
          }
       }

       if (cause EQ SMS_NO_ERROR)  /* error on previous parameter check? */
       {
          MCAST (cp_data, U_CP_DATA);
          MALLOC (sim_pdu, sizeof(T_SIM_PDU));

          CCD_START;
          ccd_decodeMsg (CCDENT_SMS, BOTH,
                         (T_MSGBUF *)SMS_SDU(sms_data),
                         (UBYTE *)sim_pdu, SMS_VT_SIM_PDU);
         /*
          * prepare submit
          */
          if (tl_prepare_submit (sim_pdu, cp_data))
          {
            /*  
             *   RL_DATA_REQ
             */
             if (!rl_data_req (SMS_INST.tp_mr, cp_data))
             {
               cause = SMS_CAUSE_ENTITY_BUSY;
             }
             else
             {
               SMS_EM_MO_SHORT_MESSAGE;
              /*
               * TL state transition
               */
               SMS_INST_SET_STATE (STATE_TL, TL_SEND);
             }
          }
          else
          {
             cause = SMS_CAUSE_PARAM_WRONG;
          }

          MFREE (sim_pdu);
          CCD_END;
       }
       if (cause NEQ SMS_NO_ERROR)
       {
         /*
          * stop sending
          */
          tl_send_failure(cause);
         /*
          * TL state transition: TL_IDLE
          */
          SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
       }
    }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_TLS                    |
| STATE   : code                ROUTINE : tl_establish_cnf_rtx       |
+--------------------------------------------------------------------+

  PURPOSE : Process the signal TL_ESTABLISH_CNF 
                     in state  TL_RTX_ESTABLISH.

*/
GLOBAL void tl_establish_cnf_rtx (void)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("tl_establish_cnf_rtx()");

  {
      MCAST (cp_data, U_CP_DATA); /* T_U_CP_DATA */
      BUF_tpdu *tpdu = &cp_data->cp_user_data_ul.rp_data_ul.rp_user_data.tpdu;
     /*
      * check whether data req still exists
      */
      if (SMS_DATA_REQ(sms_data) EQ NULL)
      {
        TRACE_ERROR("Horror: cannot retransmit DATA REQ: buffer gone");
        return;
      }
     /*
      * Inform ACI that MO transmission attempt is still going on
      */
     /* tl_mnsms_send_prog_ind(sms_data); */ /* TCS 4.x and above */

      CCD_START;

     /*
      * Revert addition of PD and TI
      */
      SMS_DATA_REQ(sms_data)->sdu.o_buf += BSIZE_TI_PD;
      SMS_DATA_REQ(sms_data)->sdu.l_buf -= BSIZE_TI_PD;

      ccd_decodeMsg (CCDENT_SMS,
                     UPLINK,
                     (T_MSGBUF *)&SMS_DATA_REQ(sms_data)->sdu,
                     (UBYTE *)cp_data,
                     NOT_PRESENT_8BIT);

     /* 
      * Set the TP-RD bit in the SMS-SUBMIT. 
      * No usage of CCD here, this would be inefficient.
      */
      tpdu->b_tpdu[tpdu->o_tpdu >> 3] |= 0x04;
     /*
      * TL state transition: TL_SEND
      */
      SMS_INST_SET_STATE (STATE_TL, TL_SEND);
     /*
      * RL_DATA_REQ
      */
      rl_data_req (SMS_INST.tp_mr, cp_data);

      CCD_END;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_TLS                    |
| STATE   : code                ROUTINE : tl_establish_cnf_cmd       |
+--------------------------------------------------------------------+

  PURPOSE : Process the signal TL_ESTABLISH_CNF 
                     in state  TL_CMD_ESTABLISH.

*/

GLOBAL void tl_establish_cnf_cmd(void)
{
  GET_INSTANCE_DATA;
  T_SIM_PDU      *sim_pdu;

  TRACE_FUNCTION ("tl_establish_cnf_cmd()");

    CCD_START;

    MALLOC (sim_pdu, sizeof(T_SIM_PDU));
    memset (sim_pdu, 0, sizeof(T_SIM_PDU));

    ccd_decodeMsg (CCDENT_SMS, BOTH,
                   (T_MSGBUF *)SMS_SDU(sms_data),
                   (UBYTE *)sim_pdu, SMS_VT_SIM_PDU);

    if (sim_pdu->tp_mti EQ SMS_COMMAND AND sim_pdu->v_tpdu)
    {
        MCAST (cp_data, U_CP_DATA);

        /* ++SMS_INST.tp_mr; */
        sim_pdu->tpdu.b_tpdu[1]  = SMS_INST.tp_mr;
        SMS_TP_REF_RET(sms_data) = SMS_INST.tp_mr;

        SMS_INST_SET_STATE (STATE_TL, TL_COMMAND);

        SMS_EM_MO_SHORT_MESSAGE_COMMAND;

        cp_data->cp_user_data_ul.v_rp_error = FALSE;
        cp_data->cp_user_data_ul.v_rp_ack = FALSE;
        memset (&cp_data->cp_user_data_ul.rp_data_ul, 0,
                 sizeof (T_rp_data_ul));

        memcpy (&cp_data->cp_user_data_ul.rp_data_ul.rp_addr,
                &sim_pdu->rp_addr, sizeof (T_rp_addr));
        cp_data->cp_user_data_ul.rp_data_ul.rp_user_data.tp_mti
           = sim_pdu->tp_mti;
        memcpy (&cp_data->cp_user_data_ul.rp_data_ul.rp_user_data.tpdu,
                &sim_pdu->tpdu, sizeof (BUF_tpdu));
        cp_data->cp_user_data_ul.rp_data_ul.rp_user_data.v_tpdu
           = TRUE;
        cp_data->cp_user_data_ul.v_rp_data_ul = TRUE;


       /*
        * RL_DATA_REQ
        */
        if (!rl_data_req (SMS_INST.tp_mr, cp_data))
        {
          tl_mnsms_command_cnf (NOT_PRESENT_8BIT, SMS_CAUSE_ENTITY_BUSY, NULL);
        }
    }
    else
    {
       tl_mnsms_command_cnf (NOT_PRESENT_8BIT, SMS_CAUSE_PARAM_WRONG, NULL);
    }

    MFREE (sim_pdu);
    CCD_END;
}
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_TLS                    |
| STATE   : code                ROUTINE : tl_data_ind                |
+--------------------------------------------------------------------+

  PURPOSE : Process the signal DATA_IND.

*/

GLOBAL void tl_data_ind (
                         T_rp_data_dl *rp_data_dl)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("tl_data_ind()");

  /* Valid tp-user data will not be set to TRUE unless futher decoding is done
  * so removed check rp_data_dl->rp_addr.v_tpdu 
  */
  if (rp_data_dl EQ NULL OR !rp_data_dl->rp_addr.v_ton)
  { 
   /*
    * RP_ERROR =>
    */
    rl_report_req_error (SMS_RP_CS_INV_MAND_INFO, NULL);
   /*
    * RL_RELEASE_REQ ==>
    */
    rl_release_req(SMS_INST.ti);
    return;
  }
  switch (rp_data_dl->rp_user_data.tp_mti)
  {
    case SMS_DELIVER:
    {
      MCAST (sms_deliver, TP_DELIVER);

      TRACE_EVENT ("SMS DELIVER");

      if (SMS_RP_RCVD(sms_data) EQ NULL)
      {
        MALLOC (SMS_RP_RCVD(sms_data), sizeof(T_rp_data_dl));
      }
      memcpy (SMS_RP_RCVD(sms_data), rp_data_dl,
              sizeof(T_rp_data_dl));
      
      /*
      *If Valid TP user Data is missing in RP Message, send RP ERROR
      * This is done by checking v_tp_ud field
      */
      if ( ccd_decodeMsg (CCDENT_SMS,
                          DOWNLINK,
                          (T_MSGBUF *)&SMS_RP_RCVD(sms_data)->rp_user_data.tpdu,
                          (UBYTE *)sms_deliver,
                          SMS_VT_DELIVER) EQ ccdError )
      {
       /*
        * RP_ERROR =>
        */
        rl_report_req_error (SMS_RP_CS_INV_MAND_INFO, NULL);
       /*
        * RL_RELEASE_REQ ==>
        */
        rl_release_req(SMS_INST.ti);
        break;
      }

      SMS_INST_SET_STATE (STATE_TL, TL_RECEIVE);

      SMS_DCS(sms_data) = sms_deliver->tp_dcs;
      SMS_PID(sms_data) = sms_deliver->tp_pid;
#ifdef FF_SMS_23430
      if (tl_handle_23430 (sms_deliver))
        return;
#endif
      switch (sms_deliver->tp_pid)
      {
        case SMS_PID_SM_TYPE_0:
          /*
           * "A short message type 0 indicates that the ME must acknowledge
           * receipt of the short message but shall discard its contents."
           * [3GPP 23.040 subclause 9.2.3.9]
           */
          rl_report_req_ack (NULL);
          SMS_INST_SET_STATE (STATE_TL, TL_IDLE);

          MFREE (SMS_RP_RCVD(sms_data));
          SMS_RP_RCVD(sms_data) = NULL;
          break;

        case SMS_PID_REP_SM_TYPE_1:
        case SMS_PID_REP_SM_TYPE_2:
        case SMS_PID_REP_SM_TYPE_3:
        case SMS_PID_REP_SM_TYPE_4:
        case SMS_PID_REP_SM_TYPE_5:
        case SMS_PID_REP_SM_TYPE_6:
        case SMS_PID_REP_SM_TYPE_7:
        case SMS_PID_RET_CALL_MSG:
          /*
           * replace short messages
           */
          tl_replace_message (sms_deliver);
          break;
        case SMS_PID_SIM_DOWNLOAD:
          /*
           * SIM data download
           */
#ifdef SIM_TOOLKIT
          if (sms_data->download_sms AND
              tl_check_class_2 (sms_deliver->tp_dcs))
          {
            tl_build_envelope_sms_download (SMS_RP_RCVD(sms_data));
          }
          else
#endif
            tl_handle_message (sms_deliver);
          break;

#ifdef REL99
        /* Currently EGPRS over TIA/EIA-136 is not supported and hence it 
         * is treated as below. If TIA/EIA-136 is supported, the message 
         * should be passed to ME for routing to the application handling 
         * ANSI-136 data
         */
        case SMS_PID_ANSI_136_R_DATA:  
          if( tl_check_class_2 (sms_deliver->tp_dcs) )
          {
#ifdef SIM_TOOLKIT
            /* Download it to SIM only if both SAT is supported and data download 
             * service is enabled 
             */
            if (sms_data->download_sms)
            {
              tl_build_envelope_sms_download (SMS_RP_RCVD(sms_data));
            }
            else
            {
              /* 11.14 8.d.0 Sec 7.1.1 mentions about storing the message when 
               * If the service "data download via SMS-PP" is not allocated 
               * and activated only for protocol identifier = SIM data download. 
               * Hence discard the message and send NACK indicating inability 
               * to handle the message*/
              T_rp_user_data *rp_ud;
              MALLOC (rp_ud, sizeof(T_rp_user_data));
              rp_ud->tpdu.o_tpdu = 0;
              rp_ud->tp_mti = rp_ud->tpdu.b_tpdu[0] = SMS_DELIVER_REPORT;
              rp_ud->tpdu.b_tpdu[1] = SMS_FCS_TP_PID_UNSPEC;  /* TP-FCS  */
              rp_ud->tpdu.b_tpdu[2] = 0;                      /* TP-PI   */
              rp_ud->tpdu.l_tpdu    = 24;                     /* 3 bytes */
              rp_ud->v_tpdu = TRUE;
              rl_report_req_error (SMS_RP_CS_PROTOCOL_ERROR, rp_ud);
              /*
               * RL_RELEASE_REQ ==>
               */
              rl_release_req( SMS_INST.ti);
              MFREE (rp_ud);
              
              SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
              MFREE (SMS_RP_RCVD(sms_data));
              SMS_RP_RCVD(sms_data) = NULL;
            }
#else
            /*
             * Discard the message and send NACK
             */
            T_rp_user_data *rp_ud;
            MALLOC (rp_ud, sizeof(T_rp_user_data));
            rp_ud->tpdu.o_tpdu = 0;
            rp_ud->tp_mti = rp_ud->tpdu.b_tpdu[0] = SMS_DELIVER_REPORT;
            rp_ud->tpdu.b_tpdu[1] = SMS_FCS_TP_PID_UNSPEC;  /* TP-FCS */
            rp_ud->tpdu.b_tpdu[2] = 0;                    /* TP-PI */
            rp_ud->tpdu.l_tpdu = 24;                      /* 3 bytes */
            rp_ud->v_tpdu = TRUE;
            rl_report_req_error (SMS_RP_CS_PROTOCOL_ERROR, rp_ud);
            /*
             * RL_RELEASE_REQ ==>
             */
            rl_release_req(SMS_INST.ti);
            MFREE (rp_ud);
           
            SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
            MFREE (SMS_RP_RCVD(sms_data));
            SMS_RP_RCVD(sms_data) = NULL;
#endif
          }
          else
          {
            tl_handle_message (sms_deliver);
          }
          break;
#endif /* REL99 */

        case SMS_PID_ME_DEPERSON:
          /*
           * ME de-personalization short message
           */
#ifdef SIM_PERS_OTA
             {
               PALLOC (mnsms_OTA_message_ind, MNSMS_OTA_MESSAGE_IND);
               memcpy (&mnsms_OTA_message_ind->tp_ud, &sms_deliver->tp_ud, sizeof(T_tp_ud));
               mnsms_OTA_message_ind->tp_dcs = sms_deliver->tp_dcs ; 
               mnsms_OTA_message_ind->tp_pid = sms_deliver->tp_pid; 
  #ifdef TI_PS_HCOMM_CHANGE
               PSEND (_hCommMMI, mnsms_OTA_message_ind);
  #else
               PSEND (hCommMMI, mnsms_OTA_message_ind);
  #endif
               break;
             }
#else 
      break;
#endif
        case SMS_PID_ME_DOWNLOAD:
          /*
           * ME download short message
           */
        default:
          tl_handle_message (sms_deliver);
          break;
      }
      break;
    }

    case SMS_STATUS_REPORT:
      TRACE_EVENT ("SMS STATUS REPORT");

      if (sms_data->ds EQ DS1)
      {
        /*
         * only if requested by MMI
         */
        PALLOC (status_ind, MNSMS_STATUS_IND);

        SMS_EM_SMS_STATUS_MESSAGE;

        tl_build_status_rep (rp_data_dl, status_ind);
        PSENDX (MMI, status_ind);

        if (SMS_MT_ACK_MODE(sms_data) EQ SMS_MHC_PH2PLUS)
        {
          SMS_INST_SET_STATE (STATE_TL, TL_RECEIVE);
          break;
        }
      }
      rl_report_req_ack (NULL);
      break;

    default:
     /*
      * RP_ERROR =>
      */
      rl_report_req_error (SMS_RP_CS_SEM_INC_MSG, NULL);
     /*
      * RL_RELEASE_REQ ==>
      */
      rl_release_req(SMS_INST.ti);
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_TLS                    |
| STATE   : code                ROUTINE : tl_timeout_ind             |
+--------------------------------------------------------------------+

  PURPOSE : Process the signal TL_TIMEOUT_IND.

*/
GLOBAL void tl_timeout_ind ( USHORT         timer_id)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("tl_timeout_ind()");

  switch (SMS_INST_GET_STATE (STATE_TL))
  {
 /* -------------------------------------- */
    case TL_ESTABLISH:
 /* -------------------------------------- */

    switch (GET_STATE(STATE_EST))
    {
    case EST_SEND:
      /*
       * Connection establishment for the SUBMIT has failed
       */
       TRACE_EVENT("Connection establishment for SUBMIT request failed");
        
       TRACE_EVENT_P1 ("TL retrans #%d",  SMS_INST.tl_retx);
        
       if (SMS_INST.tl_retx < TL_MAX_RETANS)
       {
         /*
          * Maximum number of TL retransmissions not exceeded.
          * Retry establishment.
          */
          SMS_INST.tl_retx++;
         /*
          * establish connection
          */
#ifdef REL99
          tl_mnsms_send_prog_ind(); 
#endif /* REL99 */
          tl_establish_connection(FALSE);
       }
       else
       {
         /*
          * clean up instance
          */
          if (SMS_SDU(sms_data) NEQ NULL)
          {
             MFREE (SMS_SDU(sms_data));
             SMS_SDU(sms_data) = NULL;
          }
          SMS_SEL_REC(sms_data) = SMS_RECORD_NOT_EXIST;
         /*
          * TL state transition TL_IDLE
          */
          SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
         /*
          * SUBMIT_CNF
          */
          tl_mnsms_submit_cnf (SMS_SEL_MEM(sms_data), 
                               SMS_RECORD_NOT_EXIST,
                               SMS_TP_REF_RET(sms_data),
                               SMS_CAUSE_NET_TIMEOUT,
                               SMS_SDU(sms_data));
         /*
          * End the cmms session
          */
          if(CMMS_ACTIVE)
          {
             tl_cmms_end();
          }

       }
       break;

    case EST_CMD:
      /*
       * Connection establishment for the COMMAND has failed
       */
       TRACE_EVENT("Connection establishment for COMMAND request failed");
        
       TRACE_EVENT_P1 ("TL retrans #%d",  SMS_INST.tl_retx);
        
       if (SMS_INST.tl_retx < TL_MAX_RETANS)
       {
         /*
          * Maximum number of TL retransmissions not exceeded.
          * Retry establishment.
          */
          SMS_INST.tl_retx++;
         /*
          * establish connection
          */
#ifdef REL99
          tl_mnsms_send_prog_ind(); 
#endif
          tl_establish_connection(FALSE);
       }
       else
       {
         /*
          * clean up instance
          */
          if (SMS_SDU(sms_data) NEQ NULL)
          {
             MFREE (SMS_SDU(sms_data));
             SMS_SDU(sms_data) = NULL;
          }
          SMS_SEL_REC(sms_data) = SMS_RECORD_NOT_EXIST;
         /*
          * TL state transition
          */
          SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
         /*
          * COMMAND_CNF
          */
          tl_mnsms_command_cnf (SMS_TP_REF_RET(sms_data),
                                SMS_CAUSE_NET_TIMEOUT,
                                SMS_SDU(sms_data));
       }
       break;

    case EST_RTX:
       TRACE_EVENT("timeout establishment for retransmission ignored");
       break;

    case EST_SMMA:
      /*
       * Connection establishment for the SMMA has failed
       */
       TRACE_EVENT("Connection establishment for SMMA request failed");
        
       TRACE_EVENT_P1 ("TL retrans #%d",  SMS_INST.tl_retx);
        
       if (SMS_INST.tl_retx < TL_MAX_RETANS)
       {
         /*
          * Maximum number of TL retransmissions not exceeded.
          * Retry establishment.
          */
          SMS_INST.tl_retx++;
         /*
          * try again
          */
          SMS_INST.retrans  = TRUE;
         /*
          * establish connection
          */

          tl_establish_connection(FALSE);

       }
       else
       {
         /*
          * TL  state transition TL_OTHER
          */
          SMS_INST_SET_STATE (STATE_TL, TL_OTHER);
         /*
          * handle event in report ind
          */
          tl_report_ind(NULL,SMS_CAUSE_NET_TIMEOUT);
       }
       break;
    }
    break;

 /* -------------------------------------- */
    case TL_SEND:
 /* -------------------------------------- */
      /*
       * sending of the SUBMIT has failed
       */
       TRACE_EVENT("Transmission for SUBMIT request failed");
        
       TRACE_EVENT_P1 ("TL retrans #%d",  SMS_INST.tl_retx);
        
       if (SMS_INST.tl_retx < TL_MAX_RETANS)
       {
         /*
          * Maximum number of TL retransmissions not exceeded.
          * Retry establishment.
          */
          SMS_INST.tl_retx++;
#ifdef REL99
          tl_mnsms_send_prog_ind(); 
#endif /* REl99 */

         /*
          * TL  state transition TL_ESTABLISH
          * EST state transition EST_RTX
          */
          SMS_INST_SET_STATE (STATE_TL, TL_ESTABLISH);
          SET_STATE(STATE_EST,EST_RTX);
         /*
          * establish connection
          */
          tl_establish_connection(FALSE);
       }
       else
       {
         /*
          * clean up instance
          */
          if (SMS_SDU(sms_data) NEQ NULL)
          {
             MFREE (SMS_SDU(sms_data));
             SMS_SDU(sms_data) = NULL;
          }
          SMS_SEL_REC(sms_data) = SMS_RECORD_NOT_EXIST;
         /*
          * TL state transition TL_IDLE
          */
          SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
         /*
          * SUBMIT_CNF
          */
          tl_mnsms_submit_cnf (SMS_SEL_MEM(sms_data), 
                               SMS_RECORD_NOT_EXIST,
                               SMS_TP_REF_RET(sms_data),
                               SMS_CAUSE_NET_TIMEOUT,
                               SMS_SDU(sms_data));
          /*
          * End the cmms session
          */
          if(CMMS_ACTIVE)
          {
             tl_cmms_end();
          }
       }
       break;

 /* -------------------------------------- */
    case TL_COMMAND:
 /* -------------------------------------- */
      /*
       * sending of the COMMAND has failed
       */
       TRACE_EVENT("Transmission for COMMAND request failed");
        
       TRACE_EVENT_P1 ("TL retrans #%d",  SMS_INST.tl_retx);
        
       if (SMS_INST.tl_retx < TL_MAX_RETANS)
       {
         /*
          * Maximum number of TL retransmissions not exceeded.
          * Retry establishment.
          */
          SMS_INST.tl_retx++;
#ifdef REL99
          tl_mnsms_send_prog_ind(); 
#endif /* REl99 */
         /*
          * TL  state transition TL_ESTABLISH
          * EST state transition EST_CMD
          */
          SMS_INST_SET_STATE (STATE_TL, TL_ESTABLISH);
          SET_STATE(STATE_EST,EST_CMD);
         /*
          * establish connection
          */
          tl_establish_connection(FALSE);
       }
       else
       {
         /*
          * clean up instance
          */
          if (SMS_SDU(sms_data) NEQ NULL)
          {
             MFREE (SMS_SDU(sms_data));
             SMS_SDU(sms_data) = NULL;
          }
          SMS_SEL_REC(sms_data) = SMS_RECORD_NOT_EXIST;
         /*
          * TL state transition TL_IDLE
          */
          SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
         /*
          * COMMAND_CNF
          */
          tl_mnsms_command_cnf (SMS_TP_REF_RET(sms_data),
                                SMS_CAUSE_NET_TIMEOUT,
                                SMS_SDU(sms_data));
       }
       break;

 /* -------------------------------------- */
    default:
 /* -------------------------------------- */

       // TRACE_EVENT("TL_TIMEOUT_IND ignored");
       if (timer_id EQ TRAM)
       {
         /*
          * sending of the SMMA has failed
          */
          TRACE_EVENT("Transmission for SMMA failed");
         /*
          *  ??? !!! ???
          */
          --SMS_RP_REF(sms_data);
         /*
          * TL  state transition TL_ESTABLISH
          * EST state transition EST_SMMA
          */
          SMS_INST_SET_STATE (STATE_TL, TL_ESTABLISH);
          SET_STATE(STATE_EST,EST_SMMA);
         /*
          * try again
          */
          SMS_INST.retrans  = TRUE;
         /*
          * establish connection
          */
          tl_establish_connection(FALSE);
       }
       else
       {
          tl_report_ind(NULL,SMS_CAUSE_NET_TIMEOUT);
       }
       break;
  }
}
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_TLS                    |
| STATE   : code                ROUTINE : tl_report_ind              |
+--------------------------------------------------------------------+

  PURPOSE : Process the signal TL_REPORT_IND.

*/

LOCAL UBYTE tl_check_condx_send (T_BACKUP *prop,
                                 UBYTE    mem_type,
                                 UBYTE    condx,
                                 UBYTE    rec_num)
{
  if (condx EQ SMS_CONDX_OVR_NON)
  {
    if ((rec_num = tl_get_free_space (mem_type)) NEQ 0)
      return rec_num;
    else
      return SMS_RECORD_NOT_EXIST;
  }
  else if (condx EQ SMS_CONDX_OVR_MO)
  {
    switch (tl_get_status (prop, rec_num - 1))
    {
    case SMS_RECORD_REC_UNREAD:
    case SMS_RECORD_REC_READ:
      if ((rec_num = tl_get_free_space (mem_type)) NEQ 0)
        return rec_num;
      return SMS_RECORD_NOT_EXIST;

    default:
      break;
    }
  }
  return rec_num;
}

GLOBAL void tl_report_ind (T_rp_user_data *rp_user_data,
                           USHORT         cause)
{
  GET_INSTANCE_DATA;
  T_SIM_PDU *sim_pdu;
  UBYTE rec_num, next_rec_num = 0;

  TRACE_FUNCTION ("tl_report_ind()");

#ifdef REL99
  if (cause NEQ SMS_NO_ERROR)
  {
    SMS_INST.failed_msg_rec_num = SMS_SEL_REC(sms_data);
    SMS_INST.failed_msg_mem = SMS_SEL_MEM(sms_data);
  }
#endif

  if (sms_data)
  {
    if (SMS_SDU(sms_data) NEQ NULL)
    {
      MFREE (SMS_SDU(sms_data));
      SMS_SDU(sms_data) = NULL;
    }

    /* 
     * An SMS DELIVER REPORT TPDU is carried as a RP User Data element within
     * an RP ERROR PDU and is part of the negative acknowledgement to an SMS 
     * DELIVER or SMS STATUS REPORT.
     *
     * An SMS DELIVER REPORT TPDU is also carried as a RP User Data element 
     * within an RP ACK PDU and is part of a positive acknowledgement to a 
     * SMS DELIVER or SMS STATUS REPORT.
     * [3gpp 23.040 clause 9.2.2.1a]
     * 
     * The cause value (invalid / non-invalid) is used to distinguish whether
     * the RP user data (SMS DELIVER REPORT) came with RP-ACK / RP-ERROR.
     */

    if (IS_CAUSE_INVALID(cause) AND
        (rp_user_data NEQ NULL AND rp_user_data->v_tpdu))
    {
      MALLOC (sim_pdu, sizeof(T_SIM_PDU));
      MALLOC (SMS_SDU(sms_data), sizeof(T_sms_sdu));

      memset (&sim_pdu->rp_addr, 0, sizeof(T_rp_addr));
      sim_pdu->tp_mti = rp_user_data->tp_mti;
      sim_pdu->tpdu = rp_user_data->tpdu;
      sim_pdu->v_tpdu = TRUE;
      sim_pdu->tp_vt_mti = SMS_VT_SIM_PDU;

      SMS_SDU(sms_data)->o_buf = 0;
      SMS_SDU(sms_data)->l_buf = SIM_PDU_LEN<<3;
      if (ccd_codeMsg (CCDENT_SMS, BOTH,
                       (T_MSGBUF *)SMS_SDU(sms_data),
                       (UBYTE *)sim_pdu, SMS_VT_SIM_PDU) NEQ ccdOK)
      {
        MFREE (SMS_SDU(sms_data));
        SMS_SDU(sms_data) = NULL;
      }
      MFREE (sim_pdu);
    }
    switch (SMS_INST_GET_STATE (STATE_TL))
    {
 /* -------------------------------------- */
    case TL_ESTABLISH:
 /* -------------------------------------- */

       switch (GET_STATE(STATE_EST))
       {
       case EST_SEND:
       case EST_RTX:
         /*
          * TL state transition TL_SEND
          */
          SMS_INST_SET_STATE (STATE_TL, TL_SEND);
          break;
       case EST_CMD:
         /*
          * TL state transition TL_COMMAND
          */
          SMS_INST_SET_STATE (STATE_TL, TL_COMMAND);
          break;
       case EST_SMMA:
          if (SMS_INST.retrans)
          {
             SMS_INST.retrans = FALSE;
            /*
             * TL state transition TL_OTHER
             */
             SMS_INST_SET_STATE (STATE_TL, TL_OTHER);
          }
          else
          {
            /*
             * RL_START_TRAM_REQ
             */
             rl_start_tram_req();
             return;
          }
          break;
       default:
          TRACE_ERROR("Invalid EST state!");
         /*
          * TL state transition TL_IDLE
          */
          SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
          break;
       }
      /*
       * TL_REPORT_IND recursive
       */
       tl_report_ind(rp_user_data,cause);
       return;

 /* -------------------------------------- */
    case TL_SEND:
 /* -------------------------------------- */

      if (!IS_CAUSE_INVALID(cause) AND
          (rp_user_data NEQ NULL) AND (SMS_INST.tl_retx > 0))
      {
        /* 
         * Retransmission case as of 23.040 subclause 9.2.3.6
         * and RP ERROR with RP USER DATA received. Check whether 
         * the RP USER DATA contains a SMS SUBMIT REPORT with TP-FCS set to
         * "SM Rejected - Duplicate SM".
         * If so the transmission has been a success and not a failure.
         */
        MCAST (tp_sbmt_rep_err, TP_SBMT_REP_ERR); /* T_TP_SBMT_REP_ERR */
        BUF_tpdu *tpdu = &rp_user_data->tpdu;
        BYTE ccd_result;

        switch (tpdu->b_tpdu[tpdu->o_tpdu >> 3] & 0x3)
        {
          case SMS_SUBMIT_REPORT:
            /* Copy tpdu from rp_user_data, it's part of decoded msg buffer */
            MALLOC (tpdu, sizeof(BUF_tpdu));
            memcpy (tpdu, &rp_user_data->tpdu, sizeof (BUF_tpdu));
            
            CCD_START;
            ccd_result = ccd_decodeMsg (CCDENT_SMS, DOWNLINK, 
                                        (T_MSGBUF *)tpdu,
                                        (UBYTE *)tp_sbmt_rep_err,
                                        SMS_VT_SBMT_REP_ERR);
            if (ccd_result NEQ ccdOK)
            {
              /* Could error handling be elaborated here? */
              TRACE_ERROR ("ccd decoding problem");
            }

            if (tp_sbmt_rep_err->tp_fcs EQ SMS_FCS_REJ_DUPL_SM)
            {
              TRACE_EVENT ("SC had SMS");
              cause = SMS_NO_ERROR; /* Enter "no error" handling below */
              /* Since the transmission was successful, the data stored for 
                 retransmission can be freed */
              if (SMS_DATA_REQ(sms_data) NEQ NULL)
              {
                PFREE (SMS_DATA_REQ(sms_data));
                SMS_DATA_REQ(sms_data) = NULL;
              }
            }
            CCD_END;

            MFREE (tpdu);
            break;

          default:
            break; /* Do nothing, it is an error */
        }
      }

      if (IS_CAUSE_INVALID(cause) AND SMS_SEL_REC(sms_data) > 0)
      {
        if (SMS_SEL_MEM(sms_data) EQ MEM_SM AND
            SMS_SEL_REC(sms_data) <= SMS_SIM_PROP(sms_data).max_record)
        {
          if ((rec_num = tl_check_condx_send (&SMS_SIM_PROP(sms_data),
                                              MEM_SM,
                                              SMS_CONDX(sms_data),
                                              SMS_SEL_REC(sms_data)))
               NEQ SMS_RECORD_NOT_EXIST)
            SMS_SEL_REC(sms_data) = rec_num;
          else
          {
#ifdef REL99
            if(SMS_INST.failed_msg_retx EQ FALSE)
            {
#endif
              tl_mnsms_submit_cnf (MEM_SM, SMS_RECORD_NOT_EXIST,
                                   SMS_TP_REF_RET(sms_data),
                                   SMS_CAUSE_MEM_FULL, SMS_SDU(sms_data));
#ifdef REL99
            }
            else
            {
              tl_mnsms_retrans_cnf (MEM_SM, SMS_RECORD_NOT_EXIST,
                                   SMS_TP_REF_RET(sms_data),
                                   SMS_CAUSE_MEM_FULL, SMS_SDU(sms_data));              
            }    
#endif
            
            break;
          }
          {
              UBYTE   sim_acc_ix;
              T_SMS_SIM_ACCESS_INFO   *sms_sim_access_info_ptr;
              if (tl_sms_reserve_req_id(&sim_acc_ix))
              {
                PALLOC (update_req, SIM_UPDATE_RECORD_REQ);
                sms_sim_access_info_ptr = &sms_data->sms_sim_access_info[sim_acc_ix];
                update_req->source    = SRC_SMS;
                update_req->req_id     = sim_acc_ix;
                update_req->v_path_info = FALSE;
                update_req->datafield = sms_sim_access_info_ptr->datafield   
                                      = SIM_SMS;
                update_req->record    = sms_sim_access_info_ptr->rec_num     
                                      = SMS_SEL_REC(sms_data);
                update_req->length    = SIM_LENGTH_SMS_RECORD;

                tl_convert_mo_to_mem (SMS_DATA_REQ(sms_data),
                                      update_req->linear_data);

                PSENDX (SIM, update_req);
              }
          }
          tl_store_status (&SMS_SIM_PROP(sms_data), rec_num-1, SIM_SMS_PENDING);
          tl_set_access_fifo (ACCESS_BY_MMI);
          SET_STATE (STATE_MMI, MMI_REPLACE);
         /*
          * concat control
          */
          if (sms_data->concat_cntrl.concatenation NEQ TRUE)
          {
            /*
             * RL_RELEASE_REQ ==>
             */
             rl_release_req(SMS_INST.ti);
          }
          return;
        }
        if (SMS_SEL_MEM(sms_data) EQ MEM_ME AND
            SMS_SEL_REC(sms_data) <= SMS_ME_PROP(sms_data).max_record)
        {
          UBYTE data[SIZE_EF_SMS];

          if ((rec_num = tl_check_condx_send (&SMS_ME_PROP(sms_data),
                                              MEM_ME,
                                              SMS_CONDX(sms_data),
                                              SMS_SEL_REC(sms_data)))
               NEQ SMS_RECORD_NOT_EXIST)
            SMS_SEL_REC(sms_data) = rec_num;
          else
          {
#ifdef REL99
            if(SMS_INST.failed_msg_retx EQ FALSE)
            {
#endif
              tl_mnsms_submit_cnf (MEM_ME, SMS_RECORD_NOT_EXIST,
                                 SMS_TP_REF_RET(sms_data),
                                 SMS_CAUSE_MEM_FULL, SMS_SDU(sms_data));
#ifdef REL99
            }
            else
            {
              tl_mnsms_retrans_cnf (MEM_ME, SMS_RECORD_NOT_EXIST,
                                    SMS_TP_REF_RET(sms_data),
                                    SMS_CAUSE_MEM_FULL, SMS_SDU(sms_data));              
            }
#endif
            break;
          }
          tl_convert_mo_to_mem (SMS_DATA_REQ(sms_data), data);
/* Implements Measure#32: Row 113 */
          if (pcm_WriteRecord ((UBYTE *)ef_sms_id, SMS_SEL_REC(sms_data),
                               SIZE_EF_SMS, data) NEQ DRV_OK)
          {
            cause = SMS_CAUSE_MEM_FAIL;
          }
        }
      }
     /*
      * MNSMS_SUBMIT_CNF =>
      */
#ifdef REL99
      if(SMS_INST.failed_msg_retx EQ FALSE)
      {
#endif
        tl_mnsms_submit_cnf (SMS_SEL_MEM(sms_data), SMS_RECORD_NOT_EXIST,
                     SMS_TP_REF_RET(sms_data), cause, SMS_SDU(sms_data));
#ifdef REL99
      }
      else
      {
        tl_mnsms_retrans_cnf (SMS_SEL_MEM(sms_data), SMS_RECORD_NOT_EXIST,
                     SMS_TP_REF_RET(sms_data), cause, SMS_SDU(sms_data));        
      }    
#endif
     /*
      * concat control
      */
      if ((sms_data->concat_cntrl.concatenation EQ TRUE) AND !CMMS_ACTIVE)
      {
         if (cause EQ SMS_NO_ERROR)
         {
           /*
            * start timer TLCT for next submit req supervision
            */
            sms_timer_start(TLCT);
           /*
            * TL State Transition TL_SEND_CONTD
            */
            SMS_INST_SET_STATE (STATE_TL, TL_SEND_CONTD);
           /*
            * do not release connection now
            */
            sms_data->concat_cntrl.release_pending = TRUE;
            return;
         }
         else
         {
           /*
            * error case: end concatenation series
            */
            sms_data->concat_cntrl.concatenation = FALSE;
         }
      }
      else
      {
      /*
      * cmms control
      */
      if(CMMS_ACTIVE AND (sms_data->cmms_release_pending EQ TRUE))
      {
         tl_cmms_start();
         SMS_INST_SET_STATE (STATE_TL, TL_SEND_CONTD);

         if (sms_data->concat_cntrl.concatenation EQ TRUE)
         {
            if (cause EQ SMS_NO_ERROR)
            {
               sms_data->concat_cntrl.release_pending = TRUE;
            }
            else
            {
           /*
            * error case: end concatenation series
            */
               sms_data->concat_cntrl.concatenation = FALSE;
            }
         }
         return;
      }
      else
      if(CMMS_ACTIVE)
      {
         tl_cmms_end();
      }
      }
      break;

 /* -------------------------------------- */
    case TL_COMMAND:
 /* -------------------------------------- */

#ifdef REL99
      if(SMS_INST.failed_msg_retx EQ FALSE)
      {
#endif

        tl_mnsms_command_cnf (SMS_TP_REF_RET(sms_data), cause, SMS_SDU(sms_data));
#ifdef REL99
      }
      else
      {
        tl_mnsms_retrans_cnf (NOT_PRESENT_8BIT, SMS_RECORD_NOT_EXIST,
                     SMS_TP_REF_RET(sms_data), cause, SMS_SDU(sms_data));        
      }
#endif

      break;

 /* -------------------------------------- */
    case TL_RECEIVE:
 /* -------------------------------------- */

      if (!IS_CAUSE_INVALID(cause))
      {
        switch (GET_STATE (STATE_NET))
        {
        case NET_WRITE:
        case NET_READ:
          break;
        default:
          if (SMS_MT_ACK_MODE(sms_data) EQ SMS_MHC_PH2PLUS)
            tl_mnsms_error_ind ((USHORT)((GET_CAUSE_DEFBY(cause) EQ DEFBY_CONDAT)?
                                cause: SMS_CAUSE_NET_TIMEOUT));
          break;
        }
        SET_STATE (STATE_NET, NET_IDLE);
      }

 /* -------------------------------------- */
    case TL_OTHER:
 /* -------------------------------------- */

      if (GET_STATE (STATE_MMI) EQ MMI_DELETE)
      {
        if (!tl_sms_memo_exceeded (TRUE))
        {        
          if(SMS_REC_STATUS(sms_data) NEQ CMGD_DEL_INDEX)
          {
            if(SMS_SEL_MEM(sms_data) EQ MEM_SM)
            {
              /* Status value is given. Find the next record satisfying this status value */
              next_rec_num = tl_search_record_for_delete (&SMS_SIM_PROP(sms_data), 
                                                          SMS_SEL_REC(sms_data), 
                                                          SMS_REC_STATUS(sms_data));
            }
            else if(SMS_SEL_MEM(sms_data) EQ MEM_ME)
            {
              /* Status value is given. Find the next record satisfying this status value */
              next_rec_num = tl_search_record_for_delete (&SMS_ME_PROP(sms_data), 
                                                          SMS_SEL_REC(sms_data), 
                                                          SMS_REC_STATUS(sms_data));
            }
          }
          tl_mnsms_delete_cnf (SMS_SEL_MEM(sms_data), SMS_SEL_REC(sms_data), next_rec_num,
                                                                            SIM_NO_ERROR);
          SET_STATE (STATE_MMI, MMI_IDLE);
          #ifdef SIM_TOOLKIT
          if (sms_data->file_update_ind NEQ NULL)
          {
            T_SIM_FILE_UPDATE_IND *file_update_ind = sms_data->file_update_ind;
            sms_data->file_update_ind = NULL;
            tl_sim_file_update_ind (file_update_ind);
          }
          #endif
          break;
        }
        else
        {
         /*
          * RL_RELEASE_REQ ==>
          */
          rl_release_req(SMS_INST.ti);
          return;
        }
      }
      else if (GET_STATE (STATE_MMI) EQ MMI_RESUME)
      {
        /*
         *  <<acknowledgment>> of SMMA message for
         *      user initiated RESUME
         *  we expect here that the given tl_report_ind signal
         *  is generated in the following cases:
         *  - success (positive ack for smma)
         *  - error   (negative ack for smma)
         *  - repeated timeout (waiting for ack exceeded limit)
         */
        /*
         * Unset memory full condition in any case
         */
         sms_data->pr_cntrl.delivery_state = SMS_DELIVER_STATUS_RESUME;
        /*
         * save cause
         */
         if (IS_CAUSE_INVALID(cause))
         {
            sms_data->pr_cntrl.save_cause = SMS_NO_ERROR;
         }
         else
         {
            sms_data->pr_cntrl.save_cause = cause;
         }
        /*
         * Unset notification flag on sim
         */
         tl_sms_memo_resume();
         break;
      }
      else if (GET_STATE (STATE_MMI) NEQ MMI_IDLE)
      {
        SET_STATE (STATE_MMI, MMI_IDLE);
        #ifdef SIM_TOOLKIT
        if (sms_data->file_update_ind NEQ NULL)
        {
          T_SIM_FILE_UPDATE_IND *file_update_ind = sms_data->file_update_ind;
          sms_data->file_update_ind = NULL;
          tl_sim_file_update_ind (file_update_ind);
        }
        #endif
        break;
      }
      /*FALLTHROUGH*/ /*lint -fallthrough*/

 /* -------------------------------------- */
    case TL_IDLE:
 /* -------------------------------------- */

      if (SMS_ENT_STATE(sms_data) EQ SMS_STATE_INITIALISING)
      {
        if (!tl_sms_memo_exceeded (TRUE))
        {
          tl_mnsms_report_ind (SMS_ENT_STATE(sms_data) = SMS_STATE_READY);
          break;
        }
        else
        {
         /*
          * RL_RELEASE_REQ ==>
          */
          rl_release_req(SMS_INST.ti);
          return;
        }
      }
      break;

 /* -------------------------------------- */
    default:
 /* -------------------------------------- */

      TRACE_EVENT("TL_REPORT_IND ignored");
      break;
    }

    if (SMS_SDU(sms_data) NEQ NULL)
    {
      MFREE (SMS_SDU(sms_data));
      SMS_SDU(sms_data) = NULL;
    }
    SMS_SEL_REC(sms_data) = SMS_RECORD_NOT_EXIST;
   /*
    * TL State Transition TL_IDLE
    */
    SMS_INST_SET_STATE (STATE_TL, TL_IDLE);
   /*
    * RL_RELEASE_REQ ==>
    */
    rl_release_req(SMS_INST.ti);
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_TLF                    |
| STATE   : code                ROUTINE : tl_cmms_end                |
+--------------------------------------------------------------------+

  PURPOSE : Function used for ending the CMMS Session

*/

GLOBAL void tl_cmms_end(void)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("tl_cmms_end()");

  sms_data->cmms_release_pending = FALSE;
  sms_timer_stop(TMMS);
  tl_mnsms_cmms_end_ind();
}

#endif /* #ifndef SMS_TLS_C */