view src/g23m-gsm/sms/sms_rl.c @ 682:17b7b92e7dba

uartfax.c: fix for old Openmoko bug with Auto-CTS Openmoko made the change of enabling hardware assisted CTS flow control in the UART when RTS/CTS flow control is used - it is a change which we have retained in FreeCalypso - but they forgot to turn this hw mode off if RTS/CTS flow control is deselected at the application level. We (FreeCalypso) are now fixing the latter defect ourselves.
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 26 Jun 2020 02:53:02 +0000
parents 27a4235405c6
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  GSM-F&D (8411)
|  Modul   :  SMS_RL
+----------------------------------------------------------------------------- 
|  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 relay layer
|             of the component SMS.
+----------------------------------------------------------------------------- 
*/   

#ifndef SMS_RL_C
#define SMS_RL_C

#define ENTITY_SMS

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

#define SAP_RR    /* get RR causes until all causes are in one document */
#define SAP_MMCM  /* same reason */

#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 "sms_em.h"

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

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

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

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

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

  PURPOSE : Initialize the relay layer.

*/

GLOBAL void rl_init (void)
{
  GET_INSTANCE_DATA;    

  TRACE_FUNCTION ("rl_init()");

  sms_data->data[0].state[STATE_RL] = RL_IDLE;
  sms_data->data[1].state[STATE_RL] = RL_IDLE;
}

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

#ifdef GPRS
GLOBAL void rl_proceed (void)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("rl_proceed()");

  if (SMS_INST_GET_STATE (STATE_RL) EQ RL_WAIT_FOR_SEND_ERROR)
  {
    SMS_INST_SET_STATE (STATE_RL, RL_IDLE);

    tl_report_ind (NULL, CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS,
                   SMSRP_ORIGINATING_ENTITY, SMS_RP_CS_PROTOCOL_ERROR));
  }
}
#endif

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

  PURPOSE : Processing the signal RL_DATA_IND.

*/

