view src/g23m-fad/rlp/rlp_kerf.c @ 252:27f17fbf0657

FCHG: add dependency on ETM for BSIM
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 12 May 2021 03:18:50 +0000
parents fa8dc04885d8
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  GSM-F&D (8411)
|  Modul   :  RLP_KERF
+----------------------------------------------------------------------------- 
|  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 procedures and functions for
|             the component Radio Link Protocol of the mobile station
+----------------------------------------------------------------------------- 
*/ 

#ifndef RLP_KERF_C
#define RLP_KERF_C
#endif

#define ENTITY_RLP

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

#include <string.h>
#include "typedefs.h"
#include "pconst.cdg"
#include "vsi.h"
#include "macdef.h"
#include "pconst.cdg"
#include "custom.h"
#include "gsm.h"
#include "cnf_rlp.h"
#include "mon_rlp.h"
#include "prim.h"
#include "pei.h"
#include "tok.h"
#include "ccdapi.h"
#include "rlp.h"

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

/*==== TYPES =======================================================*/

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

/*==== VAR LOCAL ===================================================*/

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

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_initTRCVS           |
+--------------------------------------------------------------------+

  PURPOSE : Initialise the TCRVS table

*/

LOCAL void ker_initTRCVS(T_RCVS_ENTRY *rcvsTab)
{
  T_FRAME_NUM lookUp;

  TRACE_FUNCTION ("ker_initTRCVS()");

  for (lookUp = 0; lookUp < MAX_SREJ_COUNT; lookUp++)
  {
    rcvsTab[lookUp].isFree       = TRUE;
    rcvsTab[lookUp].slot         = INVALID_IDX;
    rcvsTab[lookUp].trcvs_running = FALSE;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)             MODULE  : RLP_KERF            |
| STATE   : code                       ROUTINE : ker_init            |
+--------------------------------------------------------------------+

  PURPOSE : initialise the rlp data for the kernel process

*/

GLOBAL void ker_init(void)
{
  TRACE_FUNCTION ("ker_init()");

  rlp_data->tul_rcv_running = FALSE;

  ker_initTRCVS(rlp_data->ker.rcvsTab);

  rlp_data->ker.DM_State   = IS_IDLE;
  rlp_data->ker.DM_FBit    = 0;

  rbm_reset(&rlp_data->rbm);

  INIT_STATE(KER, RLP_ADM_AND_DETACHED);
  INIT_STATE(KERXID_C, ISW_IDLE);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)             MODULE  : RLP_KERF            |
| STATE   : code                       ROUTINE : ker_get_xid_data    |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL void ker_get_xid_data
            (
              T_RLP_FRAMEDATA *raw_data,
              UBYTE           index,
              T_RLP_XID_IND   *xid_data,
              BOOL             ms_is_initiator,
              ULONG           *used_flags
            )
{
  UBYTE p_type;
  UBYTE length;
  UBYTE comp_request;

#ifdef _SIMULATION_
  USHORT rcvd;
  char trc_buf[80];
  UBYTE i, idx;

  strcpy (trc_buf, "get XID ");
  idx = strlen(trc_buf);
#endif

  TRACE_FUNCTION ("ker_get_xid_data()");

  rlp_data->ker.Rlp_Vers  = DEF_RLP_VERS;
  rlp_data->ker.K_ms_iwf  = DEF_K_MS_IWF;
  rlp_data->ker.K_iwf_ms  = DEF_K_IWF_MS;
  rlp_data->ker.T1        = rlp_data->ker.Def_T1;
  rlp_data->ker.T2        = DEF_T2;
  rlp_data->ker.N2        = DEF_N2;
  rlp_data->ker.Pt        = DEF_PT;
  rlp_data->ker.P0        = DEF_P0;
  rlp_data->ker.P1        = DEF_P1;
  rlp_data->ker.P2        = DEF_P2;

  *used_flags = 0L;

  while (index < rlp_data->ker.FrameSize - HEADER_LEN - TRAILER_LEN)
  {
    length = raw_data[index] % 16;
    p_type = (raw_data[index] - length) / 16;

    if (p_type EQ XID_T_NULL)
      break;

#ifdef _SIMULATION_
    for (i = 0; i < length+1; i++)
    {
      /*lint -e661 : Possible access of out-of-bounds pointer (1 beyond end of data) by operator 'unary * */
      HEX_BYTE (raw_data[index+i], &trc_buf[idx]);
      /*lint +e661 */
      idx+=2;
    }
#endif

    switch (p_type)
    {

      case XID_T_T1:
        rlp_data->ker.T1 = TIME_EXT2INT(raw_data[index+1]);
#ifdef _SIMULATION_
        rcvd = rlp_data->ker.T1;
#endif
        if (rlp_data->ker.T1 < rlp_data->ker.Orig_T1)
          rlp_data->ker.T1 = rlp_data->ker.Orig_T1;
        *used_flags |= UF_SET_T1;

#ifdef _SIMULATION_
        TRACE_EVENT_P2("RCVD XID T1   : %d -> %d", rcvd, rlp_data->ker.T1);
#endif
        break;

      case XID_T_RLP_VERS:
        rlp_data->ker.Rlp_Vers = raw_data[index+1];
#ifdef _SIMULATION_
        rcvd = rlp_data->ker.Rlp_Vers;
#endif
        if (rlp_data->ker.Rlp_Vers > ORIG_RLP_VERS)
          rlp_data->ker.Rlp_Vers = ORIG_RLP_VERS;

        *used_flags |= UF_SET_RLP_VERS;
#ifdef _SIMULATION_
        TRACE_EVENT_P2("RCVD XID RLPV : %d -> %d", rcvd, rlp_data->ker.Rlp_Vers);
#endif
        break;

      case XID_T_T2:
        rlp_data->ker.T2 = TIME_EXT2INT(raw_data[index+1]);
#ifdef _SIMULATION_
        rcvd = rlp_data->ker.T2;
#endif
        if (rlp_data->ker.T2 < rlp_data->ker.Orig_T2)
          rlp_data->ker.T2 = rlp_data->ker.Orig_T2;

        *used_flags |= UF_SET_T2;
#ifdef _SIMULATION_
        TRACE_EVENT_P2("RCVD XID T2   : %d -> %d", rcvd, rlp_data->ker.T2);
#endif
        break;

      case XID_T_K_MS_IWF:
        rlp_data->ker.K_ms_iwf = raw_data[index+1];
#ifdef _SIMULATION_
       rcvd = rlp_data->ker.K_ms_iwf;
#endif
        if (rlp_data->ker.K_ms_iwf > rlp_data->ker.Orig_K_ms_iwf)
          rlp_data->ker.K_ms_iwf = rlp_data->ker.Orig_K_ms_iwf;

        if (rlp_data->ker.Connected)
          sbm_set_wind_size (rlp_data->ker.K_ms_iwf);

        *used_flags |= UF_SET_K_MS_IWF;
#ifdef _SIMULATION_
        TRACE_EVENT_P2("RCVD XID KMI  : %d -> %d", rcvd, rlp_data->ker.K_ms_iwf);
#endif
        break;

      case XID_T_N2:
        rlp_data->ker.N2 = raw_data[index+1];
#ifdef _SIMULATION_
        rcvd = rlp_data->ker.N2;
#endif
        if (rlp_data->ker.N2 < rlp_data->ker.Orig_N2)
          rlp_data->ker.N2 = rlp_data->ker.Orig_N2;

        sbm_set_retrans (rlp_data->ker.N2);
        *used_flags |= UF_SET_N2;
#ifdef _SIMULATION_
        TRACE_EVENT_P2("RCVD XID N2   : %d -> %d", rcvd, rlp_data->ker.N2);
#endif
        break;

      case XID_T_K_IWF_MS:
        rlp_data->ker.K_iwf_ms = raw_data[index+1];
#ifdef _SIMULATION_
        rcvd = rlp_data->ker.K_iwf_ms;
#endif
        if (rlp_data->ker.K_iwf_ms > rlp_data->ker.Orig_K_iwf_ms)
          rlp_data->ker.K_iwf_ms = rlp_data->ker.Orig_K_iwf_ms;

        if (rlp_data->ker.Connected)
          if (rbm_set_wind_size (rlp_data->ker.K_iwf_ms))
          {
            ker_reset_all_t_rcvs ();
            srm_reset();
          }

        *used_flags |= UF_SET_K_IWF_MS;
#ifdef _SIMULATION_
        TRACE_EVENT_P2("RCVD XID KIM  : %d -> %d", rcvd, rlp_data->ker.K_iwf_ms);
#endif
        break;

      case XID_T_COMPR:
        comp_request = raw_data[index+1] % 16;
        rlp_data->ker.Pt = (raw_data[index+1] - comp_request) / 16;
#ifdef _SIMULATION_
        TRACE_EVENT_P1("RCVD XID PT   : %d", rlp_data->ker.Pt);
#endif

        switch (comp_request)
        {
        case 0:
          rlp_data->ker.P0 = RLP_COMP_DIR_NONE;
          break;

        case 1:
          if (ms_is_initiator)
          {
            if (rlp_data->ker.Orig_P0 EQ RLP_COMP_DIR_RECEIVE
            OR  rlp_data->ker.Orig_P0 EQ RLP_COMP_DIR_NONE)
              rlp_data->ker.P0 = RLP_COMP_DIR_NONE;
            else
              rlp_data->ker.P0 = RLP_COMP_DIR_TRANSMIT;
          }
          else
          {
            if (rlp_data->ker.Orig_P0 EQ RLP_COMP_DIR_TRANSMIT
            OR  rlp_data->ker.Orig_P0 EQ RLP_COMP_DIR_NONE)
              rlp_data->ker.P0 = RLP_COMP_DIR_NONE;
            else
              rlp_data->ker.P0 = RLP_COMP_DIR_RECEIVE;
          }
          break;

        case 2:
          if (ms_is_initiator)
          {
            if (rlp_data->ker.Orig_P0 EQ RLP_COMP_DIR_TRANSMIT
            OR  rlp_data->ker.Orig_P0 EQ RLP_COMP_DIR_NONE)
              rlp_data->ker.P0 = RLP_COMP_DIR_NONE;
            else
              rlp_data->ker.P0 = RLP_COMP_DIR_RECEIVE;
          }
          else
          {
            if (rlp_data->ker.Orig_P0 EQ RLP_COMP_DIR_RECEIVE
            OR  rlp_data->ker.Orig_P0 EQ RLP_COMP_DIR_NONE)
              rlp_data->ker.P0 = RLP_COMP_DIR_NONE;
            else
              rlp_data->ker.P0 = RLP_COMP_DIR_TRANSMIT;
          }
          break;

        case 3:
          rlp_data->ker.P0 = rlp_data->ker.Orig_P0;
          break;

        }

#ifdef _SIMULATION_
        TRACE_EVENT_P2("RCVD XID P0: %d -> %d", comp_request, rlp_data->ker.P0);
#endif
        rlp_data->ker.P1 = (raw_data[index+3] * 256) +  raw_data[index+2];
#ifdef _SIMULATION_
        rcvd = rlp_data->ker.P1;
#endif
        if (rlp_data->ker.P1 > rlp_data->ker.Orig_P1)
          rlp_data->ker.P1 = rlp_data->ker.Orig_P1;

#ifdef _SIMULATION_
        TRACE_EVENT_P2("RCVD XID P1: %d -> %d", rcvd, rlp_data->ker.P1);
#endif

        rlp_data->ker.P2 = raw_data[index+4];
#ifdef _SIMULATION_
        rcvd = rlp_data->ker.P2;
#endif
        if (rlp_data->ker.P2 > rlp_data->ker.Orig_P2)
          rlp_data->ker.P2 = rlp_data->ker.Orig_P2;

        *used_flags |= UF_SET_COMPR;
#ifdef _SIMULATION_
        TRACE_EVENT_P2("RCVD XID P2   : %d -> %d", rcvd, rlp_data->ker.P2);
#endif
        break;
    }
    index += (length+1);
  }

  xid_data->rlp_vers = rlp_data->ker.Rlp_Vers;
  xid_data->k_ms_iwf = rlp_data->ker.K_ms_iwf;
  xid_data->k_iwf_ms = rlp_data->ker.K_iwf_ms;
  
  xid_data->t1 = TIME_INT2EXT (rlp_data->ker.T1);
  xid_data->t2 = TIME_INT2EXT (rlp_data->ker.T2);

  xid_data->n2 = rlp_data->ker.N2;
  xid_data->pt = rlp_data->ker.Pt;
  xid_data->p0 = rlp_data->ker.P0;
  xid_data->p1 = rlp_data->ker.P1;
  xid_data->p2 = rlp_data->ker.P2;

#ifdef _SIMULATION_
  trc_buf[idx] = '\0';
  TRACE_EVENT (trc_buf);
#endif
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)             MODULE  : RLP_KERF            |
| STATE   : code                       ROUTINE : ker_put_xid_data    |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL void ker_put_xid_data
            (
              T_RLP_FRAMEPTR   l_Data,          /* buffer for data  */
              UBYTE            index,           /* start index in buffer */
              ULONG            l_uf,            /* valid parameters */
              BOOL             ms_is_initiator, /* MS is sending XID*/
              UBYTE            l_rlp_version,   /* negotiated vers. */
              T_FRAME_NUM      l_k_iwf_ms,      /* winSize ms->iwf  */
              T_FRAME_NUM      l_k_ms_iwf,      /* winSize iwf->ms  */
              USHORT           l_t1,            /* ack timer value  */
              UBYTE            l_n2,            /* num restransmiss */
              USHORT           l_t2,            /* reply delay      */
              UBYTE            l_pt,            /* type data compr. */
              UBYTE            l_p0,            /* v42bis comp. req */
              USHORT           l_p1,            /* num possible code*/
              UBYTE            l_p2             /* max encod. strlen*/
            )
{
  register ULONG i;

  TRACE_FUNCTION ("ker_put_xid_data()");

  i = index;

  if (((l_uf & UF_SET_RLP_VERS) EQ 0) OR (l_rlp_version < 1))
  {
    l_uf &= ~UF_SET_COMPR;
  }

  if (l_uf & UF_SET_RLP_VERS)
  {
    l_Data[i]   = (XID_T_RLP_VERS * 16) + XID_L_RLP_VERS;
    l_Data[i+1] = l_rlp_version;
#ifdef _SIMULATION_
    TRACE_EVENT_P1("SEND XID RLPV : %d", l_rlp_version);
#endif
    i += (XID_L_RLP_VERS + 1);
  }

  if (l_uf & UF_SET_K_IWF_MS)
  {
    l_Data[i]   = (XID_T_K_IWF_MS * 16) + XID_L_K_IWF_MS;
    l_Data[i+1] = (UBYTE) l_k_iwf_ms;
#ifdef _SIMULATION_
    TRACE_EVENT_P1("SEND XID KIM  : %d", l_k_iwf_ms);
#endif
    i += (XID_L_K_IWF_MS + 1);
  }

  if (l_uf & UF_SET_K_MS_IWF)
  {
    l_Data[i]   = (XID_T_K_MS_IWF * 16) + XID_L_K_MS_IWF;
    l_Data[i+1] = (UBYTE) l_k_ms_iwf;
#ifdef _SIMULATION_
    TRACE_EVENT_P1("SEND XID KMI  : %d", l_k_ms_iwf);
#endif
    i += (XID_L_K_MS_IWF + 1);
  }

  if (l_uf & UF_SET_T1)
  {
    l_Data[i]   = (XID_T_T1 * 16) + XID_L_T1;
    l_Data[i+1] = TIME_INT2EXT (l_t1);
#ifdef _SIMULATION_
    TRACE_EVENT_P1("SEND XID T1   : %d", l_t1);
#endif
    i += (XID_L_T1 + 1);
  }

  if (l_uf & UF_SET_N2)
  {
    l_Data[i]   = (XID_T_N2 * 16) + XID_L_N2;
    l_Data[i+1] = l_n2;
#ifdef _SIMULATION_
    TRACE_EVENT_P1("SEND XID N2   : %d", l_n2);
#endif
    i += (XID_L_N2 + 1);
  }

  if (l_uf & UF_SET_T2)
  {
    l_Data[i]   = (XID_T_T2 * 16) + XID_L_T2;
    l_Data[i+1] = TIME_INT2EXT (l_t2);
#ifdef _SIMULATION_
    TRACE_EVENT_P1("SEND XID T2   : %d", l_t2);
#endif
    i += (XID_L_T2 + 1);
  }

  if ( (l_uf & UF_SET_COMPR) AND !rlp_data->ker.Connected)
  {
    l_Data[i]   = (XID_T_COMPR * 16) + XID_L_COMPR;

    switch (l_p0)
    {
      case RLP_COMP_DIR_NONE:
        l_Data[i+1] = l_pt * 16;
        break;

      case RLP_COMP_DIR_TRANSMIT:
        if (ms_is_initiator)
          l_Data[i+1] = (l_pt*16) + 1;
        else
          l_Data[i+1] = (l_pt*16) + 2;
        break;

      case RLP_COMP_DIR_RECEIVE:
        if (ms_is_initiator)
          l_Data[i+1] = (l_pt*16) + 2;
        else
          l_Data[i+1] = (l_pt*16) + 1;
        break;

      case RLP_COMP_DIR_BOTH:
        l_Data[i+1] = (l_pt*16) + 3;
        break;
    }
    l_Data[i+2] = (l_p1 % 256);
    l_Data[i+3] = (l_p1 / 256);
    l_Data[i+4] = l_p2;
#ifdef _SIMULATION_
    TRACE_EVENT_P1("SEND XID PT: %d", l_pt);
    TRACE_EVENT_P2("SEND XID P0: %d -> %d", l_p0, l_Data[i+1] % 4);
    TRACE_EVENT_P1("SEND XID P1: %d", l_p1);
    TRACE_EVENT_P1("SEND XID P2: %d", l_p2);
#endif
    i += (XID_L_COMPR + 1);
  }

#ifdef _SIMULATION_
  {
  char trc_buf[80];
  U8 j, k;

  strcpy (trc_buf, "put XID ");
  k = strlen(trc_buf);
  for (j = index; j < i; j++)
  {
    /*lint -e661 : Possible access of out-of-bounds pointer (1 beyond end of data) by operator 'unary * */
    HEX_BYTE (l_Data[j], &trc_buf[k]);
    /*lint +e661 */
    k += 2;
  }
  trc_buf[k] = '\0';
  TRACE_EVENT (trc_buf);
  }
#endif

}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_check_low_water     |
+--------------------------------------------------------------------+

  PURPOSE :

*/

LOCAL void ker_check_low_water(void)
{
  TRACE_FUNCTION ("ker_check_low_water()");

  if (sbm_space_in_buf () >= rlp_data->ker.FramesPerPrim)
  {
    if (rlp_data->ker.UL_Snd_State EQ IW_IDLE)
    {
      PALLOC (rlp_ready_ind, RLP_READY_IND);

      PSENDX (L2R, rlp_ready_ind);
      rlp_data->ker.UL_Snd_State = IW_WAIT;
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_get_send_frame      |
+--------------------------------------------------------------------+

  PURPOSE :

*/

LOCAL void ker_get_send_frame
            (
              T_FRAME_DESC *frameDesc,
              T_FRAME_NUM  *frameNo,
              BOOL         *frameFound
            )
{
  BOOL framesCouldBeSent;

  TRACE_FUNCTION ("ker_get_send_frame()");

  if (rlp_data->ker.RRReady)
  {
    sbm_get_frame
    (
      frameDesc,
      frameNo,
      &framesCouldBeSent,
      frameFound
    );

    if (framesCouldBeSent)
      ker_check_low_water ();
  }
  else
  {
    /*
     * remote receiver can not accept data
     */
    *frameFound = FALSE;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_startTRCVS          |
+--------------------------------------------------------------------+

  PURPOSE : Start the timer TRCVS for a slot

*/

LOCAL void ker_startTRCVS(T_FRAME_NUM slot)
{
  T_FRAME_NUM lookUp;

  TRACE_FUNCTION ("ker_startTRCVS()");

  for (lookUp = 0; lookUp < MAX_SREJ_COUNT; lookUp++)
  {
    if (rlp_data->ker.rcvsTab[lookUp].isFree)
    {
      rlp_data->ker.rcvsTab[lookUp].slot = slot;
      TIMERSTART(lookUp, rlp_data->ker.T1);
      rlp_data->ker.rcvsTab[lookUp].trcvs_running = TRUE;
      rlp_data->ker.rcvsTab[lookUp].isFree = FALSE;
      return;
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_send_srej_sreji_cmd |
+--------------------------------------------------------------------+

  PURPOSE :

*/

LOCAL void ker_send_srej_sreji_cmd(T_FRAME_NUM slot)
{
  T_FRAME_DESC frameDesc;
  T_FRAME_NUM  frame;
  BOOL         frameFound;


  rlp_data->ker.DTX_SF       = DTX_N;

  TRACE_FUNCTION ("ker_send_srej_sreji_cmd()");

  if (rlp_data->ker.Poll_xchg NEQ IW_WAIT
  AND rlp_data->ker.Poll_State EQ ISW_SEND)
  {
    sig_ker_snd_srej_req (1, 1, slot);
    rbm_set_rslot_wait (slot);

    ker_startTRCVS (slot);

    srm_count (slot);

    rlp_data->ker.SREJ_Count++;
    rlp_data->ker.Poll_Count++;
    rlp_data->ker.Poll_State = ISW_WAIT;
    rlp_data->ker.Poll_xchg  = IW_WAIT;

    TIMERSTART (TT_HANDLE, rlp_data->ker.T1);
  }
  else
  {
    ker_get_send_frame (&frameDesc, &frame, &frameFound);

    if (frameFound)
    {
      sig_ker_snd_srej_i_req (1, 0, slot, frame, &frameDesc);

      rbm_set_rslot_wait (slot);

      ker_startTRCVS (slot);

      srm_count (slot);

      rlp_data->ker.SREJ_Count++;

      TIMERSTART (TT_HANDLE, rlp_data->ker.T1);
    }
    else
    {
      sig_ker_snd_srej_req (1, 0, slot);

      rbm_set_rslot_wait (slot);

      ker_startTRCVS (slot);

      srm_count (slot);

      rlp_data->ker.SREJ_Count++;
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_send_rej_reji_cmd   |
+--------------------------------------------------------------------+

  PURPOSE :

*/

LOCAL void ker_send_rej_reji_cmd
            (
              T_FRAME_NUM      vr
            )
{
  T_FRAME_DESC frameDesc;
  T_FRAME_NUM  frame;
  BOOL         frameFound;

  TRACE_FUNCTION ("ker_send_rej_reji_cmd()");

  rlp_data->ker.DTX_SF       = DTX_N;

  if (rlp_data->ker.Poll_xchg NEQ IW_WAIT AND rlp_data->ker.Poll_State EQ ISW_SEND)
  {
    sig_ker_snd_rej_req (1, 1, vr);

    rlp_data->ker.Ackn_State = IS_IDLE;
    rlp_data->ker.REJ_State  = ISW_WAIT;

    TIMERSTART
    (
      TRCVR_HANDLE,
      rlp_data->ker.T1
    );
    rlp_data->ker.Poll_Count++;
    rlp_data->ker.Poll_State = ISW_WAIT;
    rlp_data->ker.Poll_xchg  = IW_WAIT;

    TIMERSTART (TT_HANDLE, rlp_data->ker.T1);
  }
  else
  {
    ker_get_send_frame (&frameDesc, &frame, &frameFound);

    if (frameFound)
    {
      sig_ker_snd_rej_i_req (1, 0, vr, frame, &frameDesc);

      TIMERSTART (TT_HANDLE, rlp_data->ker.T1);
    }
    else
      sig_ker_snd_rej_req (1, 0, vr);

    TIMERSTART(TRCVR_HANDLE, rlp_data->ker.T1);
    rlp_data->ker.Ackn_State = IS_IDLE;
    rlp_data->ker.REJ_State  = ISW_WAIT;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_send_rnr_rnri_cmd   |
+--------------------------------------------------------------------+

  PURPOSE :

*/

LOCAL void ker_send_rnr_rnri_cmd
            (
              T_FRAME_NUM      vr
            )
{
  T_FRAME_DESC frameDesc;
  T_FRAME_NUM  frame;
  BOOL         frameFound;

  TRACE_FUNCTION ("ker_send_rnr_rnri_cmd()");

  if (rlp_data->ker.Poll_xchg NEQ IW_WAIT
  AND rlp_data->ker.Poll_State EQ ISW_SEND)
  {
    sig_ker_snd_rnr_req (1, 1, vr, 0);

    rlp_data->ker.Ackn_State = IS_IDLE;
    rlp_data->ker.Poll_Count++;
    rlp_data->ker.Poll_State = ISW_WAIT;
    rlp_data->ker.Poll_xchg  = IW_WAIT;

    rlp_data->ker.DTX_SF       = DTX_N;

    TIMERSTART (TT_HANDLE, rlp_data->ker.T1);
  }
  else
  {
    ker_get_send_frame (&frameDesc, &frame, &frameFound);

    if (frameFound)
    {
      sig_ker_snd_rnr_i_req (1, 0, vr, frame, &frameDesc);

      rlp_data->ker.Ackn_State = IS_IDLE;

      rlp_data->ker.DTX_SF       = DTX_N;

      TIMERSTART (TT_HANDLE, rlp_data->ker.T1);
    }
    else
    {
      if (rlp_data->ker.Ackn_State EQ IS_IDLE
      AND rlp_data->ker.DTX_SF EQ DTX_RNR
      AND rlp_data->ker.DTX_VR EQ vr)
      {
        sig_ker_snd_rnr_req (1, 0, vr, 1);
      }
      else
      {
        sig_ker_snd_rnr_req (1, 0, vr, 0);

        rlp_data->ker.Ackn_State = IS_IDLE;
        rlp_data->ker.DTX_SF     = DTX_RNR;
        rlp_data->ker.DTX_VR     = vr;
      }
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_send_rr_rri_cmd     |
+--------------------------------------------------------------------+

  PURPOSE :

*/

LOCAL void ker_send_rr_rri_cmd
            (
              T_FRAME_NUM      vr
            )
{
  T_FRAME_DESC frameDesc;
  T_FRAME_NUM  frame;
  BOOL         frameFound;

  TRACE_FUNCTION ("ker_send_rr_rri_cmd()");

  if (rlp_data->ker.Poll_xchg NEQ IW_WAIT AND rlp_data->ker.Poll_State EQ ISW_SEND)
  {

#ifdef ENABLE_DTX
    sig_ker_snd_rr_req (1, 1, vr, 0);
#else
    sig_ker_snd_rr_req (1, 1, vr);
#endif

    rlp_data->ker.Ackn_State = IS_IDLE;
    rlp_data->ker.Poll_Count++;
    rlp_data->ker.Poll_State = ISW_WAIT;
    rlp_data->ker.Poll_xchg  = IW_WAIT;

    rlp_data->ker.DTX_SF       = DTX_N;

    TIMERSTART (TT_HANDLE, rlp_data->ker.T1);
  }
  else
  {
    ker_get_send_frame (&frameDesc, &frame, &frameFound);

    if (frameFound)
    {
      sig_ker_snd_rr_i_req (1, 0, vr, frame, &frameDesc);

      rlp_data->ker.Ackn_State = IS_IDLE;

      TIMERSTART (TT_HANDLE, rlp_data->ker.T1);
      rlp_data->ker.DTX_SF       = DTX_N;

    }
    else
    {
      if (rlp_data->ker.Ackn_State EQ IS_IDLE
      AND rlp_data->ker.DTX_SF EQ DTX_RR
      AND rlp_data->ker.DTX_VR EQ vr)
      {
#ifdef ENABLE_DTX
        sig_ker_snd_rr_req (1, 0, vr, 1);
#else
        sig_ker_snd_rr_req (1, 0, vr);
#endif
      }
      else
      {
#ifdef ENABLE_DTX
        sig_ker_snd_rr_req (1, 0, vr, 0);
#else
        sig_ker_snd_rr_req (1, 0, vr);
#endif
        rlp_data->ker.Ackn_State = IS_IDLE;
        rlp_data->ker.DTX_SF     = DTX_RR;
        rlp_data->ker.DTX_VR     = vr;
      }
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_send_rnr_rnri_resp  |
+--------------------------------------------------------------------+

  PURPOSE :

*/

LOCAL void ker_send_rnr_rnri_resp
            (
              T_FRAME_NUM      vr
            )
{

  TRACE_FUNCTION ("ker_send_rnr_rnri_resp()");

  sig_ker_snd_rnr_req (0, 1, vr, 0);

  rlp_data->ker.Ackn_State = IS_IDLE;
  rlp_data->ker.Ackn_FBit  = 0;
  rlp_data->ker.DTX_SF     = DTX_N;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_send_rr_rri_resp    |
+--------------------------------------------------------------------+

  PURPOSE :

*/

LOCAL void ker_send_rr_rri_resp(T_FRAME_NUM vr)
{

  TRACE_FUNCTION ("ker_send_rr_rri_resp()");

#ifdef ENABLE_DTX
  sig_ker_snd_rr_req (0, 1, vr, 0);
#else
  sig_ker_snd_rr_req (0, 1, vr);
#endif

  rlp_data->ker.Ackn_State = IS_IDLE;
  rlp_data->ker.Ackn_FBit  = 0;
  rlp_data->ker.DTX_SF     = DTX_N;

}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_copy_frame_to_sdu   |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL void ker_copy_frame_to_sdu
            (
              T_RLP_FRAMEPTR  frame,
              T_sdu          *sdu
            )
{
  TRACE_FUNCTION ("ker_copy_frame_to_sdu()");

  memcpy (sdu->buf+(sdu->o_buf>>3), frame, rlp_data->ker.FrameSize);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_copy_sdu_to_frame   |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL void ker_copy_sdu_to_frame(T_sdu *sdu, T_RLP_FRAMEPTR frame, USHORT n)
{
  TRACE_FUNCTION ("ker_copy_sdu_to_frame()");

  memcpy(frame, sdu->buf + (sdu->o_buf>>3) + (n * rlp_data->ker.FrameSize),
                rlp_data->ker.FrameSize);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_get_frame_desc      |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL void ker_get_frame_desc
            (
              T_RLP_FRAMEPTR  frame,
              T_FRAME_DESC   *frameDesc
            )
{
  TRACE_FUNCTION ("ker_get_frame_desc()");

  frameDesc->Adr[0] = frame;
  frameDesc->Len[0] = rlp_data->ker.FrameSize;
  frameDesc->Adr[1] = (UBYTE *) NULL;
  frameDesc->Len[1] = 0;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_handle_prim_send    |
+--------------------------------------------------------------------+

  PURPOSE :

*/

LOCAL void ker_handle_prim_send(void)
{
  TRACE_FUNCTION ("ker_handle_prim_send()");

  if (rlp_data->ker.UL_Rcv_State EQ IW_WAIT)
  {
    T_RLP_DATA_IND *rlp_data_ind;

    rbm_get_prim(&rlp_data_ind, &rlp_data->ker.LRReady, &rlp_data->ker.LRFull);

    PSENDX (L2R, rlp_data_ind);
    rlp_data->ker.UL_Rcv_State = IW_IDLE;
    TIMERSTOP (TUL_RCV_HANDLE);
    rlp_data->tul_rcv_running = FALSE;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_stopTRCVS           |
+--------------------------------------------------------------------+

  PURPOSE : search the rcvs entry for a given timer handle. The
            function stops the timer and returns the corresponding
            slot.

*/

LOCAL void ker_stopTRCVS
            (
              T_FRAME_NUM slot
            )
{
  T_FRAME_NUM lookUp;

  TRACE_FUNCTION ("ker_stopTRCVS()");

  for (lookUp = 0; lookUp < MAX_SREJ_COUNT; lookUp++)
  {
    if (!rlp_data->ker.rcvsTab[lookUp].isFree AND rlp_data->ker.rcvsTab[lookUp].slot EQ slot)
    {
      TIMERSTOP(lookUp);
      rlp_data->ker.rcvsTab[lookUp].trcvs_running = FALSE;
      rlp_data->ker.rcvsTab[lookUp].isFree = TRUE;
      return;
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_i_handler           |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL BOOL ker_i_handler(T_FRAME_NUM ns)
{
  TRACE_FUNCTION ("ker_i_handler()");

  if (rlp_data->ker.LRFull)
  {
    /*
     * ignore improper frame
     * cBit and fBit are not considered
     * at this stage
     */
    return TRUE;
  }
  else
  {
    BOOL        valid, expected, resetTimer, primToSend;
    T_FRAME_NUM count;

    rbm_ns_check (ns, &valid, &expected);

    /*
     * ns not within window?
     */
    if (!valid)
    {
      /*
       * ignore improper frame
       */
      return TRUE;
    }

    TIMERSTOP (TUL_RCV_HANDLE); /* optimisation trial... */
    /*
    TRACE_EVENT("TIMERSTART TUL_RCV ker_i_handler");
    */
    TIMERSTART(TUL_RCV_HANDLE, rlp_data->ker.T_ul);

    if (expected)
    {
      rbm_accept_current_frame ();
      rbm_set_rslot_rcvd (ns, &resetTimer);

      if (resetTimer)
      {
        ker_stopTRCVS (ns);
        rlp_data->ker.SREJ_Count--;
        srm_clear (ns);
      }

      rbm_buffer_all_in_sequence_frames
      (
        ns,
        &primToSend,
        &rlp_data->ker.LRReady,
        &rlp_data->ker.LRFull
      );

      if (primToSend)
        ker_handle_prim_send ();

      rlp_data->ker.REJ_State = ISW_IDLE;
      TIMERSTOP (TRCVR_HANDLE);
      rlp_data->ker.Ackn_State = IS_SEND;
      return FALSE;
    }
    else
    {
      if (rlp_data->ker.REJ_State NEQ ISW_IDLE)
        return TRUE;
       /*
        * ignore out of sequence frames
        */

      rbm_count_missing_i_frames (ns, &count);

      if (rlp_data->ker.SREJ_Count + (count-1) <=MAX_SREJ_COUNT)
      {
        rbm_move_current_frame (ns);
        rbm_set_rslot_rcvd (ns, &resetTimer);

        if (resetTimer)
        {
          ker_stopTRCVS (ns);
          rlp_data->ker.SREJ_Count--;
          srm_clear (ns);
        }

        rbm_mark_missing_i_frames_srej (ns);

        return FALSE;
      }
      else
      {
        rlp_data->ker.REJ_State = ISW_SEND;
        return FALSE;
      }
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_init_link_vars      |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL void ker_init_link_vars
            (
              void
            )
{
  TRACE_FUNCTION ("ker_init_link_vars()");

  rlp_data->ker.UL_Rcv_State = IW_IDLE;
  rlp_data->ker.UL_Snd_State = IW_IDLE;
  rlp_data->ker.Ackn_State   = IS_IDLE;
  rlp_data->ker.Poll_State   = ISW_IDLE;
  rlp_data->ker.Poll_Count   = 0;
  rlp_data->ker.Poll_xchg    = IW_IDLE;
  rlp_data->ker.REJ_State    = ISW_IDLE;
  rlp_data->ker.SABM_State   = ISW_IDLE;
  rlp_data->ker.DISC_State   = ISW_IDLE;
  rlp_data->ker.RRReady      = TRUE;
  rlp_data->ker.LRReady      = TRUE;
  rlp_data->ker.LRFull       = FALSE;
  rlp_data->ker.SREJ_Count   = 0;
  rlp_data->ker.Connected    = TRUE;
  rlp_data->ker.DTX_SF       = DTX_N;

  sbm_init
  (
    rlp_data->ker.K_ms_iwf,
    rlp_data->ker.FrameSize,
    rlp_data->ker.N2
  );

  rbm_init
  (
    rlp_data->ker.K_iwf_ms,
    rlp_data->ker.FrameSize,
    rlp_data->ker.FramesPerPrim
  );

  srm_init ();

}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_requestxid          |
+--------------------------------------------------------------------+

  PURPOSE : This function is invoked to request an XID command.
            Some variables are set, so that with next RA_READY_IND
            a XID command is sent.

*/

LOCAL void ker_requestxid(void)
{
  TRACE_FUNCTION ("ker_requestxid()");

  SET_STATE(KERXID_C, ISW_SEND);
  rlp_data->ker.XID_Count   = 0;
  rlp_data->ker.XID_C_PBit  = 1;

  ker_put_xid_data
  (
    rlp_data->ker.XID_C_Frame + HEADER_LEN,
    0,
    UF_ALL,
    TRUE,
    ORIG_RLP_VERS,
    rlp_data->ker.Orig_K_iwf_ms,
    rlp_data->ker.Orig_K_ms_iwf,
    rlp_data->ker.Orig_T1,
    rlp_data->ker.Orig_N2,
    rlp_data->ker.Orig_T2,
    rlp_data->ker.Orig_Pt,
    rlp_data->ker.Orig_P0,
    rlp_data->ker.Orig_P1,
    rlp_data->ker.Orig_P2
  );
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)            MODULE  : RLP_KERP             |
| STATE   : code                      ROUTINE : ker_init_xid_data    |
+--------------------------------------------------------------------+

  PURPOSE : initialize XID data from attach request

*/

GLOBAL void ker_init_xid_data
                  (
                    T_RLP_ATTACH_REQ *rlp_attach_req
                  )
{
  TRACE_FUNCTION ("ker_init_xid_data()");

  rlp_data->ker.Orig_K_ms_iwf = (U8)rlp_attach_req->k_ms_iwf;
  rlp_data->ker.K_ms_iwf      = DEF_K_MS_IWF;

  rlp_data->ker.Orig_K_iwf_ms = (U8)rlp_attach_req->k_iwf_ms;
  rlp_data->ker.K_iwf_ms      = DEF_K_IWF_MS;

  rlp_data->ker.Orig_T1       = TIME_EXT2INT (rlp_attach_req->t1);
  rlp_data->ker.T1            = rlp_data->ker.Def_T1;

  /*
   * >>>> According to GSM 11.10 V4.17.1 and V5.4.0 the default value must be used.
   * >>>> Later versions specify, that the value is used, which MS wants to negotiate.
   */
  /* use t1 immediately without negotiation, if it is greater than the default */
  /*
  if (rlp_data->ker.Orig_T1 > rlp_data->ker.T1)
  {
    rlp_data->ker.T1          = rlp_data->ker.Orig_T1;
  }
   */
  /*
  rlp_data->ker.Orig_T2       = TIME_EXT2INT (rlp_attach_req->t2);
  */
  rlp_data->ker.Orig_T2       = 200;    
  rlp_data->ker.T2            = DEF_T2;

  rlp_data->ker.Orig_N2       = rlp_attach_req->n2;
  rlp_data->ker.N2            = DEF_N2;

  rlp_data->ker.Orig_Pt       = rlp_attach_req->pt;
  rlp_data->ker.Pt            = DEF_PT;

  rlp_data->ker.Orig_P0       = rlp_attach_req->p0;
  rlp_data->ker.P0            = DEF_P0;

  rlp_data->ker.Orig_P1       = rlp_attach_req->p1;
  rlp_data->ker.P1            = DEF_P1;

  rlp_data->ker.Orig_P2       = rlp_attach_req->p2;
  rlp_data->ker.P2            = DEF_P2;

  rlp_data->ker.Rlp_Vers      = ORIG_RLP_VERS;


  if( !(rlp_data->ker.Orig_P0        EQ  RLP_COMP_DIR_NONE      AND
        rlp_data->ker.Orig_K_ms_iwf  EQ  DEF_K_MS_IWF           AND
        rlp_data->ker.Orig_K_iwf_ms  EQ  DEF_K_IWF_MS           AND
        rlp_data->ker.Orig_T1        EQ  rlp_data->ker.Def_T1   AND
        /*
        rlp_data->ker.Orig_T2        EQ  DEF_T2                 AND
        */
        rlp_data->ker.Orig_N2        EQ  DEF_N2                 AND
        rlp_data->ker.Orig_Pt        EQ  DEF_PT                 AND
        rlp_data->ker.Orig_P0        EQ  DEF_P0                 AND
        rlp_data->ker.Orig_P1        EQ  DEF_P1                 AND
        rlp_data->ker.Orig_P2        EQ  DEF_P2 ))
  {
    ker_requestxid ();
  }
  else
  {
    PALLOC (rlp_xid_ind, RLP_XID_IND);

    rlp_xid_ind->rlp_vers = rlp_data->ker.Rlp_Vers;
    rlp_xid_ind->k_ms_iwf = rlp_data->ker.K_ms_iwf;
    rlp_xid_ind->k_iwf_ms = rlp_data->ker.K_iwf_ms;
    rlp_xid_ind->t1 = TIME_INT2EXT (rlp_data->ker.T1);
    rlp_xid_ind->t2 = TIME_INT2EXT (rlp_data->ker.T2);
    rlp_xid_ind->n2 = rlp_data->ker.N2;
    rlp_xid_ind->pt = rlp_data->ker.Pt;
    rlp_xid_ind->p0 = rlp_data->ker.P0;
    rlp_xid_ind->p1 = rlp_data->ker.P1;
    rlp_xid_ind->p2 = rlp_data->ker.P2;

    PSENDX (L2R, rlp_xid_ind);
  }

}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_trace_rlp_frame     |
+--------------------------------------------------------------------+

  PURPOSE : traces the elements from the given RLP frame

*/

#ifdef TRACE_RLP_FRAME

GLOBAL void ker_trace_rlp_frame
            (
              T_RLP_FRAMEPTR  frame
            )
{
  T_BIT          cBit;
  T_BIT          pFBit;
  T_FRAME_NUM    nr;
  T_FRAME_NUM    ns;

  T_RLP_DEBUG *deb = &rlp_data->deb;

  TRACE_FUNCTION ("ker_trace_rlp_frame()");

  cBit  = (T_BIT) (frame[0] & 1);
  ns    = (T_FRAME_NUM) ((frame[0] >> 3) | ((frame[1] & 1)<<5));
  pFBit = (T_BIT) ((frame[1] & 2)>>1);

  
  deb->idx=0;

  deb->trc_buf[deb->idx++] = 'U';
  deb->trc_buf[deb->idx++] = ':';

  switch (ns)
  {
    case 62: /* S-Frame */
    {
      T_SF sFrame;

      nr = (T_FRAME_NUM) ((frame[1]>>2) & 0x3f);

      deb->trc_buf[deb->idx++] = 'S';
      deb->trc_buf[deb->idx++] = 'r';
      DEC_BYTE (nr, &deb->trc_buf[deb->idx]); deb->idx+=3;
      deb->trc_buf[deb->idx++] = ' ';

      sFrame = (T_SF) ((frame[0]>>1) & 0x03);

      /*
       * maybe optimize with a table!!
       */
      switch (sFrame)
      {
        case SF_RR:
          memcpy(&deb->trc_buf[deb->idx], "RR ",3);
          break;

        case SF_RNR:
          memcpy(&deb->trc_buf[deb->idx], "RNR",3);
          break;
        case SF_REJ:
          memcpy(&deb->trc_buf[deb->idx], "REJ",3);
          break;
        case SF_SREJ:
          memcpy(&deb->trc_buf[deb->idx], "SRJ",3);
          break;
        default:
          memcpy(&deb->trc_buf[deb->idx], "***",3);
          break;

      }
      deb->idx+=3;
      break;
    }

    case 63: /* U-Frame */
    {
      T_UF uFrame;
      uFrame = (T_UF) ((frame[1]>>2) & 0x1f);

      deb->trc_buf[deb->idx++] = 'U';
      deb->trc_buf[deb->idx++] = ' ';

      /*
       * maybe optimize with a table!!
       */
      switch (uFrame)
      {
        case UF_NULL:
          return;

        case UF_UI:
          memcpy(&deb->trc_buf[deb->idx], "UI  ",4);
          break;

        case UF_DM:
          memcpy(&deb->trc_buf[deb->idx], "DM  ",4);
          break;

        case UF_SABM:
          memcpy(&deb->trc_buf[deb->idx], "SABM",4);
          break;

        case UF_DISC:
          memcpy(&deb->trc_buf[deb->idx], "DISC",4);
          break;

        case UF_UA:
          memcpy(&deb->trc_buf[deb->idx], "UA  ",4);
          break;

        case UF_XID:
          memcpy(&deb->trc_buf[deb->idx], "XID ",4);
          break;

        case UF_TEST:
          memcpy(&deb->trc_buf[deb->idx], "TEST",4);
          break;

        case UF_REMAP:
          memcpy(&deb->trc_buf[deb->idx], "RMAP",4);
          break;

        default:
          memcpy(&deb->trc_buf[deb->idx], "****",4);
          break;
      }
      nr = 0;
      deb->idx += 4;
      break;
    }

    default: /* I+S-Frame */
    {
      T_SF sFrame;

      nr = (T_FRAME_NUM) ((frame[1]>>2) & 0x3f);

      sFrame = (T_SF) ((frame[0]>>1) & 0x03);

      deb->trc_buf[deb->idx++] = 'I';
      deb->trc_buf[deb->idx++] = 'r';
      DEC_BYTE (nr, &deb->trc_buf[deb->idx]); deb->idx+=3;
      deb->trc_buf[deb->idx++] = 's';
      DEC_BYTE (ns, &deb->trc_buf[deb->idx]); deb->idx+=3;
      deb->trc_buf[deb->idx++] = ' ';

      /*
       * maybe optimize with a table!!
       */
      switch (sFrame)
      {
        case SF_RR:
          memcpy(&deb->trc_buf[deb->idx], "RR ",3);
          break;

        case SF_RNR:
          memcpy(&deb->trc_buf[deb->idx], "RNR",3);
          break;
        case SF_REJ:
          memcpy(&deb->trc_buf[deb->idx], "REJ",3);
          break;
        case SF_SREJ:
          memcpy(&deb->trc_buf[deb->idx], "SRJ",3);
          break;
        default:
          memcpy(&deb->trc_buf[deb->idx], "***",3);
          break;
      }
      deb->idx += 3;
      break;
    }
  }
  deb->trc_buf[deb->idx++] = ' ';
  deb->trc_buf[deb->idx++] = ((cBit) ? 'C' : 'R');
  deb->trc_buf[deb->idx++] = ((cBit) ? 'P' : 'F');
  deb->trc_buf[deb->idx++] = ' ';
  HEX_BYTE (frame[1], &deb->trc_buf[deb->idx]); deb->idx+=2;
  HEX_BYTE (frame[0], &deb->trc_buf[deb->idx]); deb->idx+=2;
  deb->trc_buf[deb->idx++] = ' ';
  HEX_BYTE (frame[2], &deb->trc_buf[deb->idx]); deb->idx+=2;
  HEX_BYTE (frame[3], &deb->trc_buf[deb->idx]); deb->idx+=2;

  deb->trc_buf[deb->idx] = '\0';
  TRACE_EVENT (deb->trc_buf);
}
#endif

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_resetTRCVS          |
+--------------------------------------------------------------------+

  PURPOSE : Resets all running timer in the TCRVS table

*/

LOCAL void ker_resetTRCVS
            (
              void
            )
{
  T_FRAME_NUM lookUp;

  TRACE_FUNCTION ("ker_resetTRCVS()");

  for (lookUp = 0; lookUp < MAX_SREJ_COUNT; lookUp++)
  {
    if (!rlp_data->ker.rcvsTab[lookUp].isFree AND  rlp_data->ker.rcvsTab[lookUp].trcvs_running)
    {
      TIMERSTOP (lookUp);
      rlp_data->ker.rcvsTab[lookUp].trcvs_running = FALSE;
      rlp_data->ker.rcvsTab[lookUp].isFree       = TRUE;
      rlp_data->ker.rcvsTab[lookUp].slot         = INVALID_IDX;
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_reset_all_t_rcvs    |
+--------------------------------------------------------------------+

  PURPOSE : Resets the timer for each rcvs slot.

*/

GLOBAL void ker_reset_all_t_rcvs
            (
              void
            )
{
  TRACE_FUNCTION ("ker_reset_all_t_rcvs()");

  ker_resetTRCVS ();

  rlp_data->ker.SREJ_Count = 0;

  srm_reset ();
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_s_handler           |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL void ker_s_handler
            (
              T_BIT       cBit,
              T_BIT       pFBit,
              T_SF        sf,
              T_FRAME_NUM nr,
              BOOL        *retransError
            )
{
  BOOL allFramesAck = FALSE;

  TRACE_FUNCTION ("ker_s_handler()");

  *retransError = FALSE;

  if (cBit EQ 1 AND pFBit EQ 1)
  {
    rlp_data->ker.Ackn_State = IS_SEND;
    rlp_data->ker.Ackn_FBit  = 1;

    rbm_reset_all_r_states ();
    ker_reset_all_t_rcvs ();
    rlp_data->ker.REJ_State = ISW_IDLE;

    TIMERSTOP (TRCVR_HANDLE);
  }

  if (rlp_data->ker.Poll_State NEQ ISW_IDLE)
  {
    if (pFBit EQ 0 OR sf EQ SF_REJ OR sf EQ SF_SREJ )
      return;

    sbm_rej_from_n (nr, retransError);
    rlp_data->ker.Poll_State = ISW_IDLE;
    rlp_data->ker.Poll_xchg  = IW_IDLE;
    rlp_data->ker.Poll_Count = 0;

    if (*retransError)
    {
      ker_reset_all_t_rcvs ();
      rbm_reset_srej_slots ();

      TIMERSTOP (TRCVR_HANDLE);
      TIMERSTOP (TT_HANDLE);

      rlp_data->ker.DISC_State = ISW_SEND;
      rlp_data->ker.DISC_Count = 0;


      if (rlp_data->ker.Poll_xchg EQ IW_IDLE)
        rlp_data->ker.DISC_PBit = 1;
      else
        rlp_data->ker.DISC_PBit = 0;

      ker_deinit_link_vars();
      rlp_data->ker.DISC_Ind = TRUE;

      return;
    }
  }

  switch (sf)
  {
    case SF_RR:
      allFramesAck = sbm_ack_upto_n(nr);
      if (rlp_data->ker.RRReady EQ FALSE)
      {
        TRACE_EVENT ("Remote RR");
      }
      rlp_data->ker.RRReady = TRUE;
      break;

    case SF_RNR:
      allFramesAck = sbm_ack_upto_n(nr);
      if (rlp_data->ker.RRReady EQ TRUE)
      {
        TRACE_EVENT ("Remote RNR");
      }
      rlp_data->ker.RRReady = FALSE;
      break;

    case SF_REJ:
      allFramesAck = sbm_ack_upto_n(nr);
      sbm_rej_from_n (nr, retransError);

      if(*retransError)
      {
        ker_reset_all_t_rcvs ();
        rbm_reset_srej_slots ();

        TIMERSTOP (TRCVR_HANDLE);
        TIMERSTOP (TT_HANDLE);

        rlp_data->ker.DISC_State = ISW_SEND;
        rlp_data->ker.DISC_Count = 0;

        if (rlp_data->ker.Poll_xchg EQ IW_IDLE)
          rlp_data->ker.DISC_PBit = 1;
        else
          rlp_data->ker.DISC_PBit = 0;

        ker_deinit_link_vars();
        rlp_data->ker.DISC_Ind = TRUE;

        return;
      }

      if (rlp_data->ker.RRReady EQ FALSE)
      {
        TRACE_EVENT ("Remote RR");
      }
      rlp_data->ker.RRReady = TRUE;
      break;

    case SF_SREJ:
      sbm_srej_frame (nr);
      TIMERSTOP (TT_HANDLE);
      return;
  }

  if (allFramesAck)
  {
    TIMERSTOP (TT_HANDLE);
  }

}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_send_data           |
+--------------------------------------------------------------------+

  PURPOSE :
*/

GLOBAL void ker_send_data(void)
{
  T_EXT_FRAME_NUM slot;
  T_FRAME_NUM     vr;

  TRACE_FUNCTION ("ker_send_data()");

  if (rlp_data->ker.UA_State EQ IS_SEND)
  {
    sig_ker_snd_ua_req (rlp_data->ker.UA_FBit);
    rlp_data->ker.UA_State = IS_IDLE;
  }
  else
  {
    vr = rbm_get_vr();
    if (rlp_data->ker.Ackn_FBit EQ 1)
    {
      if (rlp_data->ker.LRReady)
        ker_send_rr_rri_resp (vr);
      else
        ker_send_rnr_rnri_resp (vr);
    }
    else
    {
      switch (rlp_data->ker.REJ_State)
      {
        case ISW_SEND:
          ker_send_rej_reji_cmd (vr);
          break;

        default:
          slot = rbm_check_slots_srej();
          if (slot EQ INVALID_IDX)
          {
            if (rlp_data->ker.LRReady)
              ker_send_rr_rri_cmd (vr);
            else
              ker_send_rnr_rnri_cmd (vr);
          }
          else
            ker_send_srej_sreji_cmd (slot);
          break;
      }
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_send_txu            |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL BOOL ker_send_txu
            (
              void
            )
{
  TRACE_FUNCTION ("ker_send_txu()");

  if (rlp_data->ker.TEST_R_State EQ IS_SEND)
  {
    sig_ker_snd_test_req
    (
      0,
      rlp_data->ker.TEST_R_FBit,
      &rlp_data->ker.TEST_R_FrameDesc
    );
    rlp_data->ker.TEST_R_State = IS_IDLE;
    return TRUE;
  }

  if (rlp_data->ker.XID_R_State EQ IS_SEND)
  {
    TRACE_EVENT ("Snd XID R");
    sig_ker_snd_xid_req
    (
      0,
      1,
      &rlp_data->ker.XID_R_FrameDesc
    );

    rlp_data->ker.XID_R_State = IS_IDLE;
    return TRUE;
  }

  if (GET_STATE(KERXID_C) EQ ISW_SEND)
  {
    if (rlp_data->ker.Poll_xchg NEQ IW_WAIT)
    {
      TRACE_EVENT ("Snd XID C");
      sig_ker_snd_xid_req
      (
        1,
        1,
        &rlp_data->ker.XID_C_FrameDesc
      );
      SET_STATE(KERXID_C, ISW_WAIT);

      TIMERSTART(TXID_HANDLE, rlp_data->ker.T1);
      rlp_data->ker.Poll_xchg = IW_WAIT;
      return TRUE;
    }
  }

  if (rlp_data->ker.UI_State EQ IS_SEND)
  {
    sig_ker_snd_ui_req
    (
      1,
      0,
      &rlp_data->ker.UI_FrameDesc
    );
    rlp_data->ker.UI_State = IS_IDLE;
    return TRUE;
  }

  return FALSE;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_deinit_link_vars    |
+--------------------------------------------------------------------+

  PURPOSE : deinitialize send/receive buffer manager,

*/

GLOBAL void ker_deinit_link_vars
            (
              void
            )
{

  TRACE_FUNCTION ("ker_deinit_link_vars()");

  rlp_data->ker.Connected = FALSE;

  sbm_deinit ();

  rbm_deinit ();

  srm_deinit ();

}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_send_rlp_error_ind  |
+--------------------------------------------------------------------+

  PURPOSE : send a error cause to L2R

*/

GLOBAL void ker_send_rlp_error_ind(USHORT cause)
{
  PALLOC (rlp_error_ind, RLP_ERROR_IND);

  TRACE_FUNCTION ("ker_send_rlp_error_ind()");
  TRACE_EVENT_P1("RLP Error : %d", cause);

  rlp_error_ind->cause = cause;
  PSENDX (L2R, rlp_error_ind);
  ker_deinit_link_vars ();
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_getSlotTRCVS        |
+--------------------------------------------------------------------+

  PURPOSE : search the rcvs entry for a given timer handle. The
            function returns the corresponding slot. The entry
            is freed. This function is used in the timeout handling
            functions of the entity.

*/
GLOBAL T_FRAME_NUM ker_getSlotTRCVS (USHORT index)
{
  rlp_data->ker.rcvsTab[index].trcvs_running = FALSE;
  rlp_data->ker.rcvsTab[index].isFree = TRUE;

  return rlp_data->ker.rcvsTab[index].slot;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_fill_remap_frame    |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL void               ker_fill_remap_frame
                          (
                            T_FRAME_NUM  vr
                          )
{

  TRACE_FUNCTION ("ker_fill_remap_frame()");

  rlp_data->ker.REMAP_Frame[HEADER_LEN + 0] = vr * 4;
  rlp_data->ker.REMAP_Frame[HEADER_LEN + 1] = 0;

  ker_put_xid_data
    (
    rlp_data->ker.REMAP_Frame + HEADER_LEN,
    2,
    UF_ALL,
    TRUE,
    ORIG_RLP_VERS,
    rlp_data->ker.Orig_K_iwf_ms,
    rlp_data->ker.Orig_K_ms_iwf,
    rlp_data->ker.Orig_T1,
    rlp_data->ker.Orig_N2,
    rlp_data->ker.Orig_T2,
    rlp_data->ker.Orig_Pt,
    rlp_data->ker.Orig_P0,
    rlp_data->ker.Orig_P1,
    rlp_data->ker.Orig_P2
    );

}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_send_remap_data     |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL BOOL               ker_send_remap_data
                          (
                            void
                          )
{
  T_RLP_DATA_REQ  *prim;

  TRACE_FUNCTION ("ker_send_remap_data()");

  if (sbm_recall_prim (&prim))
  {
    PPASS (prim, rlp_remap_data_ind, RLP_REMAP_DATA_IND);
    rlp_remap_data_ind->data_size = rlp_data->ker.OldFrameSize - HEADER_LEN - TRAILER_LEN;
    PSENDX (L2R, rlp_remap_data_ind);
    return TRUE;
  }
  return FALSE;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : RLP_KERF                |
| STATE   : code                   ROUTINE : ker_set_frame_size      |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL void               ker_set_frame_size
                          (
                            UBYTE rate
                          )
{

  TRACE_FUNCTION ("ker_set_frame_size()");

  switch(rate)
  {
  case RLP_FULLRATE_14400:
    rlp_data->ker.Def_T1 = DEF_T1_FR14400;
    rlp_data->ker.FrameSize = FRAME_SIZE_LONG;
    break;
  case RLP_FULLRATE_9600:
    rlp_data->ker.Def_T1 = DEF_T1_FR9600;
    rlp_data->ker.FrameSize = FRAME_SIZE_SHORT;
    break;
  case RLP_FULLRATE_4800:
    rlp_data->ker.Def_T1 = DEF_T1_FR4800;
    rlp_data->ker.FrameSize = FRAME_SIZE_SHORT;
    break;
  case RLP_HALFRATE_4800:
    rlp_data->ker.Def_T1 = DEF_T1_HR4800;
    rlp_data->ker.FrameSize = FRAME_SIZE_SHORT;
    break;
  }

  rlp_data->ker.FramesPerPrim =
    (rlp_data->ker.BytesPerPrim + rlp_data->ker.FrameSize - 1) /
    rlp_data->ker.FrameSize;

  sig_ker_snd_set_frame_size_req (rlp_data->ker.FrameSize);

}