view gsm-fw/gpf/frame/route.c @ 560:85562a6b6356

gsm-fw/L1/dsp/leadboot.c: import from the LoCosto source
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Mon, 04 Aug 2014 21:43:47 +0000
parents 2c760f6b1fe0
children
line wrap: on
line source

/* 
+------------------------------------------------------------------------------
|  File:       route.c
+------------------------------------------------------------------------------
|  Copyright 2004 Texas Instruments Deutschland, 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 Deutschland, AG. 
+----------------------------------------------------------------------------- 
|  Purpose :  This Modul performs the filtering and routing of
|             primitives for testing capabilities of the protocol stack.
+----------------------------------------------------------------------------- 
*/ 
 
#ifndef __ROUTE_C__
#define __ROUTE_C__
#endif

/*==== INCLUDES ===================================================*/
 
#include <stdio.h>
#include <string.h>

#include "gpfconf.h"
#include "typedefs.h"
#include "os.h"
#include "vsi.h"
#include "frame.h"
#include "tools.h"
#include "frm_defs.h"
#include "frm_types.h"
#include "frm_glob.h"
#include "p_mem.h"
#include "route.h"
#include "frm_ext.h"

/*==== CONSTANTS ==================================================*/

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

/*==== CONSTANTS ====================================================*/

/*==== EXTERNALS =====================================================*/

/* -------------- S H A R E D - BEGIN ---------------- */
#ifdef _TOOLS_
#pragma data_seg("FRAME_SHARED") 
#endif

extern OS_HANDLE ext_data_pool_handle;
extern T_HANDLE TestGroupHandle;
extern T_FRM_ROUTING_TABLE_ENTRY *Routing[];
extern char TaskName[];
#ifndef _TOOLS_
extern T_lemu_SendToQueue lemu_SendToQueue_func; 
#endif
/*==== VARIABLES ==================================================*/

#ifndef RUN_INT_RAM
T_HANDLE rt_tst_handle = VSI_ERROR;
#else
extern int rt_tst_handle;
#endif

#ifdef _TOOLS_
#pragma data_seg()
#endif
/* -------------- S H A R E D - END ---------------- */

#ifndef _TOOLS_
extern const T_MEM_PROPERTIES *mem;
#endif

/*==== FUNCTIONS ==================================================*/
                          
#ifndef RUN_INT_RAM
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)              MODULE  : PF_ROUTE            |
| STATE   : code                       ROUTINE : rt_Init             |
+--------------------------------------------------------------------+

  PURPOSE : initialize the routing table.
*/

GLOBAL SHORT rt_Init (void)
{  
USHORT i;
  /*
   * Initialize the routingTable
   */
  for ( i = 0; i <= MaxEntities; i++ )
    Routing[i] = NULL;

  return OS_OK;
}
#endif


#ifndef RUN_INT_RAM
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)              MODULE  : PF_ROUTE            |
| STATE   : code                       ROUTINE : rt_CvrtOpcMask      |
+--------------------------------------------------------------------+

  PURPOSE : convert "1010101" mask to opcMask and opcStatus
*/

LOCAL SHORT rt_CvrtToOpcMask ( char *OpcString, ULONG *opcMask, ULONG *opcStatus )
{  
unsigned int len;
unsigned int i;
char *p;

  len = strlen ( OpcString );
  p = OpcString + len;

  for ( i = 0; i < len; i++ )
  {
    switch (*--p)
    {
      case '1':
        *opcMask |= (1<<i);
        *opcStatus |= (1<<i);
        break;       
      case '0':
        *opcMask |= (1<<i);
        *opcStatus &= ~((unsigned int)1<<i);
        break;       
      case '*':           /* wildcard matches */
        *opcMask &= ~((unsigned int)1<<i);
        *opcStatus &= ~((unsigned int)1<<i);
        break;
      default:
        break;       
    }
  }
  return OS_OK;
}
#endif

#ifndef RUN_INT_RAM
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)              MODULE  : PF_ROUTE            |
| STATE   : code                       ROUTINE : rt_CvrtOpcMask      |
+--------------------------------------------------------------------+

  PURPOSE : convert opcMask and opcStatus to "1010101" 
*/
LOCAL SHORT rt_CvrtFromOpcMask ( char *OpcString, ULONG opcMask, ULONG opcStatus )
{  
signed char i;
char len;

  if ( opcMask >> 16 )
    len = 32;
  else
    len = 16;
  for ( i = len-1; i >= 0; i-- )
  {
    if ( opcMask & (1<<i) )
    {
      if ( opcStatus & (1<<i) )
        *OpcString = '1';
      else
        *OpcString = '0';
    }
    else
      *OpcString = '*';
    OpcString++;
  }
  *(OpcString++) = ' ';
  *(OpcString++) = 0;
  
  return OS_OK;
}
#endif

#ifndef RUN_INT_RAM
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)              MODULE  : PF_ROUTE            |
| STATE   : code                       ROUTINE : rt_ReadRouting      |
+--------------------------------------------------------------------+

  PURPOSE : reads all routings of the routing table of the task.
*/