GLOBAL void rl_data_ind (T_cp_user_data_dl *cp_user_data_dl)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("rl_data_ind()");

  if (sms_data)
  {
    if (cp_user_data_dl->rp_mti EQ RP_ERROR_DL)
      TRACE_EVENT_P1 ("RP_ERROR.CAUSE rcvd: 0x%2.2X",
                      (int)cp_user_data_dl->rp_error.rp_cause.rp_cause_value);

    switch (SMS_INST_GET_STATE (STATE_RL))
    {
   /* ------------------------------------- */
      case RL_ESTABLISHED:
   /* ------------------------------------- */
      case RL_IDLE:
   /* ------------------------------------- */
      {
        SMS_RP_REF(sms_data) = cp_user_data_dl->reference;
        if (cp_user_data_dl->rp_mti EQ RP_DATA_DL)
        {
         /*
          * RL state transition RL_WAIT_FOR_SEND_ACK
          */
          SMS_INST_SET_STATE (STATE_RL, RL_WAIT_FOR_SEND_ACK);
         /*
          * start timer TR2M
          */
          sms_timer_start(TR2M);

          SMS_EM_RECEIVE_RP_DATA;
         /*
          * TL_DATA_IND =>
          */
          tl_data_ind (&cp_user_data_dl->rp_data_dl);
        }
        else
        {
          MCAST (cp_data, U_CP_DATA);
          /*
           * If Message Id is unknwon then send RP-ERROR with cause #97
           */
          if(cp_user_data_dl->rp_mti > 0x06)
          {
            rl_build_rp_error (cp_user_data_dl->reference,
                               SMS_RP_CS_MSG_NON_EXIST,
                               cp_data, NULL);
          }
          else
          {
            rl_build_rp_error (cp_user_data_dl->reference,
                               SMS_RP_CS_MSG_NOT_COMP,
                               cp_data, NULL);
          }

          SMS_EM_SEND_RP_ERROR;

          cp_data_req (cp_data);
         /*
          * CP_RELEASE_REQ =>
          */
          TRACE_EVENT("CP_RELEASE_REQ_1");
      
          cp_release_req (SMS_INST.ti);
         /*
          * free instance
          */
          FREE_SMS_INSTANCE (SMS_INST.ti);
        }
        break;
      }

   /* ------------------------------------- */
      case RL_WAIT_FOR_ACK:
   /* ------------------------------------- */

        TRACE_FUNCTION ("rl_data_ind(): RP_WAIT_FOR_ACK");

        switch (cp_user_data_dl->rp_mti)
        {
          case RP_ACK_DL:
            TRACE_FUNCTION ("rl_data_ind(): RP_ACK_DL");
           /*
            * stop timer TR1M
            */
            sms_timer_stop(TR1M);
           /*
            * RL state transition RL_IDLE
            */
            SMS_INST_SET_STATE (STATE_RL, RL_IDLE);

            /* 
             * if CMMS mode is 1 or 2 then only make cmm_release_pending TRUE
             */
            if(CMMS_ACTIVE)
            {
               sms_data->cmms_release_pending = TRUE;
            }

           /*
            * TL_REPORT_IND =>
            */
            tl_report_ind (((cp_user_data_dl->rp_ack.v_rp_user_data)?
                            &cp_user_data_dl->rp_ack.rp_user_data:
                            NULL), SMS_NO_ERROR);           

            /* Since the transmission is 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;
            }

            SMS_EM_RECEIVE_RP_AKNOWLEDGE;

            break;

          case RP_ERROR_DL:
            /* When an RP-error with appropriate case value is 
            * is received, Retransmission of SMS is started
            */
          {
#ifdef REL99
            BOOL retrans_flag = FALSE;
#endif
            TRACE_FUNCTION ("rl_data_ind(): RP_ERROR_DL");
           /*
            * stop timer TR1M
            */
            sms_timer_stop(TR1M);
           /* 
            * if CMMS mode is 1 or 2 then only make cmm_release_pending TRUE
            */
            if(CMMS_ACTIVE)
            {
               sms_data->cmms_release_pending = TRUE;
            }
#ifdef REL99
            /*
             * This is done for Retransmission for the causes
             * listed in the table 8.4/3gPP TS 24.011(Part 1)
             */
             if (SMS_INST.tl_retx < TL_MAX_RETANS)
            {             
              /* Check whether the cause value satisfies the one for retransmission 
               *  listed in the table 8.4/3gPP TS 24.011(Part 1)
               */  
              switch(cp_user_data_dl->rp_error.rp_cause.rp_cause_value)
              {
                case SMS_RP_CS_UNASSIGNED_NUMBER:         
                case SMS_RP_CS_OPERATOR_DET_BARRED:       
                case SMS_RP_CS_CALL_BARRED:      
                case SMS_RP_CS_SM_TRANSFER_REJECTED:
                case SMS_RP_CS_MEM_CAP_EXCEEDED:
                case SMS_RP_CS_UNIDENT_SUBSCRIBER:
                case SMS_RP_CS_FACILITY_REJECTED:
                case SMS_RP_CS_UNKNOWN_SUBSCRIBER:
                case SMS_RP_CS_NET_OUT_OF_ORDER:
                case SMS_RP_CS_NO_RESOURCES:
                case SMS_RP_CS_FAC_NOT_SUBSCRIBED:
                case SMS_RP_CS_FAC_NOT_IMPL:
                case SMS_RP_CS_INV_SM_TR_REF_VAL:
                case SMS_RP_CS_SEM_INC_MSG:
                case SMS_RP_CS_INV_MAND_INFO:
                case SMS_RP_CS_MSG_NON_EXIST:
                case SMS_RP_CS_INFO_NON_EXIST:
                case SMS_RP_CS_PROTOCOL_ERROR:
                case SMS_RP_CS_INTERWORKING:
                  retrans_flag = FALSE;
                  break;
                /* All values other than the ones above are treated as temporary
                  failures. This includes SMS_RP_CS_DEST_OUT_OF_ORDER, 
                  SMS_RP_CS_TEMP_FAILURE, SMS_RP_CS_CONGESTION, 
                  SMS_RP_CS_MSG_NOT_COMP and others non-standard values
                  are taken as temporary error */
                default:
                  retrans_flag = TRUE;
                  break;
              }
            }
            if(retrans_flag EQ TRUE)
            {
              TRACE_EVENT ("Retransmission cause received");
              cp_release_req(SMS_INST.ti);
              TIMERSTART (SMS_INST_TR1M, 20000);
              TRACE_EVENT ("Delay expiry TR1M, retransmit");
            }
            else
#endif
            {
              /*
               * RL state transition RL_IDLE
               */
              SMS_INST_SET_STATE (STATE_RL, RL_IDLE);
              tl_report_ind (((cp_user_data_dl->rp_error.v_rp_user_data)?
                            &cp_user_data_dl->rp_error.rp_user_data: NULL),
                           CAUSE_MAKE(DEFBY_STD, ORIGSIDE_NET, SMSRP_ORIGINATING_ENTITY,
                           cp_user_data_dl->rp_error.rp_cause.rp_cause_value));
               SMS_EM_RECEIVE_RP_ERROR;
             }
          }
          break;


          default:
            TRACE_FUNCTION ("rl_data_ind(): default");

           /*
            * stop timer TR1M
            */
            sms_timer_stop(TR1M);

            {
              MCAST (cp_data_ul, U_CP_DATA);
              /*
               * If Message Id is unknwon then send RP-ERROR with cause #97
               */
              if(cp_user_data_dl->rp_mti > 0x06)
              {
                rl_build_rp_error (cp_user_data_dl->reference,
                                   SMS_RP_CS_MSG_NON_EXIST,
                                   cp_data_ul, NULL);
              }
              else
              {
                rl_build_rp_error (cp_user_data_dl->reference,
                                   SMS_RP_CS_PROTOCOL_ERROR,
                                   cp_data_ul, NULL);
              }

              cp_data_req (cp_data_ul);
            }
#ifdef GPRS   /* interworking from flow control */
            if (SMS_LLC_FLOW(sms_data) NEQ SMS_LLC_BUSY_WAITING)
#endif
            {
              SMS_INST_SET_STATE (STATE_RL, RL_IDLE);

              /* 
               * if CMMS mode is 1 or 2 and current link used is GSM then only
               * make cmm_release_pending TRUE
               */
#ifdef GPRS
              if(CMMS_ACTIVE AND (SMS_INST.downlink EQ SMS_DOWNLINK_MMSMS))
              {
                 sms_data->cmms_release_pending = TRUE;
              }
#endif
              /*
              * TL_REPORT_IND =>
              */
             /*
              * If Message Id is unknwon then send TL REPORT IND with cause #97
              */
              if(cp_user_data_dl->rp_mti > 0x06)
              {
                tl_report_ind (NULL, CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS,
                               SMSRP_ORIGINATING_ENTITY, SMS_RP_CS_MSG_NON_EXIST));
              }
              else
              {
                tl_report_ind (NULL, CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS,
                               SMSRP_ORIGINATING_ENTITY, SMS_RP_CS_PROTOCOL_ERROR));
              }
             
            }
#ifdef GPRS
            else
            {
              SMS_INST_SET_STATE (STATE_RL, RL_WAIT_FOR_SEND_ERROR);
            }
#endif

            SMS_EM_RECEIVE_UNKNOWN_2;

            break;
        }

        break;

      case RL_WAIT_FOR_SEND_ACK:
        TRACE_FUNCTION ("rl_data_ind(): RP_WAIT_FOR_SEND_ACK");
        {
          MCAST (cp_data_ul, U_CP_DATA);
         /*
          * If Message Id is unknwon then send RP-ERROR with cause #97
          */
          if(cp_user_data_dl->rp_mti > 0x06)
          {
            rl_build_rp_error (cp_user_data_dl->reference,
                               SMS_RP_CS_MSG_NON_EXIST,
                               cp_data_ul, NULL);
          }
          else
          {
            rl_build_rp_error (cp_user_data_dl->reference,
                               SMS_RP_CS_PROTOCOL_ERROR,
                               cp_data_ul, NULL);
          }
          cp_data_req (cp_data_ul);

        }
        break;

   /* ------------------------------------- */
      case RL_WAIT_FOR_SMMA_ACK:
   /* ------------------------------------- */

        TRACE_FUNCTION ("rl_data_ind(): RP_WAIT_FOR_SMMA_ACK");

        switch (cp_user_data_dl->rp_mti)
        {
          case RP_ACK_DL:
            TRACE_FUNCTION ("rl_data_ind(): RP_ACK_DL");
           /*
            * stop timer TR1M
            */
            sms_timer_stop(TR1M);

            SMS_INST.retrans  = FALSE;
           /*
            * RL state transition RL_IDLE
            */
            SMS_INST_SET_STATE (STATE_RL, RL_IDLE);
           /*
            * TL_REPORT_IND =>
            */
            tl_report_ind (NULL, SMS_NO_ERROR);
            break;

          case RP_ERROR_DL:
            TRACE_FUNCTION ("rl_data_ind(): RP_ERROR_DL");

            if (rl_temp_failure (cp_user_data_dl->rp_error.
                                 rp_cause.rp_cause_value))
            {
              if (SMS_INST.retrans)
              {
               /*
                * RL state transition RL_IDLE
                */
                SMS_INST_SET_STATE (STATE_RL, RL_IDLE);
                SMS_INST.retrans = FALSE;

               /*
                * TL_REPORT_IND =>
                */
                tl_report_ind (NULL,
                               CAUSE_MAKE(DEFBY_STD, ORIGSIDE_NET, SMSRP_ORIGINATING_ENTITY,
                               cp_user_data_dl->rp_error.rp_cause.rp_cause_value));
                sms_timer_stop(TR1M);

                tl_sms_memo_exceeded (TRUE);
               /*
                * stop timer TR1M
                */
              }
              else
              {
                SMS_INST.retrans  = TRUE;
               /*
                * RL state transition RL_WAIT_FOR_RETRANS_TIMER
                */
                SMS_INST_SET_STATE (STATE_RL, RL_WAIT_FOR_RETRANS_TIMER);
               /*
                * stop timer TR1M
                */
                sms_timer_stop(TR1M);
               /*
                * start timer TRAM
                */
                sms_timer_start(TRAM);
               /*
                * CP_RELEASE_REQ =>
                */
                TRACE_EVENT("CP_RELEASE_REQ_11");
                cp_release_req (SMS_INST.ti);
        
              }
            }
            else
            {
             /*
              * stop timer TR1M
              */

              sms_timer_stop(TR1M);
              SMS_INST.retrans  = FALSE;
             /*
              * RL state transition RL_IDLE
              */
              SMS_INST_SET_STATE (STATE_RL, RL_IDLE);
             /*
              * TL_REPORT_IND =>
              */
          
              tl_report_ind (NULL,
                             CAUSE_MAKE(DEFBY_STD, ORIGSIDE_NET, SMSRP_ORIGINATING_ENTITY,
                             cp_user_data_dl->rp_error.rp_cause.rp_cause_value));

              tl_sms_memo_exceeded (TRUE);
                  
            }
            break;

          default:
            TRACE_FUNCTION ("rl_data_ind(): default");
           /*
            * stop timer TR1M
            */
            sms_timer_stop(TR1M);

            SMS_INST.retrans  = FALSE;
           /*
            * RL state transition RL_IDLE
            */
            SMS_INST_SET_STATE (STATE_RL, RL_IDLE);
           /*
            * If Message Id is unknwon then send RP-ERROR with cause #97
            */
            if(cp_user_data_dl->rp_mti > 0x06)
            {
              MCAST (cp_data, U_CP_DATA);
              rl_build_rp_error (cp_user_data_dl->reference,
                                 SMS_RP_CS_MSG_NON_EXIST,
                                 cp_data, NULL);
              SMS_EM_SEND_RP_ERROR;
              cp_data_req (cp_data);
              tl_report_ind (NULL, CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS,
                             SMSRP_ORIGINATING_ENTITY, SMS_RP_CS_MSG_NON_EXIST));
            }
            break;
        }
        break;
    }
  }
}

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

  PURPOSE : Processing the signal RL_ESTABLISH_REQ.

