view src/g23m-fad/rlp/rlp_kerf.c @ 662:8cd8fd15a095

SIM speed enhancement re-enabled and made configurable TI's original code supported SIM speed enhancement, but Openmoko had it disabled, and OM's disabling of speed enhancement somehow caused certain SIM cards to start working which didn't work before (OM's bug #666). Because our FC community is much smaller in year 2020 than OM's community was in their day, we are not able to find one of those #666-affected SIMs, thus the real issue they had encountered remains elusive. Thus our solution is to re-enable SIM speed enhancement and simply wait for if and when someone runs into a #666-affected SIM once again. We provide a SIM_allow_speed_enhancement global variable that allows SIM speed enhancement to be enabled or disabled per session, and an /etc/SIM_spenh file in FFS that allows it to enabled or disabled on a non-volatile basis. SIM speed enhancement is now enabled by default.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 24 May 2020 05:02:28 +0000
parents 90eb61ecd093
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);

}