GLOBAL SHORT rt_RouteRead ( T_HANDLE Handle, char *Buffer )               
{
T_HANDLE TstComHandle;
static T_FRM_ROUTING_TABLE_ENTRY *pEntry;
char OrgReceiver[ RESOURCE_NAMELEN ];
char NewReceiver[ RESOURCE_NAMELEN ];
char OpcString [18];
char const *pCmd;
static UBYTE FirstRead = 1;

  if ( FirstRead )
  {
    FirstRead = 0;
    pEntry = Routing[Handle];
  }
  if ( pEntry )
  {
    if ( pEntry->OldDestComHandle == ROUTE_ALL )
      strcpy ( OrgReceiver, RT_ALL_TOKEN );
    else
      strcpy ( OrgReceiver, pf_TaskTable[pEntry->OldDestComHandle].Name );
    TstComHandle = vsi_c_open ( Handle, FRM_TST_NAME );
    if ( pEntry->NewDestComHandle == TstComHandle )
      strcpy ( NewReceiver, pEntry->ExtDest );
    else
    {
      if ( pEntry->NewDestComHandle != 0 )
        strcpy ( NewReceiver, pf_TaskTable[pEntry->NewDestComHandle].Name );
    }
    if ( pEntry->opcMask )
      rt_CvrtFromOpcMask ( OpcString, pEntry->opcMask, pEntry->opcStatus );
    else
      OpcString[0] = 0;

    switch (pEntry->Command & RT_COMMAND_MASK)
    {
      case RT_DUPLICATE: pCmd = SYSPRIM_DUPLICATE_TOKEN;
      break;
      case RT_REDIRECT:  pCmd = SYSPRIM_REDIRECT_TOKEN;
      break;
      case RT_DESTROY:   pCmd = SYSPRIM_REDIRECT_TOKEN;
                         strcpy ( NewReceiver, SYSPRIM_NULL_TOKEN );
      break;
      default:           pCmd = NULL;
      break;
    }
    sprintf ( Buffer, "%s %s %s %s%s", pf_TaskTable[Handle].Name, pCmd, OrgReceiver, OpcString, NewReceiver );
    pEntry = pEntry->pNextEntry;
    return RT_OK;
  }
  else 
  {
    FirstRead = 1;
    pEntry = Routing[Handle];
    return RT_ERROR;
  }
}
#endif

#ifndef RUN_INT_RAM
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)              MODULE  : PF_ROUTE            |
| STATE   : code                       ROUTINE : rt_RoutingEntry     |
+--------------------------------------------------------------------+

  PURPOSE : adds a new routing to the routing table of the task.
            routings with duplicates are stored in the beginning
            of the table because if the primitive is redirected and
            send it can not be duplicated.
*/