*/

GLOBAL void rl_establish_req (UBYTE ti)
{
  GET_INSTANCE_DATA;
    TRACE_FUNCTION_P1 ("rl_establish_req(TI=%u)", ti);
    switch (SMS_INST_GET_STATE (STATE_RL))
    {
      case RL_IDLE:
       /*
        * RL state transition RL_ESTABLISH
        */
        SMS_INST_SET_STATE (STATE_RL, RL_ESTABLISH);
       /*
        * CP_ESTABLISH_REQ =>
        */
        cp_establish_req(ti);
       /*
        * start timer TR1M
        */
        sms_data->timer_ti = ti;
        sms_timer_start(TR1M);
        break;
      default:
        TRACE_ERROR("RL_ESTABLISH_REQ in wrong state received!");
   }
}

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

  PURPOSE : Processing the signal RL_ESTABLISH_CNF.

*/

GLOBAL void rl_establish_cnf (BOOL         success)
{
   GET_INSTANCE_DATA;
    TRACE_FUNCTION ("rl_establish_cnf()");
    switch (SMS_INST_GET_STATE (STATE_RL))
    {
      case RL_ESTABLISH:
       /*
        * stop timer TR1M
        */
        sms_timer_stop(TR1M);
        if (success EQ TRUE)
        {
          /*
           * RL state transition RL_ESTABLISHED
           */
           SMS_INST_SET_STATE (STATE_RL, RL_ESTABLISHED);
        }
        else
        {
          /*
           * RL state transition RL_IDLE
           */
           SMS_INST_SET_STATE (STATE_RL, RL_IDLE);
        }
       /*
        * TL_ESTABLISH_CNF =>
        */
        tl_establish_cnf(success);
        break;
      default:
        TRACE_ERROR("RL_ESTABLISH_CNF in wrong state received!");
   }
}

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

  PURPOSE : Processing the signal RL_RELEASE_REQ.

*/

GLOBAL void rl_release_req ( UBYTE  ti)
{
    TRACE_FUNCTION_P1 ("rl_release_req(TI=%u)", ti);
   /*
    * CP_RELEASE_REQ =>
    */
    TRACE_EVENT("CP_RELEASE_REQ_13");
    cp_release_req(ti);
}

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

  PURPOSE : Processing the signal RL_DATA_REQ.

*/
GLOBAL BOOL rl_data_req (UBYTE       msg_ref,
                         T_U_CP_DATA *cp_data)
{
  GET_INSTANCE_DATA;    
  TRACE_FUNCTION ("rl_data_req()");

  if (sms_data)
  {
    switch (SMS_INST_GET_STATE (STATE_RL))
    {
      case RL_ESTABLISHED:
      {
        SMS_INST.msg_ref  = msg_ref;
       /*
        * RL state transtion RL_WAIT_FOR_ACK
        */
        SMS_INST_SET_STATE (STATE_RL, RL_WAIT_FOR_ACK);

        SMS_EM_SEND_RP_DATA;

        cp_data->cp_user_data_ul.rp_mti = RP_DATA_UL;
        cp_data->cp_user_data_ul.reference = msg_ref;
       /*
        * CP_DATA_REQ =>
        */
        cp_data_req (cp_data);
       /*
        * start timer TR1M
        */
        sms_timer_start(TR1M);

        return TRUE;
      }
      default:
        TRACE_ERROR("RL_DATA_REQ in wrong state received!");
        break;
    }
  }
  return FALSE;
}

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

  PURPOSE : Processing the signal RL_ERROR_IND.

