diff src/g23m-fad/l2r/l2r_upf.c @ 1:d393cd9bb723

src/g23m-*: initial import from Magnetite
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 15 Jul 2018 04:40:46 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/g23m-fad/l2r/l2r_upf.c	Sun Jul 15 04:40:46 2018 +0000
@@ -0,0 +1,1778 @@
+/* 
++----------------------------------------------------------------------------- 
+|  Project :  CSD (8411)
+|  Modul   :  L2r_upf.c
++----------------------------------------------------------------------------- 
+|  Copyright 2002 Texas Instruments Berlin, AG 
+|                 All rights reserved. 
+| 
+|                 This file is confidential and a trade secret of Texas 
+|                 Instruments Berlin, AG 
+|                 The receipt of or possession of this file does not convey 
+|                 any rights to reproduce or disclose its contents or to 
+|                 manufacture, use, or sell anything it may describe, in 
+|                 whole, or in part, without the specific written consent of 
+|                 Texas Instruments Berlin, AG. 
++----------------------------------------------------------------------------- 
+|  Purpose :  This Modul defines the procedures and functions for
+|             the component L2R of the base station
++----------------------------------------------------------------------------- 
+*/ 
+
+#ifndef L2R_UPF_C
+#define L2R_UPF_C
+#endif
+
+#define ENTITY_L2R
+
+/*==== INCLUDES ===================================================*/
+
+#include <string.h>
+#include "typedefs.h"
+#include "pconst.cdg"
+#include "vsi.h"
+#include "macdef.h"
+#include "custom.h"
+#include "gsm.h"
+#include "cus_l2r.h"
+#include "cnf_l2r.h"
+#include "mon_l2r.h"
+#include "prim.h"
+#include "pei.h"
+#include "tok.h"
+#include "dti.h"      /* functionality of the dti library */
+
+#include "cl_ribu.h"
+#include "l2r.h"
+
+/*==== CONST =======================================================*/
+
+/*==== TYPES =======================================================*/
+
+/*==== VAR EXPORT ==================================================*/
+
+/*==== VAR LOCAL ===================================================*/
+
+/*==== FUNCTIONS ===================================================*/
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_init
++------------------------------------------------------------------------------
+|  Description : initialise the l2r data for the uplink process
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+GLOBAL void up_init(T_UP *dup)
+{
+  register ULONG i;
+
+  TRACE_FUNCTION ("up_init()");
+
+  dup->FlowCtrlUsed      = FALSE;
+  dup->DnFlow            = FL_INACTIVE;
+  dup->UpFlow            = FL_INACTIVE;
+  dup->ULFlow            = FL_INACTIVE;
+  dup->LLFlow            = FL_INACTIVE;
+  dup->MrgFlow           = FL_INACTIVE;
+  dup->FlowThreshLo      = MAX_UPRIM_RIBU_SIZE/2;
+  dup->FlowThreshHi      = 3*MAX_UPRIM_RIBU_SIZE/4;
+  dup->DataSize          = 0;
+  dup->FrameSize         = 0;
+  dup->OldFrameSize      = 0;
+  dup->FramesPerPrim     = L2R_FRAMES_PER_PRIM_MAX;
+  dup->LastRcvdSa        = 0;
+  dup->LastRcvdSb        = 0;
+  dup->LastSentSa        = 0;
+  dup->LastSentSb        = 0;
+  dup->LastSentFlow      = FL_INACTIVE;
+  dup->StoreDataActive   = FALSE;
+  dup->UrgentMsg         = FALSE;
+  dup->DiscardRemapData  = FALSE;
+  dup->QRemapRead        = 0;
+  dup->QRemapWrite       = 0;
+  dup->BRemapAdr         = NULL;
+  dup->BRemapLen         = 0;
+  dup->BRemapSa          = 0;
+  dup->BRemapSb          = 0;
+  dup->BRemapLastState   = 0;
+  dup->QRemapPrimDesc.prim = NULL;
+
+  for (i = 0; i < MAX_UP_REMAP_QUEUE_SIZE; i++)
+  {
+    dup->QRemap[i] = NULL;
+  }
+
+  for (i = 0; i < UP_REMAP_BUFFER_SIZE; i++)
+  {
+    dup->BRemap[i] = 0;
+  }
+
+  dup->RiBu.idx.depth = MAX_UPRIM_RIBU_SIZE;
+
+  INIT_STATE (UP_UL, IW_IDLE);
+  INIT_STATE (UP_LL, ISW_IDLE);
+  INIT_STATE (UP, UP_DISCONNECTED);
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_alloc_prim
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+
+LOCAL void up_alloc_prim(void)
+{
+  T_UP *dup = &l2r_data->up;
+
+  T_PRIM_INDEX          m;
+  T_P_UPRIM_DESCRIPTOR  primDesc;
+  USHORT                sduSize;
+
+  TRACE_FUNCTION ("up_alloc_prim()");
+
+  sduSize = dup->FramesPerPrim * dup->FrameSize * 8;
+  primDesc = dup->RiBu.primDesc[dup->RiBu.alloc];
+  {
+    PALLOC_SDU(data_req, RLP_DATA_REQ, sduSize);
+    primDesc->prim = data_req;
+  }
+
+#ifdef _SIMULATION_
+  /* Clear SDU for test environment */
+  {
+  UBYTE *p;
+  UBYTE *pend;
+  p = &primDesc->prim->sdu.buf[0];
+  pend = p + (sduSize >> 3);
+  while (p < pend)
+  {
+    *p++ = 0;
+  }
+  }
+#endif
+
+  primDesc->prim->sdu.o_buf = 0;
+  primDesc->prim->sdu.l_buf = sduSize;
+  primDesc->nFr             = dup->FramesPerPrim;
+  primDesc->index           = 0;
+  primDesc->offset          = 0;
+  primDesc->off_status      = 0;
+  primDesc->full            = FALSE;
+  primDesc->sa              = FL_INACTIVE;
+  primDesc->sb              = FL_INACTIVE;
+  /*lint -e416 (Warning -- Likely creation of out-of-bounds) */
+  for (m = 0; m != dup->FramesPerPrim; m++)
+  {
+    (*primDesc->adr)[m] = (T_P_L2R_FRAME)(primDesc->prim->sdu.buf +L2R_ENCODING_OFFSET + m * dup->FrameSize);    
+  }
+   /*lint +e416 (Warning -- Likely creation of out-of-bounds) */	
+  dup->RiBu.alloc++;
+  if (dup->RiBu.alloc EQ dup->RiBu.idx.depth)
+  {
+    dup->RiBu.alloc = 0;
+  }
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_send_prim_timeout
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+
+GLOBAL void up_send_prim_timeout(void)
+{
+  T_UP *dup = &l2r_data->up;
+
+  TRACE_FUNCTION ("up_send_prim_timeout()");
+
+  if (!dup->RiBu.idx.filled)
+  {
+    if (dup->RiBu.alloc EQ dup->RiBu.idx.wi)
+    {
+      /* No primitive is there, so we allocate one */
+      up_alloc_prim();
+    }
+
+    /*
+    No primitive is ready, so we take one away from the relay entity
+    */
+    cl_ribu_write_index(&dup->RiBu.idx); /* point to next primitive */
+  }
+  up_send_current_prim();
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_next_remap_frame
++------------------------------------------------------------------------------
+|  Description : Local function, which is used by up_copy_data_from_l2r 
+|                to advance to the next frame in the primitive.
+|                The variable primDesc of the calling function is updated.
+|
+|  Parameters  : primDesc -
+|
+|  Return      : 1 -
+|                0 -
++------------------------------------------------------------------------------
+*/
+
+LOCAL UBYTE up_next_remap_frame(T_RPRIM_DESCRIPTOR *primDesc)
+{
+  T_UP *dup = &l2r_data->up;
+
+  U8 i;
+  T_P_RLP_REMAP_DATA_IND prim;
+
+  /* next frame */
+  primDesc->index++;
+
+  if (primDesc->index >= primDesc->nFr)
+  {
+    /* primitive is completely read out */
+    PFREE(dup->QRemap [dup->QRemapRead]);
+
+    /* next primitive */
+    (dup->QRemapRead)++;
+    if (dup->QRemapRead >= MAX_UP_REMAP_QUEUE_SIZE)
+    {
+      dup->QRemapRead = 0;
+    }
+    if (dup->QRemapRead EQ dup->QRemapWrite)
+    {
+      /* no primitive is ready */
+      primDesc->prim = NULL;
+      return (1);
+    }
+
+    /* point to next primitive descriptor */
+
+    prim            = dup->QRemap[dup->QRemapRead];
+    primDesc->prim  = prim;
+    primDesc->nFr   = prim->sdu.l_buf / (8 * prim->data_size + HT_LEN);
+    primDesc->index = 0;
+
+    for (i = 0; i < primDesc->nFr; i++)
+    {
+      primDesc->adr[i] = (T_P_L2R_FRAME)(prim->sdu.buf + (prim->sdu.o_buf>>3)
+                          + HEADER_LEN + i * (prim->data_size + HT_LEN));
+    }
+  }
+  primDesc->offset      = 0;
+  primDesc->off_status  = 0;
+  return (0);
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_copy_data_from_rq
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : buf         -
+|                len         -
+|                sa          -
+|                sb          -
+|                bytesCopied -
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+LOCAL void up_copy_data_from_rq(U8 *buf, U16 len, U8 *sa, U8 *sb, U16 *bytesCopied)
+{
+  T_UP *dup = &l2r_data->up;
+
+  register ULONG          i;
+  register T_P_UBYTE      pFrame;
+  register T_P_UBYTE      pBuf;
+  register T_P_UBYTE      pStat;
+  T_P_RLP_REMAP_DATA_IND  prim;
+  T_P_L2R_FRAME           frame;
+  T_P_UBYTE               pEnd;
+  USHORT                  bytesToCopy;
+  USHORT                  blocklen;
+  UBYTE                   statOct;
+  UBYTE                   lastState;
+
+  T_RPRIM_DESCRIPTOR *primDesc = &dup->QRemapPrimDesc;
+
+#ifdef _SIMULATION_
+  TRACE_FUNCTION ("up_copy_data_from_rq()");
+#endif
+
+  bytesToCopy = len;
+
+  if (primDesc->prim EQ NULL)
+  {
+    prim                  = dup->QRemap[dup->QRemapRead];
+    primDesc->prim        = prim;
+    primDesc->nFr         = prim->sdu.l_buf / ((prim->data_size<<3) + HT_LEN);
+    primDesc->index       = 0;
+    primDesc->offset      = 0;
+    primDesc->off_status  = 0;
+
+    for (i = 0; i < primDesc->nFr; i++)
+    {
+      primDesc->adr[i] = (T_P_L2R_FRAME)(prim->sdu.buf + (prim->sdu.o_buf>>3)
+                                         + HEADER_LEN + i * (prim->data_size + HT_LEN));
+    }
+  }
+
+  /* skip empty primitive */
+  if (primDesc->nFr EQ 0)
+  {
+    *bytesCopied = 0;
+    return;
+  }
+
+  frame  = primDesc->adr[primDesc->index];  /* point to current l2r frame in primitive */
+  pBuf   = buf;                             /* point to destination buffer */
+  pFrame = &((*frame)[primDesc->offset]);
+  pStat  = &((*frame)[primDesc->off_status]);
+
+  if (pFrame EQ pStat)
+  {
+    /* current byte is status octet */
+    dup->BRemapLastState = *pFrame & SO_STATUS_BITS_MASK;
+  }
+
+  lastState = dup->BRemapLastState;
+  *sa = GET_SO_SA_BIT(lastState);
+  *sb = GET_SO_SB_BIT(lastState);
+
+  /************************************************************************************
+   * loop until either
+   *   -  no more data are available or
+   *   -  status in L2R frame changes or
+   *   -  buffer for data is full
+   ************************************************************************************/
+  
+  for (;;)
+  {
+#ifdef _SIMULATION_
+    TRACE_FUNCTION ("loop");
+#endif
+
+    blocklen = pStat - pFrame;
+    if (blocklen EQ 0)
+    {
+      /*
+       * current byte is status octet
+       * (only in the first pass of the loop, there may be no status octet)
+       */
+
+      /*****************************
+       *  evaluate status bits
+       *****************************/
+      statOct = *pFrame;
+      if (lastState NEQ (statOct & SO_STATUS_BITS_MASK))
+      {
+        /*
+         *  status has changed. We have to stop,
+         *  since only one state can be transmitted to the upper layer
+         */
+        primDesc->offset = primDesc->off_status = pFrame - (T_P_UBYTE)frame;
+
+        *bytesCopied = len - bytesToCopy;
+        return;
+      }
+
+      pFrame++;
+
+      /************************************
+       *  evaluate addrss bits
+       ************************************/
+      statOct &= SO_ADR_MASK;
+
+      switch (statOct)
+      {
+      case SO_BREAK_ACK:
+      case SO_BREAK_REQ:
+      case SO_END_EMPTY:
+        /* no more data in this frame */
+        if (up_next_remap_frame(primDesc) EQ 1)
+        {
+          /* no more data available */
+          *bytesCopied = len - bytesToCopy; /* this much data could be copied */
+          return;
+        }
+
+        frame  = primDesc->adr[primDesc->index];
+        pFrame = (T_P_UBYTE)frame;
+        pStat  = (T_P_UBYTE)frame;
+        continue;  /* continue with next frame */
+
+      case SO_END_FULL:
+        pStat = &((*frame)[primDesc->prim->data_size]);
+        blocklen = pStat - pFrame;
+        break;
+
+      case SO_TWO_OCTET:
+          blocklen = *pFrame++ & SO_ADR_MASK_TWO_OCT;
+          pStat = pFrame + blocklen;
+          break;
+
+      default:
+          blocklen = statOct;
+          pStat = pFrame + blocklen;
+          break;
+      }
+    }
+
+    if (bytesToCopy < blocklen)
+    {
+      /***************************************
+       *  There is not enough space in the
+       *  buffer to copy the complete block
+       ***************************************/
+
+      pEnd = pFrame + bytesToCopy;
+
+      while (pFrame < pEnd)
+      {
+        *pBuf++ = *pFrame++;
+      }
+
+      if (pFrame EQ &((*frame)[primDesc->prim->data_size]))
+      {
+        /* end of frame reached */
+        up_next_remap_frame(primDesc);
+      }
+      else
+      {
+        primDesc->offset   = pFrame - (T_P_UBYTE)frame;
+        primDesc->off_status = pStat  - (T_P_UBYTE)frame;
+      }
+      *bytesCopied = len; /* this much data could be copied */
+      return;
+    }
+    else
+    {
+      /***************************************
+       *  Copy the complete block
+       ***************************************/
+      bytesToCopy -= blocklen;
+
+      while (pFrame < pStat)
+      {
+        *pBuf++ = *pFrame++;
+      }
+
+      if (pFrame EQ  &((*frame)[primDesc->prim->data_size]))
+      {
+        /* end of frame reached */
+        if (up_next_remap_frame(primDesc) EQ 1)
+        {
+          /* no more data available */
+          *bytesCopied = len - bytesToCopy; /* this much data could be copied */
+          return;
+        }
+        frame  = primDesc->adr[primDesc->index];
+        pFrame = (T_P_UBYTE)frame;
+        pStat  = (T_P_UBYTE)frame;
+      }
+      if (bytesToCopy EQ 0)
+      {
+        primDesc->offset   = pFrame - (T_P_UBYTE)frame;
+        primDesc->off_status = pStat  - (T_P_UBYTE)frame;
+        *bytesCopied = len; /* this much data could be copied */
+        return;
+      }
+    }
+  }
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_fill_in_status_octet
++------------------------------------------------------------------------------
+|  Description : local function, which is used patch a status octet into a
+|                l2r frame. This function takes into acount the two octet
+|                format for 14400.
+|
+|  Parameters  : pFrame   - points to begin of l2r frame
+|                offstat1 - offset of status octet to be patched
+|                offstat2 - offset of next status octet
+|
+|  Return      :
++------------------------------------------------------------------------------
+*/
+
+LOCAL BOOL up_fill_in_status_octet(T_P_UBYTE pFrame, UBYTE offstat1, UBYTE offstat2)
+{
+  register T_P_UBYTE pStat, pSrc, pDes, pEnd;
+  register UBYTE dataLen;
+
+  dataLen = offstat2 - offstat1 - 1;  /* number of data bytes between status octets */
+  pStat = pFrame + offstat1;
+
+  if (dataLen <= DATA_SIZE_SHORT-2)
+  {
+    *pStat |= dataLen;
+    return (FALSE);
+  }
+  else
+  {
+    /* this is only possible with 14400 */
+    if (offstat2 < DATA_SIZE_LONG - 1)
+    {
+      /* a two octet status must be inserted */
+      pSrc = pFrame + offstat2;
+      pDes = pSrc + 1;
+      pEnd = pFrame + offstat1;
+      while (pSrc > pEnd)
+      {
+        *--pDes = *--pSrc;
+      }
+      *pStat |= SO_TWO_OCTET;
+      pStat++;
+      *pStat = dataLen;
+    }
+    else
+    {
+      /* a additional status octet (FULL) must be inserted somewhere in the frame */
+      pSrc = pFrame + offstat2;
+      pDes = pSrc + 1;
+      pEnd = pFrame + offstat1 + DATA_SIZE_SHORT - 1;
+      while (pSrc > pEnd)
+      {
+        *--pDes = *--pSrc;
+      }
+      *pStat |= DATA_SIZE_SHORT - 2;
+      *pEnd = *pStat & SO_STATUS_BITS_MASK | SO_END_FULL;
+    }
+    return (TRUE);
+  }
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_next_frame
++------------------------------------------------------------------------------
+|  Description : local function, which is used by up_copy_data_into_l2r to
+|                advance to the next frame in the primitive
+|                The variables primDesc, frame and pFrame of the calling function
+|                are updated. Moreover the return values of the calling function
+|                primToSend and bytesCopied are set.
+|
+|
+|  Parameters  : primDesc   -
+|                primToSend -
+|
+|  Return      :
++------------------------------------------------------------------------------
+*/
+
+LOCAL UBYTE up_next_frame(T_P_UPRIM_DESCRIPTOR *primDesc, BOOL *primToSend)
+{
+  T_UP *dup = &l2r_data->up;
+
+  TRACE_FUNCTION("up_next_frame()");
+
+  (*primDesc)->index++;
+  (*primDesc)->offset = 0;
+
+  if ((*primDesc)->index >= dup->FramesPerPrim) /* primitive is filled */
+  {
+    (*primDesc)->full = TRUE;
+    *primToSend = TRUE;
+
+    cl_ribu_write_index(&dup->RiBu.idx); /* point to next primitive */
+
+    if (dup->RiBu.alloc EQ dup->RiBu.idx.wi)
+    {
+      /* no primitive is ready */
+      return (1);
+    }
+
+    /* point to next primitive descriptor */
+    *primDesc = dup->RiBu.primDesc[dup->RiBu.idx.wi];
+    (*primDesc)->index = 0;
+  }
+  return (0);
+}
+
+LOCAL void up_copy_data_into_l2r(U8 *buf, U16 len, U8 sa, U8 sb, U8 x, BOOL *primToSend, U16 *bytesCopied)
+{
+  T_UP *dup = &l2r_data->up;
+
+  T_P_UPRIM_DESCRIPTOR primDesc;
+  T_P_L2R_FRAME frame;
+  register T_P_UBYTE pFrame;
+  register T_P_UBYTE pEnd;
+  register T_P_UBYTE pBuf;
+  USHORT bytesToCopy;
+  UBYTE frameCount;
+  T_FLOW flow = FL_INVALID;
+
+#ifdef _SIMULATION_
+  TRACE_FUNCTION ("up_copy_data_into_l2r()");
+#endif
+
+  switch (x)
+  {
+  case DTI_FLOW_ON:
+    flow = FL_INACTIVE;
+    break;
+  case DTI_FLOW_OFF:
+    flow = FL_ACTIVE;
+    break;
+  }
+
+#ifdef _TARGET_
+  if (dup->DataSize > DATA_SIZE_SHORT)
+  {
+    frameCount = 1;
+  }
+  else
+  {
+    frameCount = 2;
+  }
+#else
+  {
+    frameCount = 100;
+  }
+#endif
+
+  up_store_status(sa, sb, flow);
+
+  if (dup->LastSentFlow EQ dup->MrgFlow)
+  {
+    *primToSend = FALSE;
+  }
+  else
+  {
+    *primToSend = TRUE;
+  }
+
+  /* don't copy into primitive if no primitive is ready */
+  if (dup->RiBu.alloc EQ dup->RiBu.idx.wi)
+  {
+    *bytesCopied = 0;
+    return;
+  }
+
+  bytesToCopy = len;
+
+  primDesc = dup->RiBu.primDesc[dup->RiBu.idx.wi]; /* point to current primitive descriptor */
+  frame = (*primDesc->adr)[primDesc->index];  /* point to current l2r frame in primitive */
+  pFrame = &(*frame)[primDesc->offset];       /* point to current byte in frame */
+  pBuf = buf;                                 /* point to source buffer */
+
+  /************************************************************************************
+   *
+   * Handle a partly filled frame, which has been written in the primitive previously
+   *
+   ************************************************************************************/
+
+  if (primDesc->offset NEQ 0)
+  {
+    /* partly filled frame is there */
+
+    if (bytesToCopy EQ 0)
+    /* no data to copy -> quit without writing status octet */
+    {
+      *bytesCopied = len;
+      return;
+    }
+
+    if (sa NEQ primDesc->sa OR sb NEQ primDesc->sb)
+    {
+      /*
+       * status has changed since last time
+       */
+
+      /* finish previous status octet */
+      if (
+          up_fill_in_status_octet(
+            (T_P_UBYTE)frame,
+            primDesc->off_status,
+            primDesc->offset
+            )
+         )
+      {
+        /* frame data has been moved to make space for two octet status */
+        pFrame++;
+        (primDesc->offset)++;
+
+        if (primDesc->offset >= (dup->DataSize))
+        {
+          /* frame is just filled by patching the previous status frame */
+
+          if (up_next_frame(&primDesc, primToSend) EQ 1)
+          {
+            /* no more space for data */
+            *bytesCopied = 0; /* no data could be copied */
+            return;
+          }
+          frameCount--;
+#ifdef _TARGET_
+          if (frameCount EQ 0)
+          {
+            *bytesCopied = 0;  /* no data could be copied */
+            return;
+          }
+#endif
+          frame = (*primDesc->adr)[primDesc->index];  /* point to current l2r frame in primitive */
+          pFrame = &(*frame)[primDesc->offset];       /* point to current byte in frame */
+        }
+      }
+
+      if (primDesc->offset NEQ 0)
+      {
+        /* write status octet */
+        *pFrame++ = (U8)(sa << SO_SA_BIT | sb << SO_SB_BIT | 0 << SO_X_BIT);    /* x is set to 0 (inactive) by default */
+
+        /* store current status for next call */
+        primDesc->sa = sa;
+        primDesc->sb = sb;
+
+        primDesc->off_status = primDesc->offset;
+        (primDesc->offset)++;
+        if (primDesc->offset >= (dup->DataSize))
+        {
+          /* frame is just filled by the status octet */
+
+          /* finish previous status octet */
+          (*frame)[primDesc->off_status] |= SO_END_EMPTY;
+
+          if (up_next_frame(&primDesc, primToSend) EQ 1)
+          {
+            /* no more space for data */
+            *bytesCopied = 0;         /* no data could be copied */
+            return;
+          }
+          frameCount--;
+          if (frameCount EQ 0)
+          {
+            *bytesCopied = 0;         /* no data could be copied */
+            return;
+          }
+          frame = (*primDesc->adr)[primDesc->index];  /* point to current l2r frame in primitive */
+          pFrame = &(*frame)[primDesc->offset];       /* point to current byte in frame */
+        }
+      }
+    }
+
+    /*
+     * write data into partly filled frame
+     */
+    if (primDesc->offset NEQ 0)
+    {
+      if (bytesToCopy >= dup->DataSize - primDesc->offset)
+      {
+        /* enough data to fill frame completly */
+
+        for (pEnd = pFrame + dup->DataSize - primDesc->offset; pFrame < pEnd; )
+        {
+          *pFrame++ = *pBuf++;
+        }
+
+        /* finish previous status octet */
+        (*frame)[primDesc->off_status] |= SO_END_FULL;
+
+        bytesToCopy -= dup->DataSize - primDesc->offset;
+
+        if (up_next_frame(&primDesc, primToSend) EQ 1)
+        {
+          /* no more space for data */
+          *bytesCopied = len - bytesToCopy; /* this much data could be copied */
+          return;
+        }
+        frameCount--;
+        if (frameCount EQ 0)
+        {
+          *bytesCopied = len - bytesToCopy; /* this much data could be copied */
+          return;
+        }
+        frame = (*primDesc->adr)[primDesc->index];  /* point to current l2r frame in primitive */
+        pFrame = &(*frame)[primDesc->offset];       /* point to current byte in frame */
+
+      }
+      else
+      {
+        /* not enough data to fill frame completly */
+
+        for (pEnd = pFrame + bytesToCopy; pFrame < pEnd; )
+        {
+          *pFrame++ = *pBuf++;
+        }
+        primDesc->offset += bytesToCopy;
+        *bytesCopied = len;
+        return; /* Nothing else to do */
+      }
+    }
+  }
+
+  /************************************************************************************
+   *
+   * Handle consecutive frames, which are filled starting with byte 0
+   *
+   ************************************************************************************/
+
+  while (bytesToCopy > 0)
+  {
+    if (bytesToCopy >= dup->DataSize - 1)
+    {
+      /*
+       * There are enough data to fill a frame completely
+       */
+      *pFrame++ = sa << SO_SA_BIT | sb << SO_SB_BIT | 0 << SO_X_BIT | SO_END_FULL;    /* x is set to 0 (inactive) by default */
+
+      /* store current status for next call */
+      primDesc->sa = sa;
+      primDesc->sb = sb;
+
+      for (pEnd = pFrame + dup->DataSize - 1; pFrame < pEnd; )
+      {
+        *pFrame++ = *pBuf++;
+      }
+      bytesToCopy -= dup->DataSize - 1;
+
+      /* advance to next frame */
+      if (up_next_frame(&primDesc, primToSend) EQ 1)
+      {
+        /* running out of primitives */
+        *bytesCopied = len - bytesToCopy; /* this much data could be copied */
+        return;
+      }
+      frameCount--;
+      if (frameCount EQ 0)
+      {
+        *bytesCopied = len - bytesToCopy; /* this much data could be copied */
+        return;
+      }
+      frame = (*primDesc->adr)[primDesc->index];  /* point to current l2r frame in primitive */
+      pFrame = &(*frame)[primDesc->offset];       /* point to current byte in frame */
+    }
+    else
+    {
+      /*
+       * There are some data, but not enough to fill a frame completely
+       */
+      *pFrame++ = (U8)(sa << SO_SA_BIT | sb << SO_SB_BIT | 0 << SO_X_BIT);    /* x is set to 0 (inactive) by default */
+
+      /* store current status for next call */
+      primDesc->sa = sa;
+      primDesc->sb = sb;
+
+      for (pEnd = pFrame + bytesToCopy; pFrame < pEnd; )
+      {
+        *pFrame++ = *pBuf++;
+      }
+      primDesc->off_status = 0;
+      primDesc->offset = bytesToCopy + 1;
+      bytesToCopy = 0;
+    }
+  }
+  *bytesCopied = len;
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_copy_remap_data
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+LOCAL void up_copy_remap_data(void)
+{
+  T_UP *dup = &l2r_data->up;
+
+  USHORT bytesCopied;
+  BOOL   dummy;
+
+#ifdef _SIMULATION_
+  TRACE_FUNCTION ("up_copy_remap_data()");
+#endif
+
+  do
+  {
+    if (dup->BRemapLen EQ 0)
+    {
+      dup->BRemapAdr = dup->BRemap;
+      up_copy_data_from_rq
+        (
+        dup->BRemapAdr,
+        UP_REMAP_BUFFER_SIZE,
+        &dup->BRemapSa,
+        &dup->BRemapSb,
+        &dup->BRemapLen
+        );
+      if (dup->BRemapLen EQ 0)
+      {
+        up_check_flow();
+        return;
+      }
+    }
+    up_copy_data_into_l2r
+      (
+      dup->BRemapAdr,
+      dup->BRemapLen,
+      dup->BRemapSa,
+      dup->BRemapSb,
+      DTI_FLOW_OFF,
+      &dummy,
+      &bytesCopied
+      );
+    dup->BRemapAdr += bytesCopied;
+    dup->BRemapLen -= bytesCopied;
+
+  } while (bytesCopied NEQ 0);
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_check_alloc
++------------------------------------------------------------------------------
+|  Description : This procedure allocates new primitives until there are
+|                UP_RIBU_PREALLOC primitives ready.
+|
+|                I.e.: alloc = write + UP_RIBU_PREALLOC
+|
+|                It may be less than this, if otherwise the alloc pointer
+|                would reach the read pointer.
+|
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+GLOBAL void up_check_alloc(void)
+{
+  T_UP *dup = &l2r_data->up;
+
+  S8 i_from, i_to;
+
+  TRACE_FUNCTION ("up_check_alloc()");
+
+  i_to = dup->RiBu.idx.ri - dup->RiBu.idx.wi - 1;
+
+  if (i_to < 0)
+  {
+    i_to = i_to + dup->RiBu.idx.depth;
+  }
+
+  if (i_to > UP_RIBU_PREALLOC)
+  {
+    i_to = UP_RIBU_PREALLOC;
+  }
+
+  i_from = dup->RiBu.alloc - dup->RiBu.idx.wi;
+
+  if (i_from < 0)
+  {
+    i_from = i_from + dup->RiBu.idx.depth;
+  }
+
+  if (i_from >= i_to)
+  {
+    return;
+  }
+
+  do
+  {
+    up_alloc_prim();
+    i_from++;
+  } while (i_from < i_to);
+
+  if (dup->QRemapRead NEQ dup->QRemapWrite)
+  {
+    up_copy_remap_data();
+    return;
+  }
+
+  switch (GET_STATE (UP_UL))
+  {
+  case IW_WAIT:
+    break;
+
+  case IW_IDLE:
+    if (dup->StoreDataActive EQ FALSE AND dup->Prim NEQ NULL)
+    {
+      up_store_data();
+    }
+    break;
+  }
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_check_flow
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+GLOBAL void up_check_flow(void)
+{
+  T_UP *dup = &l2r_data->up;
+  
+  U8 primCount;
+
+  TRACE_FUNCTION ("up_check_flow()");
+
+  if (!dup->FlowCtrlUsed)
+  {
+    return;
+  }
+
+  primCount = dup->RiBu.idx.filled;
+
+  switch (dup->UpFlow)
+  {
+  case FL_ACTIVE:
+    if (primCount < dup->FlowThreshLo)
+    {
+      dup->UpFlow = FL_INACTIVE;
+    }
+    else
+    {
+      return;
+    }
+    break;
+
+  case FL_INACTIVE:
+    if (primCount >= dup->FlowThreshHi)
+    {
+      dup->UpFlow = FL_ACTIVE;
+    }
+    else
+    {
+      return;
+    }
+    break;
+  }
+  sig_up_dn_flow(dup->UpFlow);
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_store_data
++------------------------------------------------------------------------------
+|  Description : This procedure copies data from a dti_data_req primitive 
+|                into the uplink ring buffer.
+|
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+GLOBAL void up_store_data(void)
+{
+  T_UP *dup = &l2r_data->up;
+
+  T_P_UBYTE adr;
+  USHORT len;
+  BOOL primToSend;
+  USHORT bytesCopied;
+  USHORT i, j;
+  T_desc2 *desc;
+
+  TRACE_FUNCTION ("up_store_data()");
+
+  dup->StoreDataActive = TRUE;
+
+  do
+  {
+    desc = (T_desc2*)dup->Prim->desc_list2.first;
+    if (desc)
+    {
+      len = desc->len;
+      adr = desc->buffer;
+    }
+    else
+    {
+      len = 0;
+      adr = NULL;
+    }
+    
+    up_copy_data_into_l2r (adr,
+      len,
+      dup->Prim->parameters.st_lines.st_line_sa,
+      dup->Prim->parameters.st_lines.st_line_sb,
+      dup->Prim->parameters.st_lines.st_flow,
+      &primToSend,
+      &bytesCopied);
+
+    dup->Prim->desc_list2.list_len  -= bytesCopied;
+ 
+    if (desc)
+    {
+      if ((bytesCopied EQ len))
+      {
+        /*
+         * Block has been copied successfully
+         */
+        dup->Prim->desc_list2.first = desc->next;
+        MFREE (desc);
+      }
+      else if (bytesCopied > 0)
+      {
+       /*
+        * remaining data must be copied to begin of block
+        */
+        /*lint -e{661} (Warning -- Likely creation of out-of-bounds) */        
+        for (i=0, j = bytesCopied; j < len; i++, j++)
+        {
+	  desc->buffer[i] = desc->buffer[j];
+	 }
+        desc->len -= bytesCopied;
+      }
+    }
+    up_check_alloc();
+
+  } while (dup->Prim->desc_list2.first NEQ 0 AND dup->RiBu.alloc NEQ dup->RiBu.idx.wi);
+
+  if (dup->Prim->desc_list2.first EQ 0)
+  {
+    PFREE (dup->Prim);
+    dup->Prim = NULL;
+    up_send_ready();
+  }
+  dup->StoreDataActive = FALSE;
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_send_ready
++------------------------------------------------------------------------------
+|  Description : only used in test environment
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+GLOBAL void up_send_ready(void)
+{
+  TRACE_FUNCTION ("up_send_ready()");
+
+  if (GET_STATE (UP_UL) EQ IW_IDLE)
+  {
+    if (l2r_data->up.DtiConnected EQ FALSE)
+    {
+      TRACE_EVENT("DTI not connected, but up_send_ready() called -> break");
+      return; /* jk: DTI_READY_IND primitive cannot be sent when DTI disconnected (!) */
+    }
+
+    dti_start (
+      l2r_hDTI,
+      L2R_DTI_UP_DEF_INSTANCE,
+      L2R_DTI_UP_INTERFACE,
+      L2R_DTI_UP_CHANNEL
+      );        
+    SET_STATE (UP_UL, IW_WAIT);
+  }
+}
+
+LOCAL void clear_primDesc(T_P_UPRIM_DESCRIPTOR primDesc)
+{
+  primDesc->prim        = NULL;
+
+  primDesc->nFr         = 0;
+  primDesc->index       = 0;
+  primDesc->offset      = 0;
+  primDesc->off_status  = 0;
+  primDesc->full        = FALSE;
+  primDesc->sa          = FL_INACTIVE;
+  primDesc->sb          = FL_INACTIVE;
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_free_prim
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : primDesc
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+LOCAL void up_free_prim(T_P_UPRIM_DESCRIPTOR primDesc)
+{
+  TRACE_FUNCTION ("up_free_prim()");
+
+  if (primDesc->prim NEQ NULL)
+  {
+    PFREE (primDesc->prim);
+    clear_primDesc(primDesc);
+  }
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_deinit_ribu
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+GLOBAL void up_deinit_ribu(void)
+{
+  T_UP *dup = &l2r_data->up;
+
+  T_PRIM_DESC_RIBU_INDEX n;
+
+  T_P_UPRIM_DESCRIPTOR primDesc;
+
+  TRACE_FUNCTION ("up_deinit_ribu()");
+
+  for (n = 0; n < dup->RiBu.idx.depth; n++)
+  {
+    primDesc = dup->RiBu.primDesc[n];
+    if (primDesc->prim NEQ NULL)
+    {
+      up_free_prim(primDesc);
+    }
+  }
+  if (GET_STATE (UP_LL) EQ ISW_SEND)
+  {
+    SET_STATE (UP_LL, ISW_IDLE);
+  }
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_send_status
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : sa   -
+|                sb   -
+|                flow -
+|                adr  -
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+
+
+GLOBAL void               up_send_status
+                          (
+                             T_BIT  sa,
+                             T_BIT  sb,
+                             T_FLOW flow,
+                             UBYTE adr
+                          )
+{
+  T_UP *dup = &l2r_data->up;
+
+  T_P_UPRIM_DESCRIPTOR  primDesc;
+  T_P_L2R_FRAME    frame;
+  T_BIT x = 0;
+
+  TRACE_FUNCTION ("up_send_status()");
+
+  primDesc = dup->RiBu.primDesc[dup->RiBu.idx.wi];
+  frame = (*primDesc->adr)[0];
+
+  switch (flow)
+  {
+  case FL_ACTIVE:
+    x = 1;
+    break;
+  case FL_INACTIVE:
+    x = 0;
+    break;
+  }
+  (*frame)[0] = sa << SO_SA_BIT | sb << SO_SB_BIT | x << SO_X_BIT | adr;
+
+  /* jk:030501 - TEST CASE 251 -
+  new funktion parameter 'adr' was introduced
+  in order to cancel the older function 'up_send_break(...)'
+  */
+  primDesc->sa = sa; /* the status has to be saved in order to be correctly stored later */
+  primDesc->sb = sb; /* on into "dup->LastSentSa/Sb" [up_send current_prim()] */
+
+  primDesc->index = 1;
+  primDesc->offset = 0;
+
+  cl_ribu_write_index(&dup->RiBu.idx); /* point to next primitive */
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_set_flow_in_prim
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : prim -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+LOCAL void up_set_flow_in_prim(T_P_RLP_DATA_REQ prim)
+{
+  T_UP *dup = &l2r_data->up;
+
+  if (dup->MrgFlow EQ FL_INACTIVE)
+  {
+    TRACE_FUNCTION ("up_set_flow_in_prim(INACTIVE)");
+  }
+  else
+  {
+    T_PRIM_INDEX frames;
+    T_PRIM_INDEX ind;
+    UBYTE off;
+    register UBYTE statOct;
+    T_P_L2R_FRAME frame;
+
+    TRACE_FUNCTION ("up_set_flow_in_prim(ACTIVE)");
+
+    frames = prim->sdu.l_buf / (8 * dup->FrameSize);
+    frame = (T_P_L2R_FRAME) (prim->sdu.buf + (prim->sdu.o_buf / 8) + HEADER_LEN);
+    off = 0;
+    ind = 0;
+
+    while (ind < frames)
+    {
+      statOct = (*frame)[off];
+      SET_BIT(statOct, SO_X_BIT);
+      (*frame)[off] = statOct;
+
+      switch (statOct & SO_ADR_MASK)
+      {
+      case SO_BREAK_REQ:
+      case SO_BREAK_ACK:
+      case SO_END_EMPTY:
+      case SO_END_FULL:
+        ind++;
+        frame = (T_P_L2R_FRAME)((UBYTE*)frame + dup->FrameSize);
+        off = 0;
+        break;
+
+      case SO_TWO_OCTET:
+        off++;
+        off += ((*frame)[off] & SO_ADR_MASK_TWO_OCT) + 1;
+        if (off >= dup->DataSize)
+        {
+          ind++;
+          frame = (T_P_L2R_FRAME)((UBYTE*)frame + dup->FrameSize);
+          off = 0;
+        }
+        break;
+
+      default:
+        off += (statOct & SO_ADR_MASK) + 1;
+        if (off >= dup->DataSize)
+        {
+          ind++;
+          frame = (T_P_L2R_FRAME)((UBYTE*)frame + dup->FrameSize);
+          off = 0;
+        }
+        break;
+      }
+    }
+  }
+  dup->LastSentFlow = dup->MrgFlow;
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_send_current_prim
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+GLOBAL void up_send_current_prim(void)
+{
+  T_UP *dup = &l2r_data->up;
+  T_P_UPRIM_DESCRIPTOR primDesc = dup->RiBu.primDesc[dup->RiBu.idx.ri];
+
+  TRACE_FUNCTION ("up_send_current_prim()");
+
+  if (!primDesc->full AND primDesc->index < primDesc->nFr)
+  {
+    TRACE_FUNCTION ("prim is not full");
+    if (primDesc->offset > 0)
+    {
+      if (up_fill_in_status_octet((T_P_UBYTE)(*primDesc->adr)[primDesc->index], primDesc->off_status, primDesc->offset))
+      {
+        primDesc->offset++;
+        if (primDesc->offset >= dup->DataSize)
+        {
+          primDesc->offset = 0;
+          primDesc->index++;
+        }
+      }
+    }
+
+    if (primDesc->offset > 0 OR primDesc->index EQ 0)
+    {
+      /*
+       * Add status octet, if there is a partly filled frame
+       * or if status has changed since last write
+       */
+      (*(*primDesc->adr)[primDesc->index])[primDesc->offset] =
+        dup->LastRcvdSa << SO_SA_BIT |
+        dup->LastRcvdSb << SO_SB_BIT |
+                      0 << SO_X_BIT  |
+        SO_END_EMPTY;
+      primDesc->sa = dup->LastRcvdSa;
+      primDesc->sb = dup->LastRcvdSb;
+      primDesc->index++;
+    }
+    primDesc->prim->sdu.l_buf = primDesc->index * dup->FrameSize * 8;
+  }
+
+  dup->LastSentSa = primDesc->sa;
+  dup->LastSentSb = primDesc->sb;
+  up_set_flow_in_prim(primDesc->prim);
+
+  PSENDX (RLP, primDesc->prim);
+
+  clear_primDesc(primDesc);     /* this primitive doesn't belong to us any longer */
+
+  cl_ribu_read_index(&dup->RiBu.idx); /* point to next primitive */
+
+  dup->UrgentMsg = FALSE;
+  up_check_alloc();
+  up_check_flow();
+}
+
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_send_prim_cond
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+GLOBAL void up_send_prim_cond(void)
+{
+  TRACE_FUNCTION ("up_send_prim_cond()");
+
+  switch (GET_STATE (UP_LL))
+  {
+  case ISW_WAIT:
+    TIMERSTOP (TIMER_TUP_SND);
+    up_send_current_prim();
+    SET_STATE (UP_LL, ISW_IDLE);
+    break;
+
+  default:
+    l2r_data->up.UrgentMsg = TRUE;
+    up_check_flow();
+    up_check_alloc();
+    SET_STATE (UP_LL, ISW_SEND);
+    break;
+  }
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_init_ribu
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+
+GLOBAL void up_init_ribu(void)
+{
+  T_UP *dup = &l2r_data->up;
+
+  T_PRIM_DESC_RIBU_INDEX n;
+  T_PRIM_INDEX m;
+
+  TRACE_FUNCTION ("up_init_ribu()");
+
+  dup->RiBu.alloc = 0;
+
+  cl_ribu_init(&dup->RiBu.idx, dup->RiBu.idx.depth);
+
+  for (n = 0; n < dup->RiBu.idx.depth; n++)
+  {
+    dup->RiBu.primDesc[n] = &(dup->PrimDesc[n]);
+
+    dup->PrimDesc[n].nFr = 0;
+    dup->PrimDesc[n].adr = (T_P_ADR_VECTOR)&(dup->AdrVec[n]);
+    dup->PrimDesc[n].index = 0;
+    dup->PrimDesc[n].offset = 0;
+    dup->PrimDesc[n].off_status = 0;
+    dup->PrimDesc[n].full = FALSE;
+    dup->PrimDesc[n].sa   = FL_INACTIVE;
+    dup->PrimDesc[n].sb   = FL_INACTIVE;
+    dup->PrimDesc[n].prim = NULL;
+
+    for(m = 0;m < L2R_FRAMES_PER_PRIM_MAX; m++)
+    {
+      dup->AdrVec[n][m] = NULL;
+    }
+
+    if (dup->RiBu.alloc < UP_RIBU_PREALLOC)
+    {
+      up_alloc_prim();
+    }
+  }
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_store_status
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : sa
+|                sb
+|                flow
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+
+GLOBAL void               up_store_status
+                          (
+                             T_BIT  sa,
+                             T_BIT  sb,
+                             T_FLOW flow
+                          )
+{
+  T_UP *dup = &l2r_data->up;
+
+#ifdef _SIMULATION_
+  TRACE_FUNCTION ("up_store_status()");
+#endif
+
+  dup->LastRcvdSa = sa;
+  dup->LastRcvdSb = sb;
+
+  if (dup->FlowCtrlUsed EQ FALSE OR flow EQ dup->ULFlow)
+  {
+    return;
+  }
+
+  dup->ULFlow = flow;
+
+  up_merge_flow();
+  sig_up_dn_ul_flow(dup->ULFlow);
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_send_empty_frame
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : sa   -
+|                sb   -
+|                flow -
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+
+GLOBAL void up_send_empty_frame(T_BIT sa, T_BIT sb, T_FLOW flow)
+{
+  T_UP *dup = &l2r_data->up;
+
+  T_BIT x = 0;
+  USHORT sduSize = dup->FrameSize << 3;
+
+  PALLOC_SDU(data_req, RLP_DATA_REQ, sduSize);
+
+  TRACE_FUNCTION ("up_send_empty_frame()");
+
+#ifdef _SIMULATION_
+  /* Clear SDU for test environment */
+  {
+  UBYTE *p;
+  UBYTE *pend;
+  p = &data_req->sdu.buf[0];
+  pend = p + dup->FrameSize;
+  while (p < pend)
+  {
+    *p++ = 0;
+  }
+  }
+#endif
+
+  data_req->sdu.o_buf = 0;
+  data_req->sdu.l_buf = sduSize;
+
+  switch (flow)
+  {
+  case FL_ACTIVE:
+    x = 1;
+    break;
+  case FL_INACTIVE:
+    x = 0;
+    break;
+  }
+  /*lint -e416 (Warning -- Likely creation of out-of-bounds pointer) */
+  /*lint -e415 (Warning -- Likely access of out-of-bounds pointer) */
+  data_req->sdu.buf[L2R_ENCODING_OFFSET] = sa << SO_SA_BIT | sb << SO_SB_BIT | x << SO_X_BIT | SO_END_EMPTY;
+  /*lint +e416 (Warning -- Likely creation of out-of-bounds pointer) */
+  /*lint +e415 (Warning -- Likely access of out-of-bounds pointer) */  
+
+  dup->LastSentFlow = flow;
+  dup->LastSentSa   = sa;
+  dup->LastSentSb   = sb;
+
+  PSENDX (RLP, data_req);
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_merge_flow
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+
+GLOBAL void up_merge_flow(void)
+{
+  T_UP *dup = &l2r_data->up;
+
+#ifdef _SIMULATION_
+  TRACE_FUNCTION ("up_merge_flow()");
+#endif
+
+  if (dup->FlowCtrlUsed AND (dup->DnFlow EQ FL_ACTIVE OR dup->ULFlow EQ FL_ACTIVE))
+  {
+    /* flow control active */
+    dup->MrgFlow = FL_ACTIVE;
+  }
+  else
+  {
+    /* flow control inactive */
+    dup->MrgFlow = FL_INACTIVE;
+  }
+
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_rq_init
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : -
+|
+|
+|  Return      : -
++------------------------------------------------------------------------------
+*/
+
+GLOBAL void up_rq_init(void)
+{
+#ifdef _SIMULATION_
+  TRACE_FUNCTION ("up_rq_init()");
+#endif
+
+  l2r_data->up.QRemapWrite = 0;
+  l2r_data->up.QRemapRead  = 0;
+}
+
+/*
++------------------------------------------------------------------------------
+|  Function    : up_some_data_to_send
++------------------------------------------------------------------------------
+|  Description :
+|
+|  Parameters  : -
+|
+|
+|  Return      : TRUE  -
+|                FALSE -
++------------------------------------------------------------------------------
+*/
+
+GLOBAL BOOL up_some_data_to_send(void)
+{
+  T_UP *dup = &l2r_data->up;
+
+#ifdef _SIMULATION_
+  TRACE_EVENT ("check if any data to send");
+#endif
+
+  if (
+       dup->RiBu.idx.filled OR
+      (dup->RiBu.primDesc[dup->RiBu.idx.ri]->index > 0) OR
+      (dup->RiBu.primDesc[dup->RiBu.idx.ri]->offset > 0) OR
+      (dup->LastRcvdSa NEQ dup->LastSentSa) OR
+      (dup->LastRcvdSb NEQ dup->LastSentSb)
+    )
+  {
+    return (TRUE);
+  }
+  return (FALSE);
+}