diff g23m-aci/uart/uart_kerf.c @ 0:75a11d740a02

initial import of gsm-fw from freecalypso-sw rev 1033:5ab737ac3ad7
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 09 Jun 2016 00:02:41 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/g23m-aci/uart/uart_kerf.c	Thu Jun 09 00:02:41 2016 +0000
@@ -0,0 +1,1718 @@
+/*
++-----------------------------------------------------------------------------
+|  Project :
+|  Modul   :
++-----------------------------------------------------------------------------
+|  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 is part of the entity UART and implements all
+|             procedures and functions as described in the
+|             SDL-documentation (KER-statemachine)
++-----------------------------------------------------------------------------
+*/
+
+#ifndef UART_KERF_C
+#define UART_KERF_C
+#endif /* !UART_KERF_C */
+
+#include "config.h"
+#include "fixedconf.h"
+#include "condat-features.h"
+
+#define ENTITY_UART
+
+/*
+ * Turn off spurious LINT warnings
+ */
+ /*lint -e415 access of out-of-bounds pointer */
+ /*lint -e416 creation of out-of-bounds pointer */
+ /*lint -e661 possible access of out-of-bounds pointer */
+ /*lint -e662 possible craetion of out-of-bounds pointer */
+
+
+/*==== INCLUDES =============================================================*/
+
+#ifdef WIN32
+#include "nucleus.h"
+#endif /* WIN32 */
+#include "typedefs.h"   /* to get Condat data types */
+#include "vsi.h"        /* to get a lot of macros */
+#include "macdef.h"     /* to get a lot of macros */
+#include "custom.h"
+#include "gsm.h"        /* to get a lot of macros */
+#include "cnf_uart.h"   /* to get cnf-definitions */
+#include "mon_uart.h"   /* to get mon-definitions */
+#include "prim.h"       /* to get the definitions of used SAP and directions */
+#include "dti.h"        /* to get dti lib */
+#include "pei.h"        /* to get PEI interface */
+#ifdef FF_MULTI_PORT
+#include "gsi.h"        /* to get definitions of serial driver */
+#else /* FF_MULTI_PORT */
+#ifdef _TARGET_
+#include "../../serial/serialswitch.h"
+#include "../../serial/traceswitch.h"
+#else /* _TARGET_ */
+#include "serial_dat.h" /* to get definitions of serial driver */
+#endif /* _TARGET_ */
+#endif /* FF_MULTI_PORT */
+#include "uart.h"       /* to get the global entity definitions */
+
+#include "uart_kerf.h"  /* to get KER function definitions */
+#include "uart_drxs.h"  /* to get signal definitions for service DRX */
+#include "uart_dtxs.h"  /* to get signal definitions for service DTX */
+#ifdef FF_MULTI_PORT
+#include "uart_ptxs.h"  /* to get signal definitions for service TX */
+#else /* FF_MULTI_PORT */
+#include "uart_txs.h"   /* to get signal definitions for service TX */
+#endif /* FF_MULTI_PORT */
+#include "uart_rts.h"   /* to get signal definitions for service RT */
+#include <string.h>    /* JK, delete warnings: to get memmove */
+/*==== CONST ================================================================*/
+
+/*==== LOCAL VARS ===========================================================*/
+
+/*==== PRIVATE FUNCTIONS ====================================================*/
+
+/*==== PUBLIC FUNCTIONS =====================================================*/
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_setupUart
++------------------------------------------------------------------------------
+| Description : The function ker_setupUart() sets the communication parameters
+|               of UART
+|
+| Parameters  : no parameter
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_setupUart(void)
+{
+  T_UFRET ret; /* Error code returned from a function */
+
+  TRACE_FUNCTION( "ker_setupUart" );
+
+#ifdef FF_MULTI_PORT
+  /*
+   * set new XON / XOFF character
+   */
+  uart_data->xon  = uart_data->ker.act_dcb.XON;
+  uart_data->xoff = uart_data->ker.act_dcb.XOFF;
+  /*
+   * set new parameters
+   */
+#ifndef _SIMULATION_
+  if((ret = GSI_SetConfig(uart_data->device, &uart_data->ker.act_dcb))
+                                                           NEQ DRV_OK)
+  {
+    TRACE_ERROR_P2
+      ("GSI driver: Serial devise configuration failed; [%d], uart_kerf.c(%d)",
+                                                                ret, __LINE__);
+  }
+#endif /* !_SIMULATION_ */
+#else /* FF_MULTI_PORT */
+  /*
+   * set new XON / XOFF character
+   */
+  uart_data->xon  = uart_data->ker.act_xon;
+  uart_data->xoff = uart_data->ker.act_xoff;
+  /*
+   * set new escape sequence parameters
+   */
+  uart_data->act_ec = uart_data->ker.act_ec;
+  uart_data->act_gp = uart_data->ker.act_gp;
+  /*
+   * set new parameters
+   */
+  /*
+   * set up the escape sequence
+   */
+  ret = UF_SetEscape (uart_data->device,
+                      uart_data->act_ec,
+                      uart_data->act_gp);
+#ifdef _SIMULATION_
+  TRACE_EVENT_P1 ("UF_SetEscape() = %x", (USHORT) ret);
+#endif /* _SIMULATION_ */
+  while ((ret = UF_SetComPar (uart_data->device,
+                              uart_data->ker.act_br,
+                              uart_data->ker.act_bpc,
+                              uart_data->ker.act_sb,
+                              uart_data->ker.act_par)) EQ UF_NOT_READY)
+  {
+    if(vsi_t_sleep (VSI_CALLER ONE_FRAME) NEQ VSI_OK)
+    {
+      TRACE_ERROR_P1("VSI entity: Can't suspend thread, uart_kerf.c(%d)",
+                                                               __LINE__);
+    }
+  }
+
+  /*
+   * set new flow control
+   */
+  if (ret EQ UF_OK)
+  {
+    if((ret = UF_SetFlowCtrl (uart_data->device, uart_data->ker.act_fc_rx,
+                              uart_data->xon, uart_data->xoff) NEQ UF_OK)
+                              AND (uart_data->device NEQ 0))
+    {
+      TRACE_ERROR_P2("UF driver: Can't set new flow control, [%d], uart_kerf(%d)",
+                                                                   ret, __LINE__);
+    }
+  }
+#endif /* FF_MULTI_PORT */
+} /* ker_setupUart() */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_init
++------------------------------------------------------------------------------
+| Description : The function ker_init() initializes the UART
+|
+| Parameters  : no parameter
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_init ()
+{
+#ifdef FF_MULTI_PORT
+#ifndef _SIMULATION_
+  T_DRV_EXPORT* drv_export;
+#endif /* !_SIMULATION_ */
+#endif /* FF_MULTI_PORT */
+
+  T_UFRET ret;       /* Error code returned from a function */
+
+  TRACE_FUNCTION( "ker_init" );
+
+  /*
+   * initialize values
+   */
+#ifdef FF_MULTI_PORT
+  uart_data->ker.act_dcb.Baud          = GSI_BAUD_9600;
+  uart_data->ker.act_dcb.DataBits      = GSI_CHAR8;
+  uart_data->ker.act_dcb.StopBits      = GSI_STOP1;
+  uart_data->ker.act_dcb.Parity        = GSI_PARITYNO;
+  uart_data->ker.act_dcb.RxFlowControl = GSI_FLOWHW;
+  uart_data->ker.act_dcb.TxFlowControl = GSI_FLOWHW;
+  uart_data->ker.act_dcb.RxBufferSize  = GSI_MAX_BUFFER_SIZE;
+  uart_data->ker.act_dcb.TxBufferSize  = GSI_MAX_BUFFER_SIZE;
+  uart_data->ker.act_dcb.RxThreshold   = 1;
+  uart_data->ker.act_dcb.TxThreshold   = 1;
+  uart_data->ker.act_dcb.XON           = UART_IO_XON_DEFAULT;
+  uart_data->ker.act_dcb.XOFF          = UART_IO_XOFF_DEFAULT;
+  uart_data->ker.act_dcb.EscChar       = UART_ESC_CHARACTER_DEFAULT;
+  uart_data->ker.act_dcb.GuardPeriod   = UART_GUARD_PERIOD_DEFAULT;
+#else /* FF_MULTI_PORT */
+  uart_data->ker.act_br    = UF_BAUD_9600; /* 9600 baud */
+  uart_data->ker.act_bpc   = bpc_8;        /* 8 bits per character */
+  uart_data->ker.act_sb    = sb_1;         /* 1 stop bit */
+  uart_data->ker.act_par   = pa_none;      /* no parity no space */
+  uart_data->ker.act_fc_rx = fc_rts;       /* Hardware flow control */
+  uart_data->ker.act_fc_tx = fc_rts;       /* Hardware flow control */
+  uart_data->ker.act_xon   = UART_IO_XON_DEFAULT;  /* XOn character */
+  uart_data->ker.act_xoff  = UART_IO_XOFF_DEFAULT; /* XOff character */
+  uart_data->ker.act_ec    = UART_IO_ESC_CHAR_DEFAULT; /* escape character */
+  uart_data->ker.act_gp    = UART_IO_ESC_GP_DEFAULT;   /* guard period */
+#endif /* FF_MULTI_PORT */
+
+  /* bitfield of received UART primitives */
+  uart_data->ker.received_prim = 0;
+  uart_data->ker.flush_state   = UART_KER_NOT_FLUSHING;
+
+  uart_data->ker.rx_data_desc    = NULL;    /* data received from peer  */
+  uart_data->ker.receiving_state = UART_KER_NOT_RECEIVING;
+
+  uart_data->ker.tx_data_desc    = NULL;    /* data to be sent to peer */
+  /* data waiting for access to tx_data_desc */
+  uart_data->ker.tx_data_waiting = NULL;
+  uart_data->ker.sending_state   = UART_KER_NOT_SENDING;
+  uart_data->ker.data_flow_tx    = UART_FLOW_ENABLED;
+  uart_data->ker.nr_t1           = 0;       /* nr running T1 timers yet */
+  uart_data->ker.nr_t2           = 0;       /* nr running T2 timers yet */
+  uart_data->ker.n2              = 0;       /* max nr of retransmissions */
+
+#ifdef FF_MULTI_PORT
+  /*
+   * initialize driver
+   */
+#ifndef _SIMULATION_
+  if((ret=GSI_Init(uart_data->device, uart_data->device,
+                          pei_uart_driver_signal, &drv_export)) NEQ DRV_OK)
+  {
+    TRACE_ERROR_P2("GSI driver: InitSerialDevice failed, [%d], uart_kerf.c(%d)",
+                                                                 ret, __LINE__);
+  }
+#endif /* _SIMULATION_ */
+  /*
+   * set driver signals
+   */
+#ifndef _SIMULATION_
+  if((ret = GSI_SetSignal(uart_data->device, DRV_SIGTYPE_READ  |
+                                             DRV_SIGTYPE_WRITE |
+                                             DRV_SIGTYPE_FLUSH) NEQ DRV_OK)
+  {
+    TRACE_ERROR_P2("GSI entity: SetSignals failed, [%d], uart_kerf.c(%d)",
+                                                           ret, __LINE__);
+  }
+#endif /* _SIMULATION_ */
+#else /* FF_MULTI_PORT */
+  /*
+   * initialize driver
+   */
+  if((ret = UF_Init (uart_data->device)) NEQ UF_OK)
+  {
+    TRACE_ERROR_P2("UF driver: InitSerialDevice failed, [%d], uart_kerf.c(%d)",
+                                                                ret, __LINE__);
+  }
+#ifdef _SIMULATION_
+  TRACE_EVENT_P1 ("UF_Init() = %x", (USHORT) ret);
+#endif /* _SIMULATION_ */
+
+  /*
+   * disable UART
+   */
+  if((ret = UF_Enable (uart_data->device, FALSE)) NEQ UF_OK)
+  {
+    TRACE_ERROR_P2("UF driver: DisableDriver failed, [%d], uart_kerf.c(%d)",
+                                                             ret, __LINE__);
+  }
+  /*
+   * set buffer size
+   */
+  if((ret = UF_SetBuffer (uart_data->device, UF_MAX_BUFFER_SIZE, 1, 1))
+                                                             NEQ UF_OK)
+  {
+    TRACE_ERROR_P2("UF driver: SetBufferSize failed, [%d], uart_kerf.c(%d)",
+                                                             ret, __LINE__);
+  }
+#ifdef _SIMULATION_
+  TRACE_EVENT_P1 ("UF_SetBuffer() = %x", (USHORT) ret);
+  TRACE_EVENT_P1 ("Buffer avail = %d",
+                  (USHORT) UF_OutpAvail (uart_data->device));
+#endif /* _SIMULATION_ */
+#endif /* FF_MULTI_PORT */
+
+  /*
+   * set communication parameters
+   */
+  ker_setupUart();
+
+  INIT_STATE( UART_SERVICE_KER , KER_DEAD );
+
+} /* ker_init() */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_analyze_frame_info_command
++------------------------------------------------------------------------------
+| Description : The function ker_analyze_frame_info_command() analyzes the
+|               information field of incoming frames.
+|               The appropriate internal signals are triggered and a response
+|               frame information field is generated.
+|
+|               Precondition is that the frame check sequence has been
+|               verified, the flags have been removed from the frame and
+|               message resonses have been removed from the frame.
+|
+| Parameters  : forward - result of analysis
+|               frame   - descriptor which includes frame type
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_analyze_frame_info_command (ULONG* forward, T_desc2* frame)
+{
+  T_DLC*  dlc;
+  UBYTE   dlci;
+  USHORT  i;
+  USHORT  pos;
+  USHORT  len;
+
+  TRACE_FUNCTION( "ker_analyze_frame_info_command" );
+
+  pos = UART_OFFSET_INFO;
+
+  /*
+   * parse frame info field until last octet is reached
+   * (minimal message has 2 bytes: type + value)
+   */
+  while(pos < frame->len)
+  {
+    len = 0;
+    while(!(frame->buffer[pos + len] & UART_EA))
+    {
+      len++;
+    }
+    len+= (frame->buffer[pos + 1] >> UART_MSG_LENGTH_POS) + 2;
+    switch(frame->buffer[pos])
+    {
+      case UART_MSG_TYPE_CLD_C:
+        /*
+         * Close Down
+         */
+        *forward|= UART_FORWARD_CLD;
+        frame->buffer[pos] = UART_MSG_TYPE_CLD_R;
+        break;
+      case UART_MSG_TYPE_FCON_C:
+        /*
+         * Flow Control On
+         * inform all DRX instances except Control channel
+         */
+        uart_data->ker.data_flow_tx = UART_FLOW_ENABLED;
+        *forward|= UART_FORWARD_FCON;
+        frame->buffer[pos] = UART_MSG_TYPE_FCON_R;
+        break;
+      case UART_MSG_TYPE_FCOFF_C:
+        /*
+         * Flow Control Off
+         * inform all DRX instances except Control channel
+         */
+        uart_data->ker.data_flow_tx = UART_FLOW_DISABLED;
+        *forward|= UART_FORWARD_FCOFF;
+        frame->buffer[pos] = UART_MSG_TYPE_FCOFF_R;
+        break;
+      case UART_MSG_TYPE_MSC_C:
+        /*
+         * Modem Status Command
+         * can be 2 or 3 octets
+         * (depends if break signal is included or not)
+         */
+        dlci = frame->buffer[pos+2] >> UART_DLCI_POS;
+
+        if((dlci NEQ UART_DLCI_CONTROL) &&
+           (uart_data->dlc_instance[dlci] NEQ UART_EMPTY_INSTANCE))
+        {
+          dlc = &uart_data->dlc_table[uart_data->dlc_instance[dlci]];
+
+          /*
+           * set flow control
+           */
+          if(frame->buffer[pos+3] & UART_MSC_FC_MASK)
+            dlc->lines|= UART_FC_RX_MASK;
+          else
+            dlc->lines&= ~UART_FC_RX_MASK;
+
+          /*
+           * set line states
+           */
+          if(frame->buffer[pos+3] & UART_MSC_RTR_MASK)
+            dlc->lines&= ~UART_RTS_MASK;
+          else
+            dlc->lines|= UART_RTS_MASK;
+
+          if(frame->buffer[pos+3] & UART_MSC_RTC_MASK)
+            dlc->lines&= ~UART_DTR_MASK;
+          else
+            dlc->lines|= UART_DTR_MASK;
+
+          if((len > 4) &&
+             (frame->buffer[pos+4] & UART_MSC_BRK_MASK))
+          {
+            dlc->lines|= UART_BRK_RX_MASK;
+            dlc->lines|= ((ULONG)(frame->buffer[pos+4] & UART_MSC_BRKLEN_MASK) >>
+                          UART_MSC_BRKLEN_POS) <<
+                          UART_BRKLEN_RX_POS;
+          }
+          *forward|= UART_FORWARD_MSC;
+        }
+        else
+        {
+          TRACE_EVENT( "sig_ker_ker_MSC_C: MSC for control channel or \
+                                                 not established DLC" );
+        };
+        frame->buffer[pos] = UART_MSG_TYPE_MSC_R;
+        break;
+      default:
+        TRACE_EVENT( "ker_analyze_frame_info_command: received \
+                                     unsupported message type" );
+        /*
+         * create Non Supported Command response
+         */
+        i = 0;
+        while(!(frame->buffer[pos + i] & UART_EA))
+        {
+          i++;
+        }
+        if(frame->len < uart_data->n1)
+        {
+          /*
+           * move commands behind current command
+           */
+          if(frame->len > (pos + len))
+          {
+            if(len NEQ (i + 3))
+            {
+              memmove(&frame->buffer[pos + i + 3],
+                      &frame->buffer[pos + len],
+                      frame->len - pos - len)
+              ;/*lint !e797 Conceivable creation of out-of-bounds pointer*/
+              frame->len = frame->len - len + i + 3;
+            }
+          }
+          else
+            frame->len = pos + i + 3;
+          /*
+           * insert Non Supported Command
+           */
+          len = i + 3;
+          /*lint -e669 -e670 (Warning -- data overrun/access beyond array) */
+          memmove(&frame->buffer[pos + 2], &frame->buffer[pos], i + 1)
+            ;/*lint !e803 !e804 Conceivable data overrun and access beyond array*/
+          /*lint +e669 +e670 (Warning -- data overrun/access beyond array) */
+          frame->buffer[pos + 1] = (((UBYTE)i + 1) << UART_MSG_LENGTH_POS) |
+                                                      UART_EA;
+          frame->buffer[pos]     = UART_MSG_TYPE_NSC_R;
+        }
+        else
+        {
+          /*
+           * remove command
+           */
+          if(frame->len > (pos + len))
+          {
+            memmove(&frame->buffer[pos],
+                    &frame->buffer[pos + len],
+                    frame->len - pos - len);
+            frame->len-= len;
+          }
+          else
+            frame->len = pos;
+          len = 0;
+        }
+        break;
+    }
+    pos+= len;
+  }
+
+} /* ker_analyze_frame_info_command() */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_search_msg_type
++------------------------------------------------------------------------------
+| Description : The function ker_search_msg_type() searches for a message type
+|               in a frame.
+|
+| Parameters  : frame - descriptor which includes message type
+|               pos   - position to start searching
+|               type  - message type to search for
+|
+| Return      : indicator whether message type was found
+|
++------------------------------------------------------------------------------
+*/
+LOCAL BOOL ker_search_msg_type (T_desc2* frame, USHORT* pos, UBYTE type)
+{
+  TRACE_FUNCTION( "ker_search_msg_type" );
+
+  while(*pos < frame->len)
+  {
+    if(frame->buffer[*pos] EQ type)
+    {
+      return TRUE;
+    }
+    *pos+= (frame->buffer[*pos + 1] >> UART_MSG_LENGTH_POS) + 2;
+  }
+  return FALSE;
+} /* ker_search_msg_type() */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_analyze_frame_info_resonse
++------------------------------------------------------------------------------
+| Description : The function ker_analyze_frame_info_response() analyzes the
+|               information field of incoming frames.
+|               The appropriate internal signals are triggered and the
+|               responses are removed from the information field.
+|
+|               Precondition is that the frame check sequence has been verified
+|               and that the flags have been removed from the frame.
+|
+| Parameters  : forward - result of analysis
+|               frame   - descriptor which includes frame type
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_analyze_frame_info_response (ULONG* forward, T_desc2* frame)
+{
+  USHORT  pos;
+  USHORT  len;
+  T_DLC*  dlc;
+  ULONG   forward_value;
+  USHORT  search_pos;
+  USHORT  search_len;
+  UBYTE   search_command;
+  BOOL    search_found;
+  BOOL    search_whole_msg;
+  USHORT  i;
+
+  TRACE_FUNCTION( "ker_analyze_frame_info_response" );
+
+  /*
+   * check for correct message structure:
+   * - minimal message length == 2 octets
+   * - frame must end with the last message
+   */
+  pos = UART_OFFSET_INFO;
+  while(pos < frame->len)
+  {
+    len = 0;
+    if(!(frame->buffer[pos] & UART_EA))
+    {
+      /*
+       * Type field greater than one octet
+       */
+      do
+        len++;
+      while(((pos + len) < frame->len) &&
+            (!(frame->buffer[pos + len] & UART_EA)));
+    }
+    if(((pos + len + 1) < frame->len) &&
+       (frame->buffer[pos + len + 1] & UART_EA))
+    {
+      len+= (frame->buffer[pos + 1] >> UART_MSG_LENGTH_POS) + 2;
+      if((pos + len) > frame->len)
+        /*
+         * given length in length field to long
+         * remove information field
+         */
+        frame->len = UART_OFFSET_INFO;
+      else
+        pos += len;
+    }
+    else
+      /*
+       * one octet length field expected, but not found
+       * remove information field
+       */
+      frame->len = UART_OFFSET_INFO;
+  }
+  /*
+   * parse frame info field until last octet is reached
+   */
+  pos = UART_OFFSET_INFO;
+  while(pos < frame->len)
+  {
+    len = 0;
+    while(!(frame->buffer[pos + len] & UART_EA))
+    {
+      len++;
+    }
+    len+= (frame->buffer[pos + 1] >> UART_MSG_LENGTH_POS) + 2;
+    if(frame->buffer[pos] & UART_CR)
+    {
+      /*
+       * command detected move to next message
+       */
+      pos+= len;
+    }
+    else
+    {
+      /*
+       * analyze response message
+       */
+      switch( frame->buffer[pos] )
+      {
+        case UART_MSG_TYPE_CLD_R:
+          /*
+           * Close Down
+           */
+          dlc = &uart_data->dlc_table[UART_CONTROL_INSTANCE];
+          search_command   = UART_MSG_TYPE_CLD_C;
+          forward_value    = UART_FORWARD_CLD;
+          search_whole_msg = TRUE;
+          break;
+
+        case UART_MSG_TYPE_FCON_R:
+          /*
+           * Flow Control On
+           */
+          dlc = &uart_data->dlc_table[UART_CONTROL_INSTANCE];
+          search_command   = UART_MSG_TYPE_FCON_C;
+          forward_value    = 0;
+          search_whole_msg = TRUE;
+          break;
+
+        case UART_MSG_TYPE_FCOFF_R:
+          /*
+           * Flow Control Off
+           */
+          dlc = &uart_data->dlc_table[UART_CONTROL_INSTANCE];
+          search_command   = UART_MSG_TYPE_FCOFF_C;
+          forward_value    = 0;
+          search_whole_msg = TRUE;
+          break;
+
+        case UART_MSG_TYPE_MSC_R:
+          /*
+           * Modem Status Command
+           */
+          dlc = &uart_data->dlc_table[UART_CONTROL_INSTANCE];
+          search_command   = UART_MSG_TYPE_MSC_C;
+          forward_value    = 0;
+          search_whole_msg = TRUE;
+          break;
+
+        case UART_MSG_TYPE_NSC_R:
+          /*
+           * not supported command,
+           */
+          dlc = &uart_data->dlc_table[UART_CONTROL_INSTANCE];
+          if(len > 2)
+            search_command = frame->buffer[pos + 2];
+          else
+            search_command = 0;
+          switch(search_command)
+          {
+            case UART_MSG_TYPE_CLD_C:
+              forward_value = UART_FORWARD_CLD;
+              break;
+            default:
+              forward_value = 0;
+              break;
+          }
+          search_whole_msg = FALSE;
+          break;
+
+        default:
+          TRACE_ERROR( "Error in ker_analyze_frame_info_response: \
+                        Unsupported message type received");
+          dlc = &uart_data->dlc_table[UART_CONTROL_INSTANCE];
+          search_command   = 0;
+          forward_value    = 0;
+          search_whole_msg = TRUE;
+          break;
+      }
+      /*
+       * search and remove command message
+       */
+      if(dlc->last_command NEQ NULL)
+      {
+        search_pos   = UART_OFFSET_INFO;
+        search_found = FALSE;
+        while((search_found EQ FALSE) &&
+              (ker_search_msg_type(dlc->last_command,
+                                   &search_pos,
+                                   search_command) EQ TRUE))
+        {
+          search_len   = (dlc->last_command->buffer[search_pos + 1] >>
+                          UART_MSG_LENGTH_POS) + 2;
+          search_found = TRUE;
+          if(search_whole_msg EQ TRUE)
+          {
+            /*
+             * check whole message
+             */
+            for(i=1; i < search_len; i++)
+            {
+              if(dlc->last_command->buffer[search_pos + i] NEQ
+                             frame->buffer[pos + i])
+                search_found = FALSE;
+            }
+          }
+          if(search_found EQ TRUE)
+          {
+            /*
+             * corresponding command message found
+             * remove it
+             */
+            if(dlc->last_command->len > (search_pos + search_len))
+            {
+              memmove(&dlc->last_command->buffer[search_pos],
+                      &dlc->last_command->buffer[search_pos + search_len],
+                      dlc->last_command->len - search_pos - search_len);
+              dlc->last_command->len-= search_len;
+            }
+            else
+              dlc->last_command->len = search_pos;
+            /*
+             * set retransmissions to zero and
+             * set forward parameter
+             */
+            dlc->retransmissions = 0;
+            *forward            |= forward_value;
+          }
+          else
+          {
+            search_pos+= search_len;
+          }
+        }
+      }
+      /*
+       * remove resonse message
+       */
+      if(frame->len > (pos + len))
+      {
+        memmove(&frame->buffer[pos],
+                &frame->buffer[pos + len],
+                frame->len - pos - len);
+        frame->len-= len;
+      }
+      else
+        frame->len = pos;
+    }
+  }
+} /* ker_analyze_frame_info_response() */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_mux_dlc_release
++------------------------------------------------------------------------------
+| Description : This function closes one open multiplexer channel
+|
+| Parameters  : dlc_instance - instance of dlc to release
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_mux_dlc_release (UBYTE dlc_instance)
+{
+  T_DLC*  dlc;
+  UBYTE   dlci;
+
+  TRACE_FUNCTION( "ker_mux_dlc_release" );
+
+  /*
+   * set dlc values
+   */
+  dlc  = &uart_data->dlc_table[dlc_instance];
+  dlci = dlc->dlci;
+  /*
+   * stop timer if this was the last running,
+   * free copy of last command frame
+   */
+  if(dlc->last_command NEQ NULL)
+  {
+    if(dlc->last_command->buffer[UART_OFFSET_CONTROL] EQ
+        UART_UIH_CONTROL_FRAME)
+    {
+      uart_data->ker.nr_t2--;
+      if( uart_data->ker.nr_t2 EQ 0 )
+        sig_ker_rt_stop_t2_req();
+    }
+    else
+    {
+      uart_data->ker.nr_t1--;
+      if( uart_data->ker.nr_t1 EQ 0 )
+        sig_ker_rt_stop_t1_req();
+    }
+    MFREE_DESC2(dlc->last_command);
+    dlc->last_command = NULL;
+  }
+  /*
+   * set connection state
+   */
+  dlc->connection_state = UART_CONNECTION_DEAD;
+  /*
+   * remove DLC instance
+   */
+  if(dlc->next_command NEQ NULL)
+  {
+    MFREE_DESC2(dlc->next_command);
+    dlc->next_command = NULL;
+  }
+  uart_data->dlc_instance[dlci] = UART_EMPTY_INSTANCE;
+  dlc->dlci                     = UART_DLCI_INVALID;
+  /*
+   * close DTI connection
+   */
+  uart_data->drx = dlc->drx;
+  uart_data->dtx = dlc->dtx;
+  sig_ker_drx_dead_mode_req();
+  sig_ker_dtx_dead_mode_req();
+  if(dlc->dti_state NEQ DTI_CLOSED)
+  {
+    dti_close(uart_hDTI, uart_data->device,
+              UART_DTI_UP_INTERFACE, dlc_instance, FALSE);
+    dlc->dti_state = DTI_CLOSED;
+  }
+} /* ker_mux_dlc_release() */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_mux_close_down
++------------------------------------------------------------------------------
+| Description : This function closes all currently open multiplexer channels.
+|
+| Parameters  : no parameter
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_mux_close_down ()
+{
+  UBYTE   i;
+
+  TRACE_FUNCTION( "ker_mux_close_down" );
+
+  /*
+   * close all channels
+   */
+  for(i = 0; i <= UART_MAX_NUMBER_OF_CHANNELS; i++)
+  {
+    /*
+     * set dlc values
+     */
+    if(uart_data->dlc_table[i].dlci NEQ UART_DLCI_INVALID)
+      ker_mux_dlc_release(i);
+  }
+  /*
+   * stop timers
+   */
+  uart_data->ker.nr_t1 = 0;
+  sig_ker_rt_stop_t1_req();
+  uart_data->ker.nr_t2 = 0;
+  sig_ker_rt_stop_t2_req();
+  sig_ker_rt_stop_t3_req();
+
+} /* ker_mux_close_down() */
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_mux_send_frame
++------------------------------------------------------------------------------
+| Description : This function is used to send out a frame in multiplexer mode.
+|               It checks if the KER service is currently sending. If not, the
+|               descriptor is put in the output queue for the TX service and
+|               the service is notified that data is available. If the KER
+|               service is in state sending, the descriptor is put in a second
+|               queue for later processing.
+|
+| Parameters  : frame - descriptor with frame to send
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_mux_send_frame (T_desc2* frame)
+{
+  T_desc2* desc;
+
+  TRACE_FUNCTION( "ker_mux_send_frame" );
+
+  if(uart_data->ker.tx_data_desc)
+  {
+    /*
+     * currently sending, put frame in waiting queue
+     */
+    desc = uart_data->ker.tx_data_waiting;
+    if(desc)
+    {
+      while(desc->next NEQ (ULONG)NULL)
+        desc = (T_desc2*)desc->next;
+      desc->next = (ULONG)frame;
+    }
+    else
+      uart_data->ker.tx_data_waiting = frame;
+  }
+  else
+  {
+    /*
+     * send frame immediately
+     */
+    uart_data->ker.tx_data_desc = frame;
+    sig_ker_tx_data_available_req(uart_data->ker.tx_data_desc, 0);
+  }
+} /* ker_mux_send_frame() */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_mux_send_command_frame
++------------------------------------------------------------------------------
+| Description : This function is used to send out a command frame in
+|               multiplexer mode.
+|               It enables the response timer and saves a copy of the
+|               command frame in the DLC's last_command variable so the
+|               frame can be retransmitted if the timer expires.
+|
+| Parameters  : dlc_instance - dlc instance the command frame belongs to
+|               frame        - descriptor with command frame to send
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_mux_send_command_frame (UBYTE dlc_instance, T_desc2* frame)
+{
+  T_DLC*   dlc;
+  T_desc2* desc;
+
+  TRACE_FUNCTION( "ker_mux_send_command_frame" );
+
+  dlc = &uart_data->dlc_table[dlc_instance];
+  /*
+   * copy frame
+   */
+  if(dlc->last_command NEQ NULL)
+  {
+    /*
+     * currently sending, put command frame in waiting queue
+     */
+    desc = dlc->next_command;
+    if(desc)
+    {
+      while(desc->next NEQ (ULONG)NULL)
+        desc = (T_desc2*)desc->next;
+      desc->next = (ULONG)frame;
+    }
+    else
+      dlc->next_command = frame;
+  }
+  else
+  {
+    MALLOC(dlc->last_command, (USHORT)(sizeof( T_desc2 ) - 1 +
+                               frame->len));
+
+    dlc->last_command->next = (ULONG)NULL;
+    dlc->last_command->len  = frame->len;
+    memcpy(dlc->last_command->buffer, frame->buffer, frame->len);
+
+    /*
+     * set response timer and counter
+     */
+    dlc->retransmissions = 0;
+    if(frame->buffer[UART_OFFSET_CONTROL] EQ UART_UIH_CONTROL_FRAME)
+    {
+      /*
+       * usual UIH Command frame
+       * use T2 timer
+       */
+      uart_data->ker.nr_t2++;
+      sig_ker_rt_start_t2_req();
+    }
+    else
+    {
+      /*
+       * DISC frame
+       * use T1 timer
+       */
+      uart_data->ker.nr_t1++;
+      sig_ker_rt_start_t1_req();
+    }
+
+    /*
+     * use the usual frame send function to transmit the frame
+     */
+    ker_mux_send_frame( frame );
+  }
+} /* ker_mux_send_command_frame() */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_mux_send_line_states
++------------------------------------------------------------------------------
+| Description : This function is used to send out a frame in multiplexer mode.
+|               It creates an UIH frame with MSC command and includes new line
+|               states.
+|
+| Parameters  : dlc_instance - instance of DLC
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_mux_send_line_states(UBYTE dlc_instance)
+{
+  T_DLC*   dlc;
+  T_desc2* frame;
+  USHORT   pos;
+  ULONG    line_states;
+
+  TRACE_FUNCTION( "ker_mux_send_line_states" );
+
+  dlc         = &uart_data->dlc_table[dlc_instance];
+  line_states = dlc->lines;
+  /*
+   * allocate memory
+   */
+  MALLOC(frame, (USHORT)(sizeof( T_desc2 ) - 1 + uart_data->n1 + 2));
+  frame->next = (ULONG)NULL;
+
+  /*
+   * fill frame
+   */
+    /*
+     * address field
+     */
+  pos = 0;
+  frame->buffer[pos] = (UART_DLCI_CONTROL << UART_DLCI_POS) | UART_EA;
+  pos++;
+    /*
+     * control field
+     */
+  frame->buffer[pos] = UART_UIH_CONTROL_FRAME;
+  pos++;
+    /*
+     * type field
+     */
+  frame->buffer[pos] = UART_MSG_TYPE_MSC_C;
+  pos++;
+    /*
+     * length field
+     */
+  if(line_states & UART_BRK_TX_MASK)
+    /*
+     * length 3 with break field
+     */
+    frame->buffer[pos] = (3 << UART_MSG_LENGTH_POS) | UART_EA;
+  else
+    /*
+     * length 2 without break field
+     */
+    frame->buffer[pos] = (2 << UART_MSG_LENGTH_POS) | UART_EA;
+  pos++;
+    /*
+     * DLCI field
+     */
+  frame->buffer[pos] = (dlc->dlci << UART_DLCI_POS) | UART_CR | UART_EA;
+  pos++;
+    /*
+     * V.24 signals
+     */
+  frame->buffer[pos] = UART_EA;
+  if(!(line_states & UART_DCD_MASK))
+    frame->buffer[pos] |= UART_MSC_DV_MASK;
+
+  if(line_states & UART_RI_MASK)
+    frame->buffer[pos] |= UART_MSC_IC_MASK;
+
+  if(!(line_states & UART_CTS_MASK))
+    frame->buffer[pos] |= UART_MSC_RTR_MASK;
+
+  if(!(line_states & UART_DSR_MASK))
+    frame->buffer[pos] |= UART_MSC_RTC_MASK;
+
+  if(line_states & UART_FC_TX_MASK)
+    frame->buffer[pos] |= UART_MSC_FC_MASK;
+
+  pos++;
+
+  /*
+   * break signal
+   */
+  if(line_states & UART_BRK_TX_MASK)
+  {
+    frame->buffer[pos] = (((UBYTE)((line_states & UART_BRKLEN_TX_MASK) >>
+                                                  UART_BRKLEN_TX_POS)) <<
+                                                  UART_MSC_BRKLEN_POS) |
+                                                  UART_MSC_BRK_MASK |
+                                                  UART_EA;
+    pos++;
+    /*
+     * break sent, so clear break flag
+     */
+    dlc->lines&= ~UART_BRK_TX_MASK;
+  }
+
+
+  /*
+   * send frame
+   */
+  frame->len = pos;
+  ker_mux_send_command_frame(UART_CONTROL_INSTANCE, frame);
+
+} /* ker_mux_send_line_states() */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_mux_send_close_down
++------------------------------------------------------------------------------
+| Description : This function is used to send out a frame in multiplexer mode.
+|               It creates an UIH frame with CLD command
+|
+| Parameters  : no parameters
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_mux_send_close_down()
+{
+  T_desc2* frame;
+  USHORT   pos;
+
+  TRACE_FUNCTION( "ker_mux_send_close_down" );
+
+  /*
+   * allocate memory
+   */
+  MALLOC(frame, (USHORT)(sizeof( T_desc2 ) - 1 + uart_data->n1 + 2));
+  frame->next = (ULONG)NULL;
+
+  /*
+   * fill frame
+   */
+    /*
+     * address field
+     */
+  pos = 0;
+  frame->buffer[pos] = (UART_DLCI_CONTROL << UART_DLCI_POS) | UART_EA;
+  pos++;
+    /*
+     * control field
+     */
+  frame->buffer[pos] = UART_UIH_CONTROL_FRAME;
+  pos++;
+    /*
+     * type field
+     */
+  frame->buffer[pos] = UART_MSG_TYPE_CLD_C;
+  pos++;
+    /*
+     * length field
+     */
+  frame->buffer[pos] = UART_EA;
+  pos++;
+
+  /*
+   * send frame
+   */
+  frame->len = pos;
+  frame->size = pos;
+  frame->offset = 0;
+  ker_mux_send_command_frame(UART_CONTROL_INSTANCE, frame);
+} /* ker_mux_send_close_down() */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_send_disc_frame
++------------------------------------------------------------------------------
+| Description : This function is used to send out a frame in multiplexer mode.
+|               It creates an DISC frame and sends it.
+|
+| Parameters  : none
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_send_disc_frame(UBYTE dlci)
+{
+  T_desc2* frame;
+  USHORT   pos;
+
+  TRACE_FUNCTION( "ker_send_disc_frame" );
+
+  /*
+   * allocate memory
+   */
+  MALLOC(frame, (USHORT)(sizeof(T_desc2) - 1 + 2));
+  frame->next = (ULONG)NULL;
+
+  /*
+   * fill frame
+   */
+    /*
+     * address field
+     */
+  pos = 0;
+  frame->buffer[pos] = (dlci << UART_DLCI_POS) | UART_EA;
+  pos++;
+    /*
+     * control field
+     */
+  frame->buffer[pos] = UART_DISC_FRAME;
+  pos++;
+
+  /*
+   * send frame
+   */
+  frame->len = pos;
+  ker_mux_send_command_frame(uart_data->dlc_instance[dlci], frame);
+
+} /* ker_send_disc_frame */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_receive_sabm_frame
++------------------------------------------------------------------------------
+| Description : This function analyzes received SABM frames.
+|
+| Parameters  : forward - result of analysis
+|               frame   - frame to analyze
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_receive_sabm_frame(ULONG* forward, T_desc2* frame)
+{
+  T_DLC*  dlc;
+  UBYTE   dlci;
+  UBYTE   dlc_instance;
+  UBYTE   i;
+
+  TRACE_FUNCTION( "ker_receive_sabm_frame" );
+
+  dlci         = frame->buffer[UART_OFFSET_ADDRESS] >> UART_DLCI_POS;
+  dlc_instance = uart_data->dlc_instance[dlci];
+
+  /*
+   * analyze message responses
+   */
+  ker_analyze_frame_info_response(forward, frame);
+  /*
+   * check whether frame for an existing channel
+   */
+  if(dlc_instance != UART_EMPTY_INSTANCE)
+  {
+    /*
+     * set DLC to this channel
+     */
+    dlc = &uart_data->dlc_table[dlc_instance];
+    switch(dlc->connection_state)
+    {
+      case UART_CONNECTION_OPEN:
+        /*
+         * send UA frame
+         */
+        ker_analyze_frame_info_command(forward, frame);
+        frame->buffer[UART_OFFSET_CONTROL] = UART_UA_FRAME;
+        *forward                          |= UART_FORWARD_RESPONSE;
+        break;
+
+      case UART_CONNECTION_DISC_SENT:
+        /*
+         * send DM frame
+         */
+        ker_analyze_frame_info_command(forward, frame);
+        frame->buffer[UART_OFFSET_CONTROL] = UART_DM_CONTROL_FRAME;
+        *forward                          |= UART_FORWARD_RESPONSE;
+        break;
+
+      case UART_CONNECTION_SABM_RCVD:
+        break;
+
+      default:
+        TRACE_ERROR( "DLC CONNECTION_STATE unexpected" );
+        break;
+    }
+  }
+  else
+  {
+    ker_analyze_frame_info_command(forward, frame);
+    if( dlci EQ UART_DLCI_CONTROL )
+    {
+      /*
+       * this is a SABM frame for the control channel,
+       * therefore the appropriate instance is UART_CONTROL_INSTANCE
+       */
+      dlc = &uart_data->dlc_table[UART_CONTROL_INSTANCE];
+      if(dlc->dlci EQ UART_DLCI_INVALID)
+      {
+        i = UART_CONTROL_INSTANCE;
+        /*
+         * mark DLC as opened
+         */
+        dlc->connection_state = UART_CONNECTION_SABM_RCVD;
+        dlc->dlci             = dlci;
+
+        /*
+         * create UA response frame
+         */
+        frame->buffer[UART_OFFSET_CONTROL] = UART_UA_FRAME;
+        *forward                          |= UART_FORWARD_SABM;
+      }
+      else
+      {
+        i = UART_MAX_NUMBER_OF_CHANNELS + 1;
+      }
+    }
+    else
+    {
+      /*
+       * if new, check whether there is a free channel left
+       */
+      for(i=0; i <= UART_MAX_NUMBER_OF_CHANNELS; i++ )
+      {
+        if(uart_data->dlc_table[i].dlci EQ UART_DLCI_INVALID)
+        {
+          dlc = &uart_data->dlc_table[i];
+          /*
+           * mark DLC as opened
+           */
+          dlc->connection_state = UART_CONNECTION_SABM_RCVD;
+          dlc->dlci             = dlci;
+
+          /*
+           * create UA response frame
+           */
+          frame->buffer[UART_OFFSET_CONTROL] = UART_UA_FRAME;
+          *forward                          |= UART_FORWARD_SABM;
+          break;
+        }
+      }
+    }
+    if( i > UART_MAX_NUMBER_OF_CHANNELS )
+    {
+      /*
+       * no free channel found, return DM frame
+       */
+      frame->buffer[UART_OFFSET_CONTROL] = UART_DM_CONTROL_FRAME;
+    }
+    *forward|= UART_FORWARD_RESPONSE;
+  }
+} /* ker_receive_sabm_frame */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_receive_ua_frame
++------------------------------------------------------------------------------
+| Description : This function analyzes received UA frames.
+|
+| Parameters  : forward - result of analysis
+|               frame   - frame to analyze
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_receive_ua_frame(ULONG* forward, T_desc2* frame)
+{
+  T_DLC*  dlc;
+  UBYTE   dlci;
+  UBYTE   dlc_instance;
+
+  TRACE_FUNCTION( "ker_receive_ua_frame" );
+
+  dlci         = frame->buffer[UART_OFFSET_ADDRESS] >> UART_DLCI_POS;
+  dlc_instance = uart_data->dlc_instance[dlci];
+
+  /*
+   * analyze message responses
+   */
+  ker_analyze_frame_info_response(forward, frame);
+  /*
+   * check whether frame for an existing channel
+   */
+  if(dlc_instance != UART_EMPTY_INSTANCE)
+  {
+    /*
+     * set DLC to this channel
+     */
+    dlc = &uart_data->dlc_table[dlc_instance];
+    switch(dlc->connection_state)
+    {
+      case UART_CONNECTION_DISC_SENT:
+        /*
+         * remove DISC frame
+         */
+        MFREE_DESC2(dlc->last_command);
+        dlc->last_command = NULL;
+        uart_data->ker.nr_t1--;
+        if( uart_data->ker.nr_t1 EQ 0 )
+          sig_ker_rt_stop_t1_req();
+        /*
+         * mark channel as closed
+         */
+        dlc->connection_state = UART_CONNECTION_DEAD;
+        *forward             |= UART_FORWARD_DLC_RELEASE;
+        break;
+
+      case UART_CONNECTION_SABM_RCVD:
+      case UART_CONNECTION_OPEN:
+        break;
+
+      default:
+        TRACE_ERROR( "DLC CONNECTION_STATE unexpected" );
+        break;
+    }
+  }
+} /* ker_receive_ua_frame */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_receive_dm_frame
++------------------------------------------------------------------------------
+| Description : This function analyzes received DM frames.
+|
+| Parameters  : forward - result of analysis
+|               frame   - frame to analyze
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_receive_dm_frame(ULONG* forward, T_desc2* frame)
+{
+  T_DLC*  dlc;
+  UBYTE   dlci;
+  UBYTE   dlc_instance;
+
+  TRACE_FUNCTION( "ker_receive_dm_frame" );
+
+  dlci         = frame->buffer[UART_OFFSET_ADDRESS] >> UART_DLCI_POS;
+  dlc_instance = uart_data->dlc_instance[dlci];
+
+  /*
+   * analyze message responses
+   */
+  ker_analyze_frame_info_response(forward, frame);
+  /*
+   * check whether frame for an existing channel
+   * and not for Control channel
+   */
+  if((dlc_instance NEQ UART_EMPTY_INSTANCE) &&
+     (dlci NEQ UART_DLCI_CONTROL))
+  {
+    /*
+     * set DLC to this channel
+     */
+    dlc = &uart_data->dlc_table[dlc_instance];
+    switch(dlc->connection_state)
+    {
+      case UART_CONNECTION_DISC_SENT:
+        /*
+         * remove DISC frame
+         */
+        MFREE_DESC2(dlc->last_command);
+        dlc->last_command = NULL;
+        uart_data->ker.nr_t1--;
+        if( uart_data->ker.nr_t1 EQ 0 )
+          sig_ker_rt_stop_t1_req();
+        /* fall through */
+      case UART_CONNECTION_OPEN:
+        /*
+         * mark channel as closed
+         */
+        dlc->connection_state = UART_CONNECTION_DEAD;
+        *forward             |= UART_FORWARD_DLC_RELEASE;
+        break;
+
+      case UART_CONNECTION_SABM_RCVD:
+        break;
+
+      default:
+        TRACE_ERROR( "DLC CONNECTION_STATE unexpected" );
+        break;
+    }
+  }
+} /* ker_receive_dm_frame */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_receive_disc_frame
++------------------------------------------------------------------------------
+| Description : This function analyzes received DISC frames.
+|
+| Parameters  : forward - result of analysis
+|               frame   - frame to analyze
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_receive_disc_frame(ULONG* forward, T_desc2* frame)
+{
+  T_DLC*  dlc;
+  UBYTE   dlci;
+  UBYTE   dlc_instance;
+
+  TRACE_FUNCTION( "ker_receive_disc_frame" );
+
+  dlci         = frame->buffer[UART_OFFSET_ADDRESS] >> UART_DLCI_POS;
+  dlc_instance = uart_data->dlc_instance[dlci];
+
+  /*
+   * analyze messages
+   */
+  ker_analyze_frame_info_response(forward, frame);
+  ker_analyze_frame_info_command(forward, frame);
+  /*
+   * check whether frame for an existing channel
+   */
+  if(dlc_instance NEQ UART_EMPTY_INSTANCE)
+  {
+    /*
+     * set DLC to this channel
+     */
+    dlc = &uart_data->dlc_table[dlc_instance];
+    if(dlci EQ UART_DLCI_CONTROL)
+    {
+      /*
+       * send UA frame
+       */
+      frame->buffer[UART_OFFSET_CONTROL] = UART_UA_FRAME;
+      *forward                          |= UART_FORWARD_CLD;
+    }
+    else
+    {
+      switch(dlc->connection_state)
+      {
+        case UART_CONNECTION_DISC_SENT:
+          /*
+           * remove DISC frame
+           */
+          MFREE_DESC2(dlc->last_command);
+          dlc->last_command = NULL;
+          uart_data->ker.nr_t1--;
+          if( uart_data->ker.nr_t1 EQ 0 )
+            sig_ker_rt_stop_t1_req();
+          /* fall through */
+        case UART_CONNECTION_SABM_RCVD:
+        case UART_CONNECTION_OPEN:
+          /*
+           * mark channel as closed
+           */
+          dlc->connection_state = UART_CONNECTION_DEAD;
+          /*
+           * send UA frame
+           */
+          frame->buffer[UART_OFFSET_CONTROL] = UART_UA_FRAME;
+          *forward                          |= UART_FORWARD_DLC_RELEASE;
+          break;
+
+        default:
+          TRACE_ERROR( "DLC CONNECTION_STATE unexpected" );
+          break;
+      }
+    }
+  }
+  else
+  {
+    /*
+     * send DM frame
+     */
+    frame->buffer[UART_OFFSET_CONTROL] = UART_DM_CONTROL_FRAME;
+  }
+  *forward|= UART_FORWARD_RESPONSE;
+} /* ker_receive_disc_frame */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_receive_uih_control_frame
++------------------------------------------------------------------------------
+| Description : This function analyzes received UIH Control frames.
+|
+| Parameters  : forward - result of analysis
+|               frame   - frame to analyze
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_receive_uih_control_frame(ULONG* forward, T_desc2* frame)
+{
+  T_DLC*  dlc;
+  UBYTE   dlci;
+  UBYTE   dlc_instance;
+
+  TRACE_FUNCTION( "ker_receive_uih_control_frame" );
+
+  dlci         = frame->buffer[UART_OFFSET_ADDRESS] >> UART_DLCI_POS;
+  dlc_instance = uart_data->dlc_instance[dlci];
+
+  /*
+   * analyze message responses
+   */
+  ker_analyze_frame_info_response(forward, frame);
+  /*
+   * check whether frame for an existing channel
+   */
+  if(dlc_instance NEQ UART_EMPTY_INSTANCE)
+  {
+    /*
+     * set DLC to this channel
+     */
+    dlc = &uart_data->dlc_table[dlc_instance];
+    /*
+     * check whether it is an command frame
+     * discard frame if it is a response frame
+     */
+    if(frame->buffer[UART_OFFSET_ADDRESS] & UART_CR)
+    {
+      switch(dlc->connection_state)
+      {
+        case UART_CONNECTION_OPEN:
+          /*
+           * send UIH response frame
+           */
+          ker_analyze_frame_info_command(forward, frame);
+          *forward|= UART_FORWARD_RESPONSE;
+          break;
+
+        case UART_CONNECTION_DISC_SENT:
+          /*
+           * send DM frame
+           */
+          ker_analyze_frame_info_command(forward, frame);
+          frame->buffer[UART_OFFSET_CONTROL] = UART_DM_CONTROL_FRAME;
+          *forward                          |= UART_FORWARD_RESPONSE;
+          break;
+
+        case UART_CONNECTION_SABM_RCVD:
+          break;
+
+        default:
+          TRACE_ERROR( "DLC CONNECTION_STATE unexpected" );
+          break;
+      }
+    }
+  }
+  else
+  {
+    /*
+     * send DM frame
+     */
+    ker_analyze_frame_info_command(forward, frame);
+    frame->buffer[UART_OFFSET_CONTROL] = UART_DM_CONTROL_FRAME;
+    *forward                          |= UART_FORWARD_RESPONSE;
+  }
+} /* ker_receive_uih_control_frame */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : ker_receive_uih_data_frame
++------------------------------------------------------------------------------
+| Description : This function analyzes received UIH Data frames.
+|
+| Parameters  : forward - result of analysis
+|               frame   - frame to analyze
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void ker_receive_uih_data_frame(ULONG* forward, T_desc2* frame)
+{
+  UBYTE dlci;
+  UBYTE dlc_instance;
+
+  TRACE_FUNCTION( "ker_receive_uih_data_frame" );
+
+  dlci         = frame->buffer[UART_OFFSET_ADDRESS] >> UART_DLCI_POS;
+  dlc_instance = uart_data->dlc_instance[dlci];
+
+  /*
+   * check whether frame for a not existing channel
+   * discard packet if it is for an extisting channel
+   */
+  if(dlc_instance EQ UART_EMPTY_INSTANCE)
+  {
+    /*
+     * send DM frame
+     * shorten information field
+     */
+    frame->buffer[UART_OFFSET_CONTROL] = UART_DM_DATA_FRAME;
+    frame->len                         = UART_OFFSET_INFO;
+    *forward                          |= UART_FORWARD_RESPONSE;
+  }
+} /* ker_receive_uih_data_frame */