*/

GLOBAL void rl_error_ind (USHORT     cause)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("rl_error_ind()");

  if (sms_data)
  {
    switch (SMS_INST_GET_STATE (STATE_RL))
    {
   /* --------------------------------- */
      case RL_ESTABLISH:
   /* --------------------------------- */

        if ( SMS_INST.tl_retx < TL_MAX_RETANS )
        {
          switch ( cause )
          {
            case MMCM_MMCS_MESSAGE_INCOMPAT:
            case RRCS_NORM:
              /* 
               * start timer TR1M with value
               */
              TIMERSTART ( SMS_INST_TR1M, 20000 );
              TRACE_EVENT ( "Delay expiry TR1M, retransmit" );
              return;

            default: /* No retransmission */
              break;
          }
        }

       /*
        * stop timer TR1M
        */
        sms_timer_stop(TR1M);
       /*FALLTHROUGH*/ /*lint -fallthrough*/
   /* --------------------------------- */
      case RL_ESTABLISHED:
   /* --------------------------------- */
       /*
        * RL state transition RL_IDLE
        */
        SMS_INST_SET_STATE (STATE_RL, RL_IDLE);
       /*
        * free instance
        */
        FREE_SMS_INSTANCE (SMS_INST.ti);
       /*
        * TL_REPORT_IND
        */
        tl_report_ind (NULL, cause);
        break;

   /* --------------------------------- */
      case RL_WAIT_FOR_ACK:
   /* --------------------------------- */
        TRACE_FUNCTION ("rl_error_ind(): RL_WAIT_FOR_ACK");
        /* 
         * The following code is to implement a subset of 
         * 3GPP 23.040 Release 1999 subclause 9.2.3.6.
         * For certain errors the SMS SUBMIT / SMS COMMAND is repeated
         * after timeout of TR1M.
         */
        TRACE_EVENT_P2 ("TL retrans #%d, error_cs %04x",
                        SMS_INST.tl_retx,
                        cause);

        if (SMS_INST.tl_retx < TL_MAX_RETANS)
        {
          switch (cause)
          {
            case SMS_CAUSE_NET_TIMEOUT:
             /* 11.10 test case 34.2.2 step 68 */
             /*
              * start timer TR1M with value
              */
              TIMERSTART (SMS_INST_TR1M, 20000);
              TRACE_EVENT ("Delay expiry TR1M, retransmit");
              return;

            case RRCS_NORM:
            case MMCM_MMCS_MESSAGE_INCOMPAT: /* Make cingular happy, #19189 */
              TRACE_EVENT ("Retransmission after TR1M");
              return;

            default: /* No retransmission */
              break;
          }
        }
       /*
        * stop timer TR1M
        */
        sms_timer_stop(TR1M);
       /*
        * RL state transition RL_IDLE
        */
        SMS_INST_SET_STATE (STATE_RL, RL_IDLE);
       /*
        * free instance
        */
        FREE_SMS_INSTANCE (SMS_INST.ti);
       /*
        * TL_REPORT_IND =>
        */
        tl_report_ind (NULL, cause);
        break;

   /* --------------------------------- */
      case RL_WAIT_FOR_SEND_ACK:
   /* --------------------------------- */

        TRACE_FUNCTION ("rl_error_ind(): RL_WAIT_FOR_SEND_ACK");
       /*
        * free instance
        */
        FREE_SMS_INSTANCE (SMS_INST.ti);
       /*
        * stop timer TR2M
        */
        sms_timer_stop(TR2M);
       /*
        * RL state transition RL_IDLE
        */
        SMS_INST_SET_STATE (STATE_RL, RL_IDLE);
       /*
        * TL_REPORT_IND =>
        */
        tl_report_ind (NULL, cause);
        break;

   /* --------------------------------- */
        case RL_WAIT_FOR_SMMA_ACK:
   /* --------------------------------- */

        TRACE_FUNCTION ("rl_error_ind(): RL_WAIT_FOR_SMMA_ACK");
        
        // FREE_SMS_INSTANCE (SMS_INST.ti);

        if (SMS_INST.retrans)
        {
         /*
          * RL state transition RL_IDLE
          */
          SMS_INST_SET_STATE (STATE_RL, RL_IDLE);
          SMS_INST.retrans = FALSE;
         /*
          * TL_REPORT_IND =>
          */
          tl_report_ind (NULL, SMS_CAUSE_NET_TIMEOUT);
         /*
          * stop timer TR1M
          */
          sms_timer_stop(TR1M);
          tl_sms_memo_exceeded (TRUE);

        }
        else
        {
          SMS_INST.retrans  = TRUE;
         /*
          * RL state transition RL_WAIT_FOR_RETRANS_TIMER
          */
          SMS_INST_SET_STATE (STATE_RL, RL_WAIT_FOR_RETRANS_TIMER);
         /*
          * stop timer TR1M
          */
          sms_timer_stop(TR1M);
         /*
          * start timer TRAM
          */
          sms_timer_start(TRAM);
         /*
          * CP_RELEASE_REQ =>
          */
          TRACE_EVENT("CP_RELEASE_REQ_15");
          cp_release_req (SMS_INST.ti);

         /*
          * free instance
          */
          FREE_SMS_INSTANCE (SMS_INST.ti);
        }

        break;
    

      default:
        
        if(CMMS_ACTIVE)
        {
           tl_cmms_end();
        }
       /*
        * free instance
        */
        FREE_SMS_INSTANCE (SMS_INST.ti);
       /*
        * RL state transition RL_IDLE
        */
        
        SMS_INST_SET_STATE (STATE_RL, RL_IDLE);
        break;
    }
  }
}

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

  PURPOSE : Processing the signal RL_MEM_AVAIL_REQ.