LOCAL SHORT rt_RoutingEntry ( T_HANDLE SndTaskHandle, T_FRM_ROUTING_TABLE_ENTRY *pNewEntry, RT_ENTRY Status )
{
T_FRM_ROUTING_TABLE_ENTRY     *pEntry, *pNextEntry, *pPrevEntry;

  /*
   * delete all entries with same OldDestComHandle if a destroy command is stored
   */
  if ( pNewEntry->Command & RT_DESTROY )
  {
    if ( ( pEntry = Routing[SndTaskHandle] ) != NULL )
    {
      do
      {
        if ( pEntry->OldDestComHandle == pNewEntry->OldDestComHandle )
        {
          if ( pEntry == Routing[SndTaskHandle] )
          {
            if ( pEntry->pNextEntry )
            {
              ((T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pNextEntry)->pPrevEntry = NULL;
            }
            Routing[SndTaskHandle] = pEntry->pNextEntry;
          }
          else
          {
            ((T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pPrevEntry)->pNextEntry = pEntry->pNextEntry;
            if ( pEntry->pNextEntry )
            {
              ((T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pNextEntry)->pPrevEntry = pEntry->pPrevEntry;
            }
          }
          pNextEntry = pEntry->pNextEntry;
          os_DeallocateMemory ( SndTaskHandle, (T_VOID_STRUCT*)pEntry );
        }
        else
          pNextEntry = pEntry->pNextEntry;

        pEntry = pNextEntry;
      }
      while ( pEntry );
    }
  }
  else
  {
    /*
     * delete destroy command for OldDestComHandle if a new command is stored
     */
    if ( ( pEntry = Routing[SndTaskHandle] ) != NULL )
    {
      do
      {
        if ( pEntry->OldDestComHandle == pNewEntry->OldDestComHandle )
        {
          if ( pEntry->Command == RT_DESTROY )
          {
            if ( pEntry == Routing[SndTaskHandle] )
            {
              if ( pEntry->pNextEntry )
              {
                ((T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pNextEntry)->pPrevEntry = NULL;
              }
              Routing[SndTaskHandle] = pEntry->pNextEntry;
            }
            else
            {
              ((T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pPrevEntry)->pNextEntry = pEntry->pNextEntry;
              if ( pEntry->pNextEntry )
              {
                ((T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pNextEntry)->pPrevEntry = pEntry->pPrevEntry;
              }
            }
            pNextEntry = pEntry->pNextEntry;
            os_DeallocateMemory ( SndTaskHandle, (T_VOID_STRUCT*)pEntry );
          }
          break;
        }
        else
          pNextEntry = pEntry->pNextEntry;

        pEntry = pNextEntry;
      }
      while ( pEntry );
    }
  }
     
       
  if ( (pEntry = Routing[SndTaskHandle]) != NULL )
  {
    do
    {
      if ( pEntry->SndTaskHandle    == SndTaskHandle   
        && pEntry->NewDestComHandle == pNewEntry->NewDestComHandle  
        && pEntry->OldDestComHandle == pNewEntry->OldDestComHandle  
        && pEntry->MsgType          == pNewEntry->MsgType )
      {
        if ( !strcmp (pEntry->ExtDest, pNewEntry->ExtDest) )
        {
          if ( Status == RT_DELETE )
          {
            if ( pEntry == Routing[SndTaskHandle] )
            {
              Routing[SndTaskHandle] = pEntry->pNextEntry;
              if ( pEntry->pNextEntry )
              {
                ((T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pNextEntry)->pPrevEntry = NULL;
              }
            }
            else
            {
              ((T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pPrevEntry)->pNextEntry = pEntry->pNextEntry;
              if ( pEntry->pNextEntry )
              {
                ((T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pNextEntry)->pPrevEntry = pEntry->pPrevEntry;
              }
            }
            pNextEntry = pEntry->pNextEntry;
            os_DeallocateMemory ( SndTaskHandle, (T_VOID_STRUCT*)pEntry );
            return RT_OK;
          }
#ifndef _TOOLS_
          else
          {
            pEntry->Command = pNewEntry->Command;         /* modify command for old routing entry */
            pEntry->opcMask = pNewEntry->opcMask;       /* set new opcMask in old routing entry */
            pEntry->opcStatus = pNewEntry->opcStatus; /* set new opcStatus in old routing entry */
            return RT_OK;
          }
#else
          pEntry = pEntry->pNextEntry;
#endif
        }
        else
        {
#ifdef _TOOLS_
          if ( ( pEntry->opcMask == pNewEntry->opcMask )
            && ( pEntry->opcStatus == pNewEntry->opcStatus ) )
          {
            strcpy ( pEntry->ExtDest, pNewEntry->ExtDest );
            return RT_OK;
          }
          else
#endif
            pEntry = pEntry->pNextEntry;
        }
      }
      else
        pEntry = pEntry->pNextEntry;
    } while ( pEntry );
  }

  pPrevEntry = NULL;
  if ( ( pEntry = Routing[SndTaskHandle] ) != NULL )
  {
    do
    {
      pPrevEntry = pEntry;
      if ( pNewEntry->Command & RT_DUPLICATE )/* put Duplications at the end of Duplications */
      {
        if ( pEntry->Command & RT_DUPLICATE )
          pEntry = pEntry->pNextEntry;
        else
        {
          if ( pPrevEntry == Routing[SndTaskHandle] )
            pPrevEntry = NULL;
          else
            pPrevEntry = pEntry->pPrevEntry;
          break;
        }
      }
      else
        pEntry = pEntry->pNextEntry;
    }
    while ( pEntry );
  }
  if ( os_AllocateMemory ( SndTaskHandle, (T_VOID_STRUCT**)&pNextEntry, sizeof(T_FRM_ROUTING_TABLE_ENTRY), OS_NO_SUSPEND, ext_data_pool_handle ) == OS_TIMEOUT )
    return RT_NO_MEM;
  pNextEntry->SndTaskHandle = SndTaskHandle;
  pNextEntry->OldDestComHandle = pNewEntry->OldDestComHandle;
  pNextEntry->NewDestComHandle = pNewEntry->NewDestComHandle;
  pNextEntry->OldDestTaskHandle = pNewEntry->OldDestTaskHandle;
  pNextEntry->Command       = pNewEntry->Command;
  pNextEntry->MsgType       = pNewEntry->MsgType;
  pNextEntry->opcMask       = pNewEntry->opcMask;
  pNextEntry->opcStatus     = pNewEntry->opcStatus;
  strcpy ( pNextEntry->ExtDest, pNewEntry->ExtDest );
  
  if ( pEntry )                 
  {
    pEntry->pPrevEntry = pNextEntry;          /* store at the beginning/in the list */
  }
  else                          
    pNextEntry->pNextEntry = NULL;            /* append to the list */

  if ( pPrevEntry )
  {
    pPrevEntry->pNextEntry = pNextEntry;      /* store in the list */
    pNextEntry->pPrevEntry = pPrevEntry;
    pNextEntry->pNextEntry = pEntry;
  }
  else
  {
    Routing[SndTaskHandle] = pNextEntry;      /* store at the beginning */
    pNextEntry->pNextEntry = pEntry;
  }
  return RT_OK;
}
#endif

#if 0
/* not needed -> temporarily removed */
#ifndef RUN_INT_RAM
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)              MODULE  : PF_ROUTE            |
| STATE   : code                       ROUTINE : rt_ModifyRouting    |
+--------------------------------------------------------------------+

  PURPOSE : handle the contents of the redirection or duplicate
            system primitive

*/
GLOBAL SHORT rt_isolate_entity ( T_HANDLE caller, char *entity )
{
T_FRM_ROUTING_TABLE_ENTRY entry;
T_HANDLE snd;
T_HANDLE rcv;
int read_entry = FIRST_ENTRY;

  if ( (rcv = vsi_e_handle ( caller, entity )) == VSI_ERROR )
    return RT_ERROR;
  else
  {
    while ( vsi_c_get_entity_com_entry ( read_entry, rcv, &snd ) == VSI_OK )
    {
      read_entry = NEXT_ENTRY;
      entry.SndTaskHandle = snd;
      entry.OldDestComHandle = rcv;
      entry.NewDestComHandle = 0;
      entry.opcMask = 0;
      entry.MsgType = RT_PRIMITIVE_TYPE;
      entry.Command = RT_DESTROY;
      rt_RoutingEntry ( snd, &entry, RT_STORE );
    }

    entry.SndTaskHandle = rcv;
    entry.OldDestComHandle = ROUTE_ALL;
    entry.NewDestComHandle = 0;
    entry.opcMask = 0;
    entry.MsgType = RT_PRIMITIVE_TYPE;
    entry.Command = RT_DESTROY;
    rt_RoutingEntry ( rcv, &entry, RT_STORE );

    return RT_OK;
  }
}
#endif
#endif

#ifndef RUN_INT_RAM
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)              MODULE  : PF_ROUTE            |
| STATE   : code                       ROUTINE : rt_ModifyRouting    |
+--------------------------------------------------------------------+

  PURPOSE : handle the contents of the redirection or duplicate
            system primitive

*/
GLOBAL SHORT rt_RoutingModify ( T_HANDLE SndTaskHandle, char *Command, char *RoutingString)
{
char Token[81];
char *pChar = RoutingString;
T_FRM_ROUTING_TABLE_ENTRY Entry = { 0 }; 
unsigned int len;
T_FRM_ROUTING_TABLE_ENTRY *pEntry, *pNextEntry;

  if ( !strcmp (Command, SYSPRIM_DUPLICATE_TOKEN) )
    Entry.Command = RT_DUPLICATE;

  if ( !strcmp (Command, SYSPRIM_REDIRECT_TOKEN) )
    Entry.Command = RT_REDIRECT;
  
  if ( (len = GetNextToken (pChar, Token, " #")) == 0 )
    return RT_ERROR;
  else
    pChar += (len+1);

  if ( !strcmp (Token, RT_CLEAR_TOKEN) )
    Entry.Command |= RT_CLEAR_ENTRY;

  if ( !strcmp (Token, RT_ALL_TOKEN) )
    Entry.Command |= RT_ALL_DESTINATION;

  if ( Entry.Command & RT_CLEAR_ENTRY )
  {
    if ( (pEntry = Routing[SndTaskHandle]) != NULL )
    {
      do
      {
        pNextEntry = (T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pNextEntry;
        os_DeallocateMemory ( SndTaskHandle, (T_VOID_STRUCT*)pEntry );
        pEntry = pNextEntry;
      }
      while ( pEntry );
      Routing[SndTaskHandle] = NULL;
    }
    return RT_OK;
  }

  if ( Entry.Command & RT_ALL_DESTINATION )
  {
    Entry.OldDestComHandle = ROUTE_ALL;
    Entry.OldDestTaskHandle = ROUTE_ALL;
  }
  else
  {
    if ( ( Entry.OldDestComHandle = vsi_c_open (SndTaskHandle, Token ) ) == VSI_ERROR )
      return RT_ERROR;
    Entry.OldDestTaskHandle = Entry.OldDestComHandle;
  }

  if ( (len = GetNextToken (pChar, Token, " #")) == 0 )
    return RT_ERROR;
  else
    pChar += (len+1);

  if ( !strcmp (Token, RT_TIMEOUT_TOKEN) ) 		
  {
    Entry.MsgType = RT_TIMEOUT_TYPE;
    if ( (len = GetNextToken (pChar, Token, " #")) == 0 )
      return RT_ERROR;
    else
      pChar += (len+1);

  }
  else
  {
    if ( !strcmp (Token, RT_SIGNAL_TOKEN) )		
    {
      Entry.MsgType = RT_SIGNAL_TYPE;
      if ( (len = GetNextToken (pChar, Token, " #")) == 0 )
        return RT_ERROR;
      else
        pChar += (len+1);
    }
    else
      Entry.MsgType = RT_PRIMITIVE_TYPE;
  } 

  if ( (Token[0] == '1') || (Token[0] == '0') || (Token[0] == '*') )
  {
    rt_CvrtToOpcMask(Token, &Entry.opcMask, &Entry.opcStatus);
    if ( (len = GetNextToken (pChar, Token, " #")) == 0 )
      return RT_ERROR;
    else
      pChar += (len+1);
  }
/*    else */
  { 
    if (!strcmp (Token, SYSPRIM_NULL_TOKEN))
    {
      if ( Entry.Command & RT_REDIRECT )
      {
        Entry.Command |= RT_DESTROY;  /* destroy the primitive */
        Entry.Command &= ~RT_REDIRECT;  
      }
      else
        return RT_ERROR;
    }
    else
    {
      if ( ( Entry.NewDestComHandle = vsi_c_open (SndTaskHandle, Token ) ) == VSI_ERROR )
      {
#ifdef _TOOLS_
        if ( !strcmp ( FRM_PCO_NAME, Token ) )
          return RT_ERROR;
#endif
        if ( ( Entry.NewDestComHandle = vsi_c_open (SndTaskHandle, FRM_TST_NAME ) ) != VSI_ERROR )
        {
          rt_tst_handle = Entry.NewDestComHandle;
          if ( len < RESOURCE_NAMELEN )
          {
            strncpy( Entry.ExtDest, Token, RESOURCE_NAMELEN );
            Entry.ExtDest[RESOURCE_NAMELEN-1] = 0;
          }
          else
            return RT_ERROR;
        }
      }
    }

    if ( Entry.Command & RT_ALL_DESTINATION )
    {
      if ( (pEntry = Routing[SndTaskHandle]) != NULL )
      {
        int all_cleared = 1;
        do
        {
          pNextEntry = (T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pNextEntry;
          if ( (pEntry->NewDestComHandle == Entry.NewDestComHandle )
            && !strcmp(pEntry->ExtDest, Entry.ExtDest) )
          {
            if ( pEntry == Routing[SndTaskHandle] )
            {
              Routing[SndTaskHandle] = pEntry->pNextEntry;
              if ( pEntry->pNextEntry != NULL )
              {
                ((T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pNextEntry)->pPrevEntry = NULL;
              }
            }
            else
            {
              ((T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pPrevEntry)->pNextEntry = pEntry->pNextEntry;
              if ( pEntry->pNextEntry != NULL )
              {
                ((T_FRM_ROUTING_TABLE_ENTRY*)pEntry->pNextEntry)->pPrevEntry = pEntry->pPrevEntry;
              }
            }
            os_DeallocateMemory ( SndTaskHandle, (T_VOID_STRUCT*)pEntry );
          }
          else
          {
            all_cleared = 0;
          }
          pEntry = pNextEntry;
        }
        while ( pEntry );
        if ( all_cleared == 1 )
          Routing[SndTaskHandle] = NULL;
      }
    }

    if ( (pChar >= RoutingString+ strlen (RoutingString)) 
      || ((len = GetNextToken (pChar, Token, " #")) == 0) )
      return ( rt_RoutingEntry(SndTaskHandle, &Entry, RT_STORE) );
    else
      pChar += (len+1);

    if ( Entry.Command & RT_CLEAR_ENTRY )
      return ( rt_RoutingEntry(SndTaskHandle, &Entry, RT_DELETE) );
    return RT_ERROR;
  }
  
}
#endif

#ifndef RUN_FLASH
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)              MODULE  : PF_ROUTE            |
| STATE   : code                       ROUTINE : rt_routePrim        |
+--------------------------------------------------------------------+

  PURPOSE : Looks if the task have some routing rules stored and
            perform the redirection or duplication.

*/

GLOBAL SHORT rt_Route ( T_HANDLE SndTaskHandle, T_HANDLE RcvComHandle, USHORT Prio, ULONG Suspend, OS_QDATA *Msg )
{
T_FRM_ROUTING_TABLE_ENTRY *pEntry;

T_PRIM_HEADER *prim;
ULONG opc;

  if ( ( pEntry = Routing[SndTaskHandle] ) != NULL )
  {
    if ( pEntry->MsgType == Msg->data16 )
    { 
      prim = (T_PRIM_HEADER*)Msg->ptr;

#ifndef _TOOLS_
      if (prim->opc & MEMHANDLE_OPC)
      {
        P_MEMHANDLE_SDU(prim)=0x00000000;
      }
#endif

      do
      {
        if ( SndTaskHandle == pEntry->SndTaskHandle 
         && ( (RcvComHandle == pEntry->OldDestComHandle) || (pEntry->OldDestComHandle == ROUTE_ALL) ) )
        {
        /*
         * a route for the receiver is defined. Now
         * check the filter conditions
         */
          opc = ((T_PRIM_HEADER*)Msg->ptr)->opc;
          if ( (opc & pEntry->opcMask) == (pEntry->opcStatus & pEntry->opcMask) )
          {
          /*
           * filter matched -> redirect, duplicate or destroy
           * the primitive.
           */
            switch (pEntry->Command & RT_COMMAND_MASK)
            {
              case RT_DESTROY: 
                /* add VSI_PPM_FREE(Msg->ptr) just to avoid the PPM warning of freeing a primitive in a queue */
                VSI_PPM_RCV(Msg->ptr);
                VSI_PPM_FREE(Msg->ptr);
                os_DeallocatePartition (SndTaskHandle, Msg->ptr-PPM_OFFSET );
                return RT_OK; 

              case RT_REDIRECT:
#ifndef _TOOLS_
                if (pEntry->NewDestComHandle != rt_tst_handle)
                {
                  /* if not on tool side and not sending via TST -> send directly */
                  Msg->e_id = pEntry->NewDestComHandle;
                  return ( (SHORT)os_SendToQueue ( SndTaskHandle, pf_TaskTable[pEntry->NewDestComHandle].QueueHandle, OS_NORMAL, OS_SUSPEND, Msg ) );
                }
#endif
                /*lint -fallthrough */
              case RT_DUPLICATE:
                if (pEntry->NewDestComHandle != OS_ERROR)
                {
                  OS_QDATA QData;
#ifdef _TOOLS_
                  QData.len = (USHORT)(PSIZE(P2D(Msg->ptr))-sizeof(T_PRIM_HEADER));
#else
                  /* QData.len = 4; not needed if per reference */
                  T_DP_HEADER *dp_hdr;
#if 0                  
                  P_ATTACH(P2D(prim));  /* recursivly increase use counters */
#else
                  prim->use_cnt++;
                  if ( prim->dph_offset != 0 )
                  {
                    dp_hdr = (T_DP_HEADER*)((ULONG*)prim + prim->dph_offset);
                    /* only increment use_cnt for dynamic primitives - not for DTI primitives */
                    if ( dp_hdr->magic_nr == GUARD_PATTERN )
                    {
                      do
                      {
                        dp_hdr->use_cnt++;
                      } while ( (dp_hdr = (T_DP_HEADER*)dp_hdr->next) != NULL );
                    }
                  }
#endif /* 0 */

#endif
                  QData.data16 = MSG_PRIMITIVE;
                  QData.ptr = Msg->ptr;

#ifndef _TOOLS_
                  if (pEntry->NewDestComHandle != rt_tst_handle)
                  {
                    Msg->e_id = pEntry->NewDestComHandle;
                    os_SendToQueue ( SndTaskHandle, pf_TaskTable[pEntry->NewDestComHandle].QueueHandle, OS_NORMAL, OS_SUSPEND, Msg );
                  }
                  else
#endif
                  {
                    /* if on tool side or sending via TST -> send with sys header a.s.o */
                    rt_ExtPrimitive ( SndTaskHandle, pEntry->NewDestComHandle, RcvComHandle, pEntry->ExtDest, &QData );
                  }
                }
                if ( pEntry->Command & RT_REDIRECT )
                {
                  T_VOID_STRUCT *free_ptr = (T_VOID_STRUCT*)P2D(prim);

#ifndef _TOOLS_
                  if ((prim->opc & MEMHANDLE_OPC) && (mem!=NULL))
                  {
                    if (P_MEMHANDLE(prim)!=0)
                    {
                      mem->dealloc(P_MEMHANDLE(prim));
                    }
                  }
#endif /* !_TOOLS_ */
                  
                  vsi_free ((T_VOID_STRUCT**)&free_ptr FILE_LINE_MACRO);
                  return RT_OK; 
                }
                break;
              default:
                break;
            }
          }
        }
        pEntry = pEntry->pNextEntry;
      } while ( pEntry );
    }
  }
  
  /*
   * send original
   */

#ifdef _TOOLS_
  return ( (SHORT)os_SendToQueue ( SndTaskHandle, RcvComHandle, Prio, Suspend, Msg ) );
#else
  if((pf_TaskTable[RcvComHandle].Flags & USE_LEMU_QUEUE) AND
     (lemu_SendToQueue_func.magic_nr == LEMU_SENDTOQUEUE_INITIALIZED))
  {
    if(lemu_SendToQueue_func.plemu_SendToQueue( SndTaskHandle, RcvComHandle,
             pf_TaskTable[RcvComHandle].QueueHandle, Prio, Suspend, Msg ) 
             != lemu_SendToQueue_func.ret_ok  )
    {
      return OS_ERROR;
    }
    return OS_OK;
  }
  else
  {
    return ( (SHORT)os_SendToQueue ( SndTaskHandle, pf_TaskTable[RcvComHandle].QueueHandle, Prio, Suspend, Msg ) );
  }
#endif
}
#endif

#ifndef RUN_INT_RAM
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)              MODULE  : PF_ROUTE            |
| STATE   : code                       ROUTINE : rt_ExtPrimitive     |
+--------------------------------------------------------------------+

  PURPOSE : formats duplicated primitive to be sent to TST

*/
void rt_ExtPrimitive ( T_HANDLE TaskHandle, T_HANDLE DestComHandle, T_HANDLE OrgDestTaskHandle, char *ExtDest, OS_QDATA *Msg ) 
{
T_PRIM_HEADER *prim;
#ifndef _TOOLS_
T_PRIM_HEADER *sdu_prim;
#endif /* not _TOOLS_ */
T_PRIM_HEADER *ptr;
T_S_HEADER *s_hdr;
OS_QDATA DMsg;
ULONG AllocSize;
LONG Status;
ULONG suspend;
#ifdef _TOOLS_
T_S_HEADER *prim_s_hdr;
unsigned int i;
#endif

  prim = (T_PRIM_HEADER*)Msg->ptr;
#ifdef _TOOLS_
  AllocSize = S_ALLOC_SIZE(Msg->len + 1); /* +1 To add LF in TIF */
#else
  if ( prim->dph_offset != 0 )
  {
    T_DP_HEADER *dp_hdr;

    dp_hdr = (T_DP_HEADER*)((ULONG*)prim + prim->dph_offset);
    if ( dp_hdr->magic_nr != GUARD_PATTERN 
#ifdef _TARGET_
      && route_desclist[TaskHandle] == TRUE
#endif
         )
    {
      rt_desclist_to_sdu ( TaskHandle, DestComHandle, prim, &sdu_prim );
      prim = sdu_prim;
    }
  }

  AllocSize = S_ALLOC_SIZE(4 + 1);        /* only ptr to primitive */
#endif /* _TOOLS_ */
  suspend = get_suspend_state(TaskHandle,CHECK_PRIM_SUSPEND);
  Status = os_AllocatePartition ( TaskHandle, (T_VOID_STRUCT**)&ptr, AllocSize, suspend, TestGroupHandle );
  if ( Status == OS_OK || Status == OS_WAITED || Status == OS_ALLOCATED_BIGGER )
  {
    DMsg.data16 = MSG_PRIMITIVE;
  	DMsg.data32 = Msg->data32;
#ifdef _TOOLS_
    DMsg.len = AllocSize;
#endif
    DMsg.ptr = (T_VOID_STRUCT*)ptr;

    ptr->opc = prim->opc;
    ptr->len = AllocSize;
    ptr->sh_offset = S_HDR_OFFSET(AllocSize - sizeof(T_S_HEADER));
    s_hdr = (T_S_HEADER*)((ULONG*)ptr + ptr->sh_offset);
#ifdef _TOOLS_
    if ( prim->sh_offset == 0 )
    {
      /* 
         if the primitive is sent via the TAP REDIRECT TAP ... mechanism, then the prim->sh_offset
         is zero and the org_rcv is filled corresponding to the original addressed entity name.
      */
      vsi_e_name ( TaskHandle, OrgDestTaskHandle, TaskName );
      strcpy (s_hdr->org_rcv, TaskName);
      strcpy (s_hdr->rcv, ExtDest);
    }
    else
    {
      /*
         if the primitive is sent via the TAP TPORT mechanism then the original receiver is already 
         filled by the TAP and copied to the newly allocated primitive to be routed.
      */
      prim_s_hdr = (T_S_HEADER*)((ULONG*)prim + prim->sh_offset);

      for (i = 0; prim_s_hdr->org_rcv[i] != 0 && i < sizeof (s_hdr->org_rcv)-1; i++)
        s_hdr->org_rcv[i] = prim_s_hdr->org_rcv[i];
      for (i = 0; prim_s_hdr->rcv[i] != 0     && i < sizeof (s_hdr->rcv)-1;     i++)
        s_hdr->rcv[i]     = prim_s_hdr->rcv[i];
    }
    get_local_time (&s_hdr->time);
    os_GetTaskName ( TaskHandle, TaskHandle, TaskName );
    strcpy (s_hdr->snd, TaskName);
#else
    vsi_e_name ( TaskHandle, OrgDestTaskHandle, TaskName );
    strcpy (s_hdr->org_rcv, TaskName);
    strcpy (s_hdr->rcv, ExtDest);
    os_GetTime(TaskHandle,&s_hdr->time);
    s_hdr->snd[0] = (char)(TaskHandle | HANDLE_BIT);
#endif
#ifdef _TOOLS_
    memcpy ( (char*)P2D(ptr), P2D(Msg->ptr), Msg->len );
#else
    ((T_PRIM_X*)(ptr))->prim_ptr = prim;
#endif
    DMsg.e_id = DestComHandle;
#ifdef _TOOLS_
    os_SendToQueue ( TaskHandle, DestComHandle, OS_NORMAL, OS_SUSPEND, &DMsg );
#else
    if ((prim->opc & MEMHANDLE_OPC) && (mem!=NULL))
    {
      if (P_MEMHANDLE_SDU(prim)==0x00000000)
      {
        /* copy MEM-handle content into new sdu */
        U8 *user_data;
        U16 ptr_length;
        user_data=mem->get_user_data(P_MEMHANDLE(prim), &ptr_length);

        if (user_data)
        {
          T_sdu *sdu=(T_sdu *)M_ALLOC(ptr_length+2*sizeof(U16));

          sdu->l_buf=ptr_length*8;
          sdu->o_buf=0;
          memcpy(sdu->buf,user_data,ptr_length);

          P_MEMHANDLE_SDU(prim)=(U32)sdu;
        }
      }
      else
      {
        M_ATTACH((void*)P_MEMHANDLE_SDU(prim));
      }
    }

    if ( PrimAborted[TaskHandle] > 0 )
    {
      if ( vsi_o_ttrace ( 0, TC_SYSTEM, "%d %s primitive routings aborted",PrimAborted[TaskHandle], pf_TaskTable[TaskHandle].Name ) == VSI_OK )
        PrimAborted[TaskHandle] = 0;
    }
    if ( os_SendToQueue ( TaskHandle, pf_TaskTable[DestComHandle].QueueHandle, OS_NORMAL, suspend, &DMsg ) == OS_TIMEOUT )
    {
      T_VOID_STRUCT *free_ptr = (T_VOID_STRUCT*)P2D(prim);
      vsi_free ((T_VOID_STRUCT**)&free_ptr FILE_LINE_MACRO);
      vsi_trc_free (0, (T_VOID_STRUCT**)&ptr);
      PrimAborted[TaskHandle]++;
    }
#endif
  }
  else
  {
    T_VOID_STRUCT *free_ptr = (T_VOID_STRUCT*)P2D(prim);
    vsi_free ((T_VOID_STRUCT**)&free_ptr FILE_LINE_MACRO);
    PrimAborted[TaskHandle]++;
  }
}
#endif

#ifndef RUN_INT_RAM
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)              MODULE  : PF_ROUTE            |
| STATE   : code                       ROUTINE : rt_desclist_to_sdu  |
+--------------------------------------------------------------------+

  PURPOSE : formats duplicated primitive with descriptor list into a 
            primitive with SDU

*/
int rt_desclist_to_sdu ( T_HANDLE caller, T_HANDLE dst, T_PRIM_HEADER *prim, T_PRIM_HEADER **sdu_prim )
{
T_PRIM_HEADER *ptr;
T_DP_HEADER *dp_hdr;
T_M_HEADER *m_hdr;
T_desc3 *desc3;
T_desc2 *desc2;
T_desc *desc;
int len = 0;                   
int sdu_prim_size = 0;
char *fill_ptr;
USHORT *l_buf_ptr;
USHORT *o_buf_ptr;
char *sdu_data_ptr;
T_sdu *sdu = NULL;
unsigned int new_opc;
int desc_type = 0; 

  dp_hdr = (T_DP_HEADER*)((ULONG*)prim + prim->dph_offset);
  /* primitive contains descriptor list */

  /*
  START OF NON GENERIC CODE
  This code is for the phase 1 routing of primitives containing descriptor lists.
  It is non-generic and depends on the primitive ids defined in SAP docs.
  It should be removed as soon as the generic descriptor list routing is ready
  */
  switch ( prim->opc )
  {
  case 0x7754: /* DTI2_DATA_IND */
      new_opc = 0x7755; /* DTI2_DATA_TEST_IND */
      desc_type = VSI_DESC_TYPE2 >> 16;
      break;
  case 0x3754: /* DTI2_DATA_REQ */
      new_opc = 0x3755; /* DTI2_DATA_TEST_REQ */
      desc_type = VSI_DESC_TYPE2 >> 16;
      break;
  case 0x6800: /* SN_DATA_IND */
      new_opc = 0x6806; /* SN_DATA_TEST_IND */
      desc_type = VSI_DESC_TYPE2 >> 16;
      break;
  case 0x2800: /* SN_DATA_REQ */
      new_opc = 0x2806; /* SN_DATA_TEST_REQ */
      desc_type = VSI_DESC_TYPE2 >> 16;
      break;
  case 0x6801: /* SN_UNITDATA_IND */
      new_opc = 0x6807; /* SN_DATA_TEST_IND */
      desc_type = VSI_DESC_TYPE2 >> 16;
      break;
  case 0x2801: /* SN_UNITDATA_REQ */
      new_opc = 0x2807; /* SN_DATA_TEST_REQ */
      desc_type = VSI_DESC_TYPE2 >> 16;
      break;
  case 0x7701: /* DTI_DATA_IND */
      new_opc = 0x7702; /* DTI_DATA_TEST_IND */
      desc_type = VSI_DESC_TYPE1 >> 16;
      break;
  case 0x3701: /* DTI_DATA_REQ */
      new_opc = 0x3702; /* DTI_DATA_TEST_REQ */
      desc_type = VSI_DESC_TYPE1 >> 16;
      break;
  case 0x80004097: /* GRLC_DATA_IND */
      new_opc = 0x80014097; /* GRLC_DATA_IND_TEST */
      desc_type = VSI_DESC_TYPE1 >> 16;
      break;
  case 0x80024097: /* GRLC_UNITDATA_IND */
      new_opc = 0x80034097; /* GRLC_UNITDATA_IND_TEST */
      desc_type = VSI_DESC_TYPE1 >> 16;
      break;
  default:
      new_opc = prim->opc;
      break;
  }
  /* END OF NON GENERIC CODE */

  /* 
  it has to be distinguished between T_desc, T_desc2 and T_desc3 because to length information
  is located at different places inside the structure 
  */
  m_hdr = (T_M_HEADER*)(((T_desc_list*)dp_hdr)->first) - 1;
  if ( m_hdr->desc_type != 0 )
  {
    desc_type = m_hdr->desc_type;
  }
  if ( desc_type == (VSI_DESC_TYPE2 >> 16) )
  {
    desc2 = (T_desc2*)(((T_desc_list2*)dp_hdr)->first);
    while (desc2 != NULL)                         
    {                                             
      len = len + desc2->len;
      desc2 = (T_desc2 *)desc2->next;                           
    }
    /* the size to be allocated for the primitive containing the sdu needs to be 
                    root prim length  + data length + sdu size minus data buffer            - desc list2 size */
    sdu_prim_size = prim->len         + len         + sizeof(sdu->l_buf) + sizeof(sdu->o_buf) - sizeof(T_desc_list2);
  }
  else if ( desc_type == (VSI_DESC_TYPE1 >> 16) )
  {
    desc = (T_desc*)(((T_desc_list*)dp_hdr)->first);
    while (desc != NULL)                         
    {                                             
      len = len + desc->len;
      desc = (T_desc *)desc->next;                           
    }
    /* the size to be allocated for the primitive containing the sdu needs to be 
                    root prim length  + data length + sdu size minus data buffer            - desc list size */
    sdu_prim_size = prim->len         + len         + sizeof(sdu->l_buf) + sizeof(sdu->o_buf) - sizeof(T_desc_list);
  }
  else if ( desc_type == (VSI_DESC_TYPE3 >> 16) )
  {
    /* it is assumed that type 3 is valid if not 1 or 2 */
    desc3 = (T_desc3*)(((T_desc_list3*)dp_hdr)->first);
    while (desc3 != NULL)                         
    {                                             
      len = len + desc3->len;
      desc3 = (T_desc3 *)desc3->next;                           
    }
    /* the size to be allocated for the primitive containing the sdu needs to be 
                    root prim length  + data length + sdu size minus data buffer            - desc list3 size */
    sdu_prim_size = prim->len         + len         + sizeof(sdu->l_buf) + sizeof(sdu->o_buf) - sizeof(T_desc_list3);
  }
  else 
  {
    vsi_o_ttrace ( 0, TC_SYSTEM, "unknown desc type in 0x%x, routing aborted", prim->opc );
    vsi_c_free ( caller, (T_VOID_STRUCT**)&prim FILE_LINE_MACRO );
    return RT_ERROR;
  }

  if ( sdu_prim_size < (int)MaxPrimPartSize )
  {
    ptr = (T_PRIM_HEADER*)vsi_c_new ( caller, sdu_prim_size, new_opc FILE_LINE_MACRO );
  }
  else
  {
    vsi_o_ttrace ( 0, TC_SYSTEM, "desclist in 0x%x too long, routing aborted", prim->opc );
    vsi_c_free ( caller, (T_VOID_STRUCT**)&prim FILE_LINE_MACRO );
    return RT_ERROR;
  }
#ifdef MEMORY_SUPERVISION
  vsi_ppm_send ( caller, dst, (T_PRIM_HEADER*)ptr FILE_LINE_MACRO );
#endif /* MEMORY_SUPERVISION */

  fill_ptr = (char*)ptr;
  l_buf_ptr =  &((T_sdu*)((int*)fill_ptr + prim->dph_offset))->l_buf;
  o_buf_ptr =  &((T_sdu*)((int*)fill_ptr + prim->dph_offset))->o_buf;
  sdu_data_ptr = (char*)&((T_sdu*)((int*)fill_ptr + prim->dph_offset))->buf;

  memcpy ( (char*)P2D(fill_ptr), (char*)P2D(prim), prim->len-sizeof(T_PRIM_HEADER) );

  *l_buf_ptr = 0;
  *o_buf_ptr = 0;

  fill_ptr = sdu_data_ptr;

  if ( desc_type == (VSI_DESC_TYPE2 >> 16) )
  {
    desc2 = (T_desc2*)(((T_desc_list2*)dp_hdr)->first);
    while (desc2 != NULL)                         
    {                                             
      *l_buf_ptr += (desc2->len*8);
      memcpy ( fill_ptr, (char*)(&desc2->buffer)+desc2->offset, desc2->len );
      fill_ptr += desc2->len;
      desc2 = (T_desc2 *)desc2->next;                           
    }
  }
  else if ( desc_type == (VSI_DESC_TYPE1 >> 16) )
  {
    desc = (T_desc*)(((T_desc_list*)dp_hdr)->first);
    while (desc != NULL)                         
    {                                             
      *l_buf_ptr += (desc->len*8);
      memcpy ( fill_ptr, (char*)(&desc->buffer), desc->len );
      fill_ptr += desc->len;
      desc = (T_desc *)desc->next;                           
    }
  }
  else if ( desc_type == (VSI_DESC_TYPE3 >>16) )
  {
    desc3 = (T_desc3*)(((T_desc_list3*)dp_hdr)->first);
    while (desc3 != NULL)                         
    {                                             
      *l_buf_ptr += (desc3->len*8);
      memcpy ( fill_ptr, (char*)(desc3->buffer)+desc3->offset, desc3->len );
      fill_ptr += desc3->len;
      desc3 = (T_desc3 *)desc3->next;                           
    }
  }
  vsi_c_free ( caller, (T_VOID_STRUCT**)&prim FILE_LINE_MACRO );
  *sdu_prim = ptr;
  return RT_OK;
}
#endif