*/

GLOBAL BOOL rl_mem_avail_req (void)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("rl_mem_avail_req()");

  if (sms_data)
  {
    switch (SMS_INST_GET_STATE (STATE_RL))
    {
      case RL_ESTABLISHED:
      {
        CCD_START;
        {
          MCAST (cp_data, U_CP_DATA);
         /*
          * RL state transition RL_WAIT_FOR_SMMA_ACK
          */
          SMS_INST_SET_STATE (STATE_RL, RL_WAIT_FOR_SMMA_ACK);
          SMS_RP_REF(sms_data) = SMS_INST.tp_mr;

          rl_build_rp_smma (SMS_RP_REF(sms_data), cp_data);

          CCD_END;
         /*
          * CP_DATA_REQ =>
          */
          cp_data_req (cp_data);
        }
       /*
        * start timer TR1M
        */
        sms_timer_start(TR1M);    
        return TRUE;

      default:
        TRACE_ERROR("RL_MEM_AVAIL_REQ in wrong state received!");
        break;
      }
    }
  }
  return FALSE;
}

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

  PURPOSE : Processing the signal RL_START_TRAM_REQ.

*/

GLOBAL void rl_start_tram_req (void)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("rl_start_tram_req()");
          
  SMS_INST.retrans  = TRUE;
 /*
  * RL state transition RL_WAIT_FOR_RETRANS_TIMER
  */
  SMS_INST_SET_STATE (STATE_RL, RL_WAIT_FOR_RETRANS_TIMER);
 /*
  * start timer TRAM
  */
  sms_timer_start(TRAM);
}

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

  PURPOSE : Processing the function RL_BUILD_RP_ACK.

*/

LOCAL void rl_build_rp_ack (UBYTE          msg_ref,
                            T_U_CP_DATA    *cp_data,
                            T_rp_user_data *rp_user_data)
{
  TRACE_FUNCTION ("rl_build_rp_ack()");

  memset (&cp_data->cp_user_data_ul.rp_ack, 0, sizeof (T_rp_ack));

  cp_data->msg_type                  = U_CP_DATA;
  cp_data->cp_user_data_ul.rp_mti    = RP_ACK_UL;
  cp_data->cp_user_data_ul.reference = msg_ref;

  cp_data->cp_user_data_ul.v_rp_data_ul  = FALSE;
  cp_data->cp_user_data_ul.v_rp_error    = FALSE;
  cp_data->cp_user_data_ul.v_rp_ack      = TRUE;

  if (rp_user_data NEQ NULL AND rp_user_data->v_tpdu)
  {
    memcpy (&cp_data->cp_user_data_ul.rp_ack.rp_user_data,
            rp_user_data, sizeof (T_rp_user_data));
    cp_data->cp_user_data_ul.rp_ack.v_rp_user_data = TRUE;
  }
}

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

  PURPOSE : Processing the signal RL_REPORT_REQ_ACK.

*/

GLOBAL void rl_report_req_ack (T_rp_user_data *rp_user_data)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("rl_report_req_ack()");

  if (sms_data)
  {
    switch (SMS_INST_GET_STATE (STATE_RL))
    {
      case RL_WAIT_FOR_SEND_ACK:
      {
        MCAST (cp_data, U_CP_DATA);
       /*
        * stop timer TR2M
        */
        sms_timer_stop(TR2M);

        rl_build_rp_ack (SMS_RP_REF(sms_data), cp_data, rp_user_data);
       /*
        * RL state transition RL_IDLE
        */
        SMS_INST_SET_STATE (STATE_RL, RL_IDLE);
       /*
        * CP_DATA / RP_ACK ==>
        */
        cp_data_req (cp_data);
       /*
        * CP_RELEASE_REQ =>
        */
        TRACE_EVENT("CP_RELEASE_REQ_16");
        cp_release_req (SMS_INST.ti);
        break;
      }
      default:
        break;
    }
  }
}

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

  PURPOSE : Processing the function RL_BUILD_RP_ERROR.

*/

GLOBAL void rl_build_rp_error (UBYTE          msg_ref,
                               USHORT         error,
                               T_U_CP_DATA    *cp_data,
                               T_rp_user_data *rp_user_data)
{
  TRACE_FUNCTION ("rl_build_rp_error()");
  TRACE_EVENT_P1 ("RP_ERROR.CAUSE sent: 0x%2.2X", (int)error);

  memset (&cp_data->cp_user_data_ul.rp_error, 0, sizeof (T_rp_error));

  cp_data->msg_type                  = U_CP_DATA;
  cp_data->cp_user_data_ul.rp_mti    = RP_ERROR_UL;
  cp_data->cp_user_data_ul.reference = msg_ref;

  cp_data->cp_user_data_ul.v_rp_data_ul  = FALSE;
  cp_data->cp_user_data_ul.v_rp_ack      = FALSE;
  cp_data->cp_user_data_ul.v_rp_error    = TRUE;

  cp_data->cp_user_data_ul.rp_error.
           rp_cause.v_rp_cause_value = TRUE;
  if (error < 128)              /* GSM 04.11 cause */
  {
    cp_data->cp_user_data_ul.rp_error.
             rp_cause.rp_cause_value = (UBYTE)error;
  }
  else
  {
    cp_data->cp_user_data_ul.rp_error.
             rp_cause.rp_cause_value = SMS_RP_CS_PROTOCOL_ERROR;
    cp_data->cp_user_data_ul.rp_error.
             v_rp_user_data = TRUE;
  }
  if (rp_user_data NEQ NULL AND rp_user_data->v_tpdu)
  {
    memcpy (&cp_data->cp_user_data_ul.rp_error.rp_user_data,
            rp_user_data, sizeof (T_rp_user_data));
    cp_data->cp_user_data_ul.rp_error.v_rp_user_data = TRUE;
  }
}

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

  PURPOSE : Processing the signal RL_REPORT_REQ_ERROR.

*/

GLOBAL void rl_report_req_error (USHORT         cause,
                                 T_rp_user_data *rp_user_data)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("rl_report_req_error()");

  if (sms_data)
  {
    switch (SMS_INST_GET_STATE (STATE_RL))
    {
      case RL_WAIT_FOR_SEND_ACK:
      {
        MCAST (cp_data, U_CP_DATA);
       /*
        * stop timer TR2M
        */
        sms_timer_stop(TR2M);

        rl_build_rp_error (SMS_RP_REF(sms_data), cause,
                           cp_data, rp_user_data);
       /*
        * RL state transition RL_IDLE
        */
        SMS_INST_SET_STATE (STATE_RL, RL_IDLE);
       /*
        * CP_DATA / RP_ERROR ==>
        */
        cp_data_req (cp_data);
        break;
      }
      default:
        break;
    }
  }
}

#if defined (GPRS)
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_RL                     |
| STATE   : code                ROUTINE : rl_build_rp_error_gprs     |
+--------------------------------------------------------------------+

  PURPOSE : Processing the function RL_BUILD_RP_ERROR for GSMS.

*/

GLOBAL void rl_build_rp_error_gprs (UBYTE              ti,
                                    T_LL_UNITDATA_REQ  *data_req,
                                    USHORT             error,
                                    UBYTE              msg_ref,
                                    T_U_CP_DATA        *cp_data,
                                    T_stk_cmd          *stk_cmd)
{
  TRACE_FUNCTION ("rl_build_rp_error_gprs()");
  TRACE_EVENT_P1 ("RP_ERROR.CAUSE sent: 0x%4.2X", (int)error);

  data_req->sdu.o_buf = ENCODE_OFFSET;

  cp_data->msg_type                  = U_CP_DATA;
  cp_data->cp_user_data_ul.rp_mti    = RP_ERROR_UL;
  cp_data->cp_user_data_ul.reference = msg_ref;

  cp_data->cp_user_data_ul.v_rp_data_ul  = FALSE;
  cp_data->cp_user_data_ul.v_rp_error    = TRUE;

  memset (&cp_data->cp_user_data_ul.rp_error.rp_cause, 0,
          sizeof (T_rp_cause));

  cp_data->cp_user_data_ul.rp_error.
           rp_cause.v_rp_cause_value = TRUE;
  if (error < 128)              /* GSM 04.11 cause */
  {
    cp_data->cp_user_data_ul.rp_error.
             rp_cause.rp_cause_value = (UBYTE)error;
    cp_data->cp_user_data_ul.rp_error.
             v_rp_user_data = FALSE;
  }
  else
  {
    cp_data->cp_user_data_ul.rp_error.
             rp_cause.rp_cause_value = SMS_RP_CS_PROTOCOL_ERROR;
    cp_data->cp_user_data_ul.rp_error.
             v_rp_user_data = TRUE;
    memset (&cp_data->cp_user_data_ul.rp_error.rp_user_data,
            0, sizeof (T_rp_user_data));
    if (error >= 256)           /* no GSM 03.40 cause */
      error = SMS_FCS_UNSPECIFIED;
    cp_data->cp_user_data_ul.rp_error.rp_user_data.
             v_tpdu = TRUE;
  /*
    cp_data->cp_user_data_ul.rp_error.rp_user_data.
             sms_deliver_rep_err.tp_fcs = (UBYTE)error;
   */
  }

  ccd_codeMsg (CCDENT_SMS,
               UPLINK,
               (T_MSGBUF *) &data_req->sdu,
               (UBYTE *) cp_data,
               NOT_PRESENT_8BIT);
  /*lint -e415 -e416 Likely creation/access of out-of-bounds pointer */
  data_req->sdu.buf[3] = (ti << 4) + PD_SMS;
  data_req->sdu.o_buf  = ENCODE_OFFSET - BSIZE_TI_PD;
  data_req->sdu.l_buf += BSIZE_TI_PD;

  if (stk_cmd NEQ NULL)
  {
    /*
     * response from a SIM Toolkit command
     */
    if (stk_cmd->l_cmd NEQ 0)
    {
      /*
       * response TPDU available
       */
      /* change length of rp-error */
      data_req->sdu.buf[5] += ((stk_cmd->l_cmd >> 3) + 2);
      /* add IEI for rp user data */
      data_req->sdu.buf[10] = 0x41;
      /* add length for rp user data */
      data_req->sdu.buf [11] = stk_cmd->l_cmd >> 3;
      /* add TPDU */
      memcpy (&data_req->sdu.buf [12],
              &stk_cmd->cmd[stk_cmd->o_cmd>>3],
              stk_cmd->l_cmd>>3);
      /* modify length of CP Data */
      data_req->sdu.l_buf += (stk_cmd->l_cmd + 16);
    }
  }
  /*lint +e415 +e416 Likely creation/access of out-of-bounds pointer */
}
#endif /* GPRS */

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

  PURPOSE : Processing the function RL_BUILD_RP_SMMA.

*/

GLOBAL void rl_build_rp_smma (UBYTE       msg_ref,
                              T_U_CP_DATA *cp_data)
{
  TRACE_FUNCTION ("rl_build_rp_smma()");

  cp_data->cp_user_data_ul.rp_mti    = RP_SMMA_UL;
  cp_data->cp_user_data_ul.reference = msg_ref;

  cp_data->cp_user_data_ul.v_rp_data_ul = FALSE;
  cp_data->cp_user_data_ul.v_rp_error = FALSE;
  cp_data->cp_user_data_ul.v_rp_ack = FALSE;
}

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

  PURPOSE : Processing the function RL_TEMP_FAILURE.
            This is valid for memory available notification attempt.
            [04.11 Table 8.4 part 3]
*/

GLOBAL UBYTE rl_temp_failure (UBYTE cause)
{
  TRACE_FUNCTION ("rl_temp_failure()");

  switch (cause)
  {
    case SMS_RP_CS_UNKNOWN_SUBSCRIBER:
    case SMS_RP_CS_FAC_NOT_IMPL:
    case SMS_RP_CS_SEM_INC_MSG:
    case SMS_RP_CS_INV_MAND_INFO:
    case SMS_RP_CS_MSG_NON_EXIST:
    case SMS_RP_CS_MSG_NOT_COMP:
    case SMS_RP_CS_INFO_NON_EXIST:
    case SMS_RP_CS_PROTOCOL_ERROR:
    case SMS_RP_CS_INTERWORKING:
      return FALSE; /* Non-temporary */

    default:
      return TRUE;  /* Temporary */
  }
}

#endif /* #ifndef SMS_RL_C */