view src/g23m-fad/udp/udp_kerp.c @ 541:5019764a0e9f

doc/Config-vars: RVTMUX_ON_MODEM documented
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 06 Nov 2018 05:20:02 +0000
parents 90eb61ecd093
children
line wrap: on
line source

/*
+----------------------------------------------------------------------------
|  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 defines the functions for processing
|             of incomming primitives for the component
|             Internet Protocol of the mobile station
+----------------------------------------------------------------------------
*/

#define ENTITY_UDP

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

#include <string.h>
#include "typedefs.h"
#include "pcm.h"
#include "pconst.cdg"
#include "mconst.cdg"
#include "message.h"
#include "ccdapi.h"
#include "vsi.h"
#include "macdef.h" /* To get PFREE_DESC2 */
#include "custom.h"
#include "gsm.h"
#include "prim.h"
#include "cnf_udp.h"
#include "mon_udp.h"
#include "pei.h"
#include "tok.h"
#include "dti.h" /* To get DTI lib */
#include "udp.h"

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

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

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

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

/*==== MACROS ======================================================*/

/*==== Prototypes ==================================================*/

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

/*
+--------------------------------------------------------------------+
| PROJECT : WAP                           MODULE  : UDP_KERP         |
| STATE   : code                          ROUTINE : ker_udpa_dti_req |
+--------------------------------------------------------------------+

  PURPOSE : Process UDPA_DTI_REQ primitive
*/

void ker_udpa_dti_req (T_UDPA_DTI_REQ * udpa_dti_req)
{
  BOOL confirm = TRUE;
  UBYTE dti_conn = UDPA_DISCONNECT_DTI;
  PACCESS (udpa_dti_req);

  TRACE_FUNCTION ("ker_udpa_dti_req()");

  switch (GET_STATE (KER))
  {
    case DEACTIVATED:
    {
      switch (udpa_dti_req->dti_conn)
      {
        case UDPA_CONNECT_DTI:
        {
          switch (udpa_dti_req->dti_direction)
          {
            case UDPA_DTI_TO_HIGHER_LAYER:
              if (! * udp_data->hila.entity_name)
              {
                hCommHL = vsi_c_open (
                  VSI_CALLER (char *) udpa_dti_req->entity_name
                );
                if (hCommHL > VSI_OK)
                {
                  udp_data->hila.link_id = udpa_dti_req->link_id;
                  strcpy (
                    udp_data->hila.entity_name,
                    (char *) udpa_dti_req->entity_name
                  );
                  SET_STATE (HILA, CONNECTING);
                  if (dti_open (
                    udp_hDTI,
                    UDP_DTI_DEF_INSTANCE,
                    UDP_DTI_HL_INTERFACE,
                    UDP_DTI_DEF_CHANNEL,
                    UDP_DTI_INIT_QUEUE_SIZE,
                    DTI_CHANNEL_TO_HIGHER_LAYER,
                    FLOW_CNTRL_ENABLED,
                    DTI_VERSION_10,
                    (U8 *) udpa_dti_req->entity_name,
                    udpa_dti_req->link_id
                  ) EQ TRUE)
                  {
                    confirm = FALSE;
                  }
                  else /* dti_open failed, close VSI handle: */
                  {
                    vsi_c_close (VSI_CALLER hCommHL);
                    hCommHL = VSI_ERROR;
                  }
                }
              }
              else
              {
                TRACE_ERROR ("DTI link to higher layer already requested");
              }
              break;

            case UDPA_DTI_TO_LOWER_LAYER:
              if (! * udp_data->lola.entity_name)
              {
                udp_data->lola.link_id = udpa_dti_req->link_id;
                strcpy (
                  udp_data->lola.entity_name,
                  (char *) udpa_dti_req->entity_name
                );
                SET_STATE (LOLA, CONNECTING);
                if (dti_open (
                  udp_hDTI,
                  UDP_DTI_DEF_INSTANCE,
                  UDP_DTI_LL_INTERFACE,
                  UDP_DTI_DEF_CHANNEL,
                  UDP_DTI_INIT_QUEUE_SIZE,
                  DTI_CHANNEL_TO_LOWER_LAYER,
                  FLOW_CNTRL_ENABLED,
                  DTI_VERSION_10,
                  (U8 *) udpa_dti_req->entity_name,
                  udpa_dti_req->link_id
                ) EQ TRUE)
                {
                  confirm = FALSE;
                }
              }
              else
              {
                TRACE_ERROR ("DTI link to lower layer already requested");
              }
              break;

            default:
              TRACE_ERROR("illegal parameter (udpa_dti_req->dti_direction)");
          } /* End switch (udpa_dti_req->dti_direction) */
          dti_conn = UDPA_DISCONNECT_DTI;
          break;
        }

        case UDPA_DISCONNECT_DTI:
        {
          if (udp_data->hila.link_id EQ udpa_dti_req->link_id)
          {
            dti_close (
              udp_hDTI,
              UDP_DTI_DEF_INSTANCE,
              UDP_DTI_HL_INTERFACE,
              UDP_DTI_DEF_CHANNEL,
              FALSE
            );
            *udp_data->hila.entity_name = 0;
            SET_STATE (HILA, DOWN);
            dti_conn = UDPA_DISCONNECT_DTI;

            vsi_c_close (VSI_CALLER hCommHL);
            hCommHL = VSI_ERROR;
            /*XXX check for remaining UP/DOWN-LINK DTI connections, XXX*/
            /*XXX terminate_ip() if noting left open                XXX*/
          }
          else if (udp_data->lola.link_id EQ udpa_dti_req->link_id)
          {
            dti_close (
              udp_hDTI,
              UDP_DTI_DEF_INSTANCE,
              UDP_DTI_LL_INTERFACE,
              UDP_DTI_DEF_CHANNEL,
              FALSE
            );
            *udp_data->lola.entity_name = 0;
            SET_STATE (LOLA, DOWN);
            dti_conn = UDPA_DISCONNECT_DTI;

            /*XXX check for remaining UP/DOWN-LINK DTI connections, XXX*/
            /*XXX terminate_ip() if noting left open                XXX*/
          }
          else
          {
            TRACE_ERROR ("illegal parameter (udpa_dti_req->dti_conn)");
            dti_conn = UDPA_CONNECT_DTI;
          }
        }
        break;
      } /* End switch (udpa_dti_req->dti_conn) */
      break;
    }

    case ACTIVE_NC:
      switch (udpa_dti_req->dti_conn)
      {
      case UDPA_DISCONNECT_DTI:
        if (udp_data->hila.link_id EQ udpa_dti_req->link_id)
        {
          dti_close (
            udp_hDTI,
            UDP_DTI_DEF_INSTANCE,
            UDP_DTI_HL_INTERFACE,
            UDP_DTI_DEF_CHANNEL,
            FALSE
          );
          *udp_data->hila.entity_name = 0;
          SET_STATE (HILA, DOWN);
          dti_conn = UDPA_DISCONNECT_DTI;
          SET_STATE (KER, DEACTIVATED);

          vsi_c_close (VSI_CALLER hCommHL);
          hCommHL = VSI_ERROR;
        }
        else if (udp_data->lola.link_id EQ udpa_dti_req->link_id)
        {
          dti_close (
            udp_hDTI,
            UDP_DTI_DEF_INSTANCE,
            UDP_DTI_LL_INTERFACE,
            UDP_DTI_DEF_CHANNEL,
            FALSE
          );
          *udp_data->lola.entity_name = 0;
          SET_STATE (LOLA, DOWN);
          dti_conn = UDPA_DISCONNECT_DTI;
          SET_STATE (KER, DEACTIVATED);
        }
        break;
      default:
        TRACE_ERROR ("unexpected parameter (udpa_dti_req->dti_conn)");
        dti_conn = UDPA_DISCONNECT_DTI;
        break;
      } /* End switch (udpa_dti_req->dti_conn) */
      break;

    case CONNECTED:
    default:
      TRACE_ERROR ("unexpected UDPA_DTI_REQ");
      if (udpa_dti_req->dti_conn EQ UDPA_CONNECT_DTI)
        dti_conn = UDPA_DISCONNECT_DTI;
      else
        dti_conn = UDPA_CONNECT_DTI;
      break;
  } /* End switch (GET_STATE (KER)) */

  if (confirm)
  {
    PALLOC (udpa_dti_cnf, UDPA_DTI_CNF);
    udpa_dti_cnf->dti_conn = dti_conn;
    udpa_dti_cnf->link_id = udpa_dti_req->link_id;
    PSENDX (ACI, udpa_dti_cnf);
  }
  PFREE (udpa_dti_req);
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP         MODULE  : UDP_KERP                           |
| STATE   : code        ROUTINE : sig_dti_ker_tx_buffer_ready_ll_ind |
+--------------------------------------------------------------------+

  PURPOSE : Process signal SIG_DTI_KER_TX_BUFFER_READY_DN_IND
*/

void sig_dti_ker_tx_buffer_ready_ll_ind ()
{
  TRACE_FUNCTION ("sig_dti_ker_tx_buffer_ready_ll_ind()");

  switch (GET_STATE (KER))
  {
  case ACTIVE_NC: /* DTI_READY_IND not received yet */
    SET_STATE (HILA, WAIT);
    break;

  case CONNECTED:
    {
      T_KER * p_ker = & udp_data->ker;
      T_HILA * p_ul = & udp_data->hila;

      /* Check if an ICMP message shall be sent */

      if (p_ker->send_icmp)
      {
        T_DTI2_DATA_REQ * dti_data_req;

        p_ker->send_icmp = FALSE;

        if(p_ker->dti_data_req_icmp)
        {
          dti_data_req = p_ker->dti_data_req_icmp;
          p_ker->dti_data_req_icmp = NULL;
        }
        else
        {
          TRACE_ERROR("no ICMP message ready!");
          return;
        }

        dti_data_req->parameters.p_id                  = DTI_PID_IP;
        dti_data_req->parameters.st_lines.st_flow      = DTI_FLOW_ON;
        dti_data_req->parameters.st_lines.st_line_sa   = DTI_SA_ON;
        dti_data_req->parameters.st_lines.st_line_sb   = DTI_SB_ON;
        dti_data_req->parameters.st_lines.st_break_len = DTI_BREAK_OFF;

        PACCESS (dti_data_req);
        {
          PPASS (dti_data_req, dti_data_ind, DTI2_DATA_IND);
          dti_send_data (
            udp_hDTI,
            UDP_DTI_DEF_INSTANCE,
            UDP_DTI_LL_INTERFACE,
            UDP_DTI_DEF_CHANNEL,
            dti_data_ind
          );
        }

        /* Call dti_start to indicate ready */

        dti_start (
          udp_hDTI,
          UDP_DTI_DEF_INSTANCE,
          UDP_DTI_HL_INTERFACE,
          UDP_DTI_DEF_CHANNEL
        );
      }
      /* If we have got a ready indication from LL - send dti_data_req */
      else if (GET_STATE (HILA) EQ SEND AND p_ul->dti_data_req)
      {
        p_ul->dti_data_req->parameters.p_id                  = DTI_PID_IP;
        p_ul->dti_data_req->parameters.st_lines.st_flow      = DTI_FLOW_ON;
        p_ul->dti_data_req->parameters.st_lines.st_line_sa   = DTI_SA_ON;
        p_ul->dti_data_req->parameters.st_lines.st_line_sb   = DTI_SB_ON;
        p_ul->dti_data_req->parameters.st_lines.st_break_len = DTI_BREAK_OFF;

        PACCESS (p_ul->dti_data_req);
        {
          PPASS (p_ul->dti_data_req, dti_data_ind, DTI2_DATA_IND);
          dti_send_data (
            udp_hDTI,
            UDP_DTI_DEF_INSTANCE,
            UDP_DTI_LL_INTERFACE,
            UDP_DTI_DEF_CHANNEL,
            dti_data_ind
          );
        }
        p_ul->dti_data_req = NULL;
        dti_start (
          udp_hDTI,
          UDP_DTI_DEF_INSTANCE,
          UDP_DTI_HL_INTERFACE,
          UDP_DTI_DEF_CHANNEL
        );
      }
      else
      {
        SET_STATE (HILA, WAIT);
      }
    }
    break;

  default:
    break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP           MODULE  : UDP_KERP                         |
| STATE   : code          ROUTINE : sig_dti_ker_data_received_hl_ind |
+--------------------------------------------------------------------+

  PURPOSE : Process signal SIG_DTI_KER_DATA_RECEIVED_UP_IND
*/

void sig_dti_ker_data_received_hl_ind (T_DTI2_DATA_REQ * dti_data_req)
{
  PACCESS (dti_data_req);

  TRACE_FUNCTION ("sig_dti_ker_data_received_hl_ind()");

  switch (GET_STATE (KER))
  {
  case CONNECTED:
    {
      T_HILA * p_ul = & udp_data->hila;
      T_KER * p_ker = & udp_data->ker;

      dti_stop (
        udp_hDTI,
        UDP_DTI_DEF_INSTANCE,
        UDP_DTI_HL_INTERFACE,
        UDP_DTI_DEF_CHANNEL
      );

#ifdef _SIMULATION_
      /* Get the T_SRC_DES out of the first and only descriptor
       * created by DTILIB and put it in a descriptor of its own */

      if (dti_data_req->desc_list2.first &&
          dti_data_req->desc_list2.list_len >= sizeof(T_SRC_DES))
      {
        // The following is mostly taken from UDPa_sendRequest() from module
        // wap_udpc.c to achieve the same behaviour. (Issue UDP-FIX-21925)
        // The desc from the desc_list2 is splitted into a linked desc list
        // to simulate large data chunks (such large data chunks are spread over
        // in several decs in the list).
        T_desc2    *desc, *first_desc;
        ULONG      *pLast;
        USHORT     len, dataSize, data_length;
        const char *data_p;
        USHORT     BLOCK_SIZE = 50;

        first_desc = (T_desc2 *) dti_data_req->desc_list2.first;
        data_length = dti_data_req->desc_list2.list_len;

        /* Build the T_desc2 for IP addresses and ports */
        desc = M_ALLOC (offsetof (T_desc2, buffer) + sizeof (T_SRC_DES));
        
        // update the desc list
        dti_data_req->desc_list2.first = (ULONG) desc;
        desc->offset = 0;
        desc->len = sizeof (T_SRC_DES);
        desc->size = sizeof (T_SRC_DES);

        // copy IP addresses and ports
        memcpy(desc->buffer, &first_desc->buffer[first_desc->offset],desc->len);
        
        /* Build the desc for the UDP data */
        pLast = &desc->next;
        len = data_length - desc->len;
        data_p = &first_desc->buffer [first_desc->offset + desc->len];;
        while (len >0)
        {
          if (len > BLOCK_SIZE)
          {
            dataSize = BLOCK_SIZE;
          }
          else
          {
            dataSize = len;
          }
          MALLOC (desc, (USHORT)(sizeof(T_desc2) - 1 + dataSize));
          memcpy( desc->buffer, data_p, dataSize);
          desc->offset = 0;
          desc->len = dataSize;
          desc->size = dataSize;
          len        -= dataSize;
          data_p     += dataSize;
          *pLast      = (ULONG) desc;
          pLast       = &desc->next;
        }

        MFREE (first_desc);
      }
#endif /* _SIMULATION_ */

      p_ul->dti_data_req = dti_data_req;

      if (p_ul->drop_packet)
      {
        p_ul->drop_packet = FALSE;
        PFREE_DESC2 (p_ul->dti_data_req);
        p_ul->dti_data_req = NULL;
        dti_start (
          udp_hDTI,
          UDP_DTI_DEF_INSTANCE,
          UDP_DTI_LL_INTERFACE,
          UDP_DTI_DEF_CHANNEL
        );
      }
      else
      {
        /* Get the IP addresses and the ports from HL */

        T_desc2 * desc = (T_desc2 *) p_ul->dti_data_req->desc_list2.first;
        T_SRC_DES * p_SrcDes;
        USHORT old_len;

        if (desc == NULL) {
          TRACE_ERROR (
            "Hila's T_desc2 is NULL in "
            "sig_dti_ker_data_received_hl_ind()."
          );
          return;
        }

        p_SrcDes = (T_SRC_DES *) (desc->buffer + desc->offset);

        memcpy (& p_ker->src_addr, p_SrcDes->src_ip, 4);
        memcpy (& p_ker->dst_addr, p_SrcDes->des_ip, 4);
        memcpy (& p_ker->src_port, p_SrcDes->src_port, 2);
        memcpy (& p_ker->dst_port, p_SrcDes->des_port, 2);

        old_len = p_ul->dti_data_req->desc_list2.list_len;
        p_ul->dti_data_req->desc_list2.first = desc->next;
        p_ul->dti_data_req->desc_list2.list_len =
          (USHORT) (old_len - sizeof (T_SRC_DES));
        p_ul = & udp_data->hila;
        MFREE (desc);
      }

      /* Send IP_ADDR_REQ to LL */
      {
        PALLOC (ip_addr_req, IP_ADDR_REQ);
        ip_addr_req->dst_addr = p_ker->dst_addr;
        ip_addr_req->trans_prot = UDP_PROTOCOL;
        PSENDX (LL, ip_addr_req);
      }
    }
    break;

  default:
    PFREE_DESC2 (dti_data_req);
    break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP                            MODULE  : udp_kerp.c      |
| STATE   : code                           ROUTINE : ker_ip_addr_cnf |
+--------------------------------------------------------------------+

  PURPOSE : Process primitive T_IP_ADDR_CNF
*/

void ker_ip_addr_cnf (T_IP_ADDR_CNF * ip_addr_cnf)
{
  TRACE_FUNCTION ("ker_ip_addr_cnf()");
  PACCESS (ip_addr_cnf);

  switch (GET_STATE (KER))
  {
  case CONNECTED:
    {
      T_KER * p_ker = & udp_data->ker;
      T_HILA * p_ul = & udp_data->hila;
      BOOL send_ready_ind = FALSE;

      /* No error ? */
      if (ip_addr_cnf->err NEQ IP_ADDR_NOERROR)
      {
        PALLOC (udp_error_ind, UDP_ERROR_IND);
        udp_error_ind->dst_port = p_ker->dst_port;
        udp_error_ind->src_port = p_ker->src_port;
        udp_error_ind->err_msg  = ip_addr_cnf->err;
        udp_error_ind->src_addr = ip_addr_cnf->src_addr;
        udp_error_ind->dst_addr = p_ker->dst_addr;
        PSENDX (HL, udp_error_ind);
        p_ul->drop_packet = TRUE; /* Packet error - drop it */
      }
      /* Is the address correct ? */
      else if (ip_addr_cnf->src_addr NEQ p_ker->src_addr)
      {
        PALLOC (udp_error_ind, UDP_ERROR_IND);
        udp_error_ind->dst_port = p_ker->dst_port;
        udp_error_ind->src_port = p_ker->src_port;
        udp_error_ind->err_msg  = IP_ADDR_NOROUTE;
        udp_error_ind->src_addr = ip_addr_cnf->src_addr;
        udp_error_ind->dst_addr = p_ker->dst_addr;
        PSENDX (HL, udp_error_ind);
        p_ul->drop_packet = TRUE; /* Packet error - drop it */
      }
      else /* Build the "standard" packet for higher layer */
      {
        udp_build_packet (TRUE, B_NORMAL_PACKET);
      }

      /* ICMP sent at first */
      if (p_ker->send_icmp && GET_STATE (HILA) EQ WAIT)
      {
        T_DTI2_DATA_REQ * dti_data_req;
        dti_data_req = p_ker->dti_data_req_icmp;
        dti_data_req->parameters.p_id                  = DTI_PID_IP;
        dti_data_req->parameters.st_lines.st_flow      = DTI_FLOW_ON;
        dti_data_req->parameters.st_lines.st_line_sa   = DTI_SA_ON;
        dti_data_req->parameters.st_lines.st_line_sb   = DTI_SB_ON;
        dti_data_req->parameters.st_lines.st_break_len = DTI_BREAK_OFF;

        PACCESS (dti_data_req);
        {
          PPASS (dti_data_req, dti_data_ind, DTI2_DATA_IND);
          dti_send_data (
            udp_hDTI,
            UDP_DTI_DEF_INSTANCE,
            UDP_DTI_LL_INTERFACE,
            UDP_DTI_DEF_CHANNEL,
            dti_data_ind
          );
        }
        p_ker->dti_data_req_icmp = NULL;
        SET_STATE (HILA, SEND);

        /* Call dti_start to indicate ready for new packet */
        dti_start (
          udp_hDTI,
          UDP_DTI_DEF_INSTANCE,
          UDP_DTI_LL_INTERFACE,
          UDP_DTI_DEF_CHANNEL
        );
      }

      /* Packet not correct - drop it */
      if (p_ul->drop_packet)
      {
        p_ul->drop_packet = FALSE;
        PFREE_DESC2 (p_ul->dti_data_req);
        p_ul->dti_data_req = NULL;
        send_ready_ind = TRUE;
      }
      else
      {
        /* We have got a ready indication from LL -> send */

        if (GET_STATE (HILA) EQ WAIT) /* Send dti_data_req packet */
        {
          p_ul->dti_data_req->parameters.p_id                 = DTI_PID_IP;
          p_ul->dti_data_req->parameters.st_lines.st_flow     = DTI_FLOW_ON;
          p_ul->dti_data_req->parameters.st_lines.st_line_sa  = DTI_SA_ON;
          p_ul->dti_data_req->parameters.st_lines.st_line_sb  = DTI_SB_ON;
          p_ul->dti_data_req->parameters.st_lines.st_break_len=DTI_BREAK_OFF;

          PACCESS (p_ul->dti_data_req);
          {
            PPASS (p_ul->dti_data_req, dti_data_ind, DTI2_DATA_IND);
            dti_send_data (
              udp_hDTI,
              UDP_DTI_DEF_INSTANCE,
              UDP_DTI_LL_INTERFACE,
              UDP_DTI_DEF_CHANNEL,
              dti_data_ind
            );
          }
          SET_STATE (HILA, IDLE);
          send_ready_ind = TRUE;
          p_ul->dti_data_req = NULL;
        }
        else
        {
          SET_STATE (HILA, SEND);
          send_ready_ind = FALSE;
        }
      }

      /* Send dti_ready indication */
      if (send_ready_ind)
      {
        dti_start (
          udp_hDTI,
          UDP_DTI_DEF_INSTANCE,
          UDP_DTI_HL_INTERFACE,
          UDP_DTI_DEF_CHANNEL
        );
      }
      PFREE (ip_addr_cnf);
    }
    break;

    default:
      PFREE (ip_addr_cnf);
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP           MODULE  : udp_kerp.c                       |
| STATE   : code          ROUTINE : sig_dti_ker_data_received_ll_ind |
+--------------------------------------------------------------------+

  PURPOSE : Process signal SIG_DTI_KER_DATA_RECEIVED_DN_IND
*/

void sig_dti_ker_data_received_ll_ind (T_DTI2_DATA_IND * dti_data_ind)
{
  TRACE_FUNCTION ("sig_dti_ker_data_received_ll_ind()");
  PACCESS (dti_data_ind);

  switch (GET_STATE (KER))
  {
  case CONNECTED:
    {
      USHORT calc_chksum, header_chksum, start_udp, udp_len;
      UBYTE prot;
      BOOL send_getdata_req = FALSE;
      UBYTE * ip_header;
      T_desc_list2 * desc_list;
      T_desc2 * desc;

      T_KER * p_ker = & udp_data->ker;
      T_LOLA * p_dl = & udp_data->lola;

      dti_stop (
        udp_hDTI,
        UDP_DTI_DEF_INSTANCE,
        UDP_DTI_LL_INTERFACE,
        UDP_DTI_DEF_CHANNEL
      );

      /* Build necessary variable */

      p_dl->dti_data_ind = dti_data_ind;
      p_dl->state_err = STATE_DL_NO_ERROR;

      desc_list = & p_dl->dti_data_ind->desc_list2;
      desc = (T_desc2 *) desc_list->first;

      if (
        desc == NULL ||
        desc->len < LEN_IP_HEADER_B ||
        GET_IP_HEADER_LEN_B (desc->buffer + desc->offset) < LEN_IP_HEADER_B ||
        desc->len < GET_IP_HEADER_LEN_B (desc->buffer + desc->offset) +
          LEN_UDP_HEADER_B
      ) {
        TRACE_ERROR (
          "Lola's UDP packet is too short in "
          "sig_dti_ker_data_received_ll_ind()."
        );
        return;
      }

      ip_header = desc->buffer + desc->offset;
      start_udp = (USHORT) GET_IP_HEADER_LEN_B (ip_header);

      /* Fill in port numbers and IP addresses */

      p_dl->src_addr = GET_IP_SOURCE_ADDR (ip_header);
      p_dl->dst_addr = GET_IP_DEST_ADDR (ip_header);
      p_dl->src_port = (USHORT) GET_UDP_SRC_PORT (ip_header, start_udp);
      p_dl->dst_port = (USHORT) GET_UDP_DST_PORT (ip_header, start_udp);

      udp_len = (USHORT) GET_UDP_LEN (ip_header, start_udp);
      prot = GET_IP_PROT (ip_header);

      /* Check if ICMP Message, if yes - send UDP_ERROR_IND */

      if (GET_IP_PROT (ip_header) EQ ICMP_PROT)
      {
        USHORT pos_icmp = (USHORT) GET_IP_HEADER_LEN_B (ip_header);

        p_dl->drop_packet = TRUE;
        p_dl->state_err = STATE_DL_ERROR;
        {
          PALLOC (udp_error_ind, UDP_ERROR_IND);
          udp_error_ind->dst_port = p_dl->dst_port;
          udp_error_ind->src_port = p_dl->src_port;
          udp_error_ind->err_msg  = GET_ICMP_TYPE (ip_header, pos_icmp);
          udp_error_ind->src_addr = GET_IP_SOURCE_ADDR (ip_header);
          udp_error_ind->dst_addr = GET_IP_DEST_ADDR (ip_header);
          PSENDX (HL, udp_error_ind);
        }
      }
      else /* No ICMP_PROT */
      {
        {
          ULONG overlay;
          UBYTE pseudo_header [LEN_PSEUDO_HEADER_B];

          /* Build the pseudoheader for the calculation of the checksum */

          SET_UDP_PSEUDO_H_SRC_ADDR (pseudo_header, p_dl->src_addr);
          SET_UDP_PSEUDO_H_DEST_ADDR (pseudo_header, p_dl->dst_addr);
          SET_UDP_PSEUDO_H_ZERO (pseudo_header, 0);
          SET_UDP_PSEUDO_H_PROT (pseudo_header, prot);
          SET_UDP_PSEUDO_H_LEN (pseudo_header, udp_len);

          /* Calculate a part of the checksum for the pseudoheader */
          overlay = partial_checksum (pseudo_header, LEN_PSEUDO_HEADER_B);

          /* Calculate for the UDP header and the data */
          header_chksum = (USHORT) GET_UDP_CHK_SUM (ip_header, start_udp);
          RESET_UDP_CHKSUM (ip_header, start_udp);
          calc_chksum = desc_checksum (desc_list, start_udp, overlay);
          SET_UDP_CHKSUM (ip_header, start_udp, header_chksum);
        }

        /* Packet checksum error ? */
        if (header_chksum NEQ calc_chksum)
        {
          p_dl->drop_packet = TRUE;
        }
        else
        {

#define POS_UDP_DEST_PORT 1


          /* Is it the correct port ? */
          if (p_ker->src_port EQ p_dl->dst_port)
          {
            udp_build_packet (FALSE, B_NORMAL_PACKET);
          }
          else
          {
            /* Build ICMP packet for no dest port.
             * If LL is ready to collect then send */
            udp_build_packet (FALSE, B_NO_DEST_PORT);
            p_ker->send_icmp = TRUE;
          }
        }
      } /* No ICMP_PROT */

      /* Packet is not correct -> drop it and free the primitive */
      if (p_dl->drop_packet)
      {
        p_dl->drop_packet = FALSE;
        PFREE_DESC2 (p_dl->dti_data_ind);
        p_dl->dti_data_ind = NULL;
        send_getdata_req = TRUE;
      }
      else
      {
        /* An ICMP message - send it */
        if (p_ker->send_icmp)
        {
          UBYTE state = GET_STATE (LOLA);
          if (state EQ IDLE OR state EQ WAIT)
          {
            T_DTI2_DATA_REQ * dti_data_req;

            udp_data->ker.send_icmp = FALSE;

            dti_data_req = p_ker->dti_data_req_icmp;
            dti_data_req->parameters.p_id                  = DTI_PID_IP;
            dti_data_req->parameters.st_lines.st_flow      = DTI_FLOW_ON;
            dti_data_req->parameters.st_lines.st_line_sa   = DTI_SA_ON;
            dti_data_req->parameters.st_lines.st_line_sb   = DTI_SB_ON;
            dti_data_req->parameters.st_lines.st_break_len = DTI_BREAK_OFF;

            PACCESS (dti_data_req);
            {
              PPASS (dti_data_req, dti_data_indication, DTI2_DATA_IND);
              dti_send_data (
                udp_hDTI,
                UDP_DTI_DEF_INSTANCE,
                UDP_DTI_LL_INTERFACE,
                UDP_DTI_DEF_CHANNEL,
                dti_data_indication
              );
            }
            SET_STATE (LOLA, IDLE);
            p_ker->dti_data_req_icmp = NULL;
            send_getdata_req = TRUE;
          }
        }
        else
        {
          /* We have got a DTI2_GETDATA_REQ from LL. Send the packet. */

          if (GET_STATE (LOLA) EQ WAIT)
          {
            SET_STATE (LOLA, IDLE);

            p_dl->dti_data_ind->parameters.p_id = DTI_PID_IP;
            p_dl->dti_data_ind->parameters.st_lines.st_flow = DTI_FLOW_ON;
            p_dl->dti_data_ind->parameters.st_lines.st_line_sa = DTI_SA_ON;
            p_dl->dti_data_ind->parameters.st_lines.st_line_sb = DTI_SB_ON;
            p_dl->dti_data_ind->parameters.st_lines.st_break_len =
              DTI_BREAK_OFF;

            dti_send_data (
              udp_hDTI,
              UDP_DTI_DEF_INSTANCE,
              UDP_DTI_HL_INTERFACE,
              UDP_DTI_DEF_CHANNEL,
              p_dl->dti_data_ind
            );
            send_getdata_req = TRUE;
            p_dl->dti_data_ind = NULL;
          }
          else
          {
            SET_STATE (LOLA, SEND);
          }
        }
      }

      if (send_getdata_req) /* Send DTI2_GETDATA_REQ to LL */
      {
        dti_start (
          udp_hDTI,
          UDP_DTI_DEF_INSTANCE,
          UDP_DTI_LL_INTERFACE,
          UDP_DTI_DEF_CHANNEL
        );
      }
    }
    break;

  default:
    PFREE_DESC2 (dti_data_ind);
    break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP         MODULE  : udp_kerp.c                         |
| STATE   : code        ROUTINE : sig_dti_ker_tx_buffer_ready_hl_ind |
+--------------------------------------------------------------------+

  PURPOSE : Process signal SIG_DTI_KER_TX_BUFFER_READY_UP_IND
*/

void sig_dti_ker_tx_buffer_ready_hl_ind ()
{
  TRACE_FUNCTION ("sig_dti_ker_tx_buffer_ready_hl_ind()");

  switch (GET_STATE (KER))
  {
  case CONNECTED:
    {
      T_KER * p_ker = & udp_data->ker;
      T_LOLA * p_dl = & udp_data->lola;

      /* We have bound a port and got a DTI_GETDATA_REQ */

      if (p_ker->port_state EQ PORT_BOUND)
      {
        p_ker->port_state = PORT_ACTIVE;
        dti_start (
          udp_hDTI,
          UDP_DTI_DEF_INSTANCE,
          UDP_DTI_HL_INTERFACE,
          UDP_DTI_DEF_CHANNEL
        );
      }

      /* Send dti_data_ind packet if we have one */

      if (GET_STATE (LOLA) EQ SEND)
      {
        p_dl->dti_data_ind->parameters.p_id                  = DTI_PID_IP;
        p_dl->dti_data_ind->parameters.st_lines.st_flow      = DTI_FLOW_ON;
        p_dl->dti_data_ind->parameters.st_lines.st_line_sa   = DTI_SA_ON;
        p_dl->dti_data_ind->parameters.st_lines.st_line_sb   = DTI_SB_ON;
        p_dl->dti_data_ind->parameters.st_lines.st_break_len = DTI_BREAK_OFF;

        dti_send_data (
          udp_hDTI,
          UDP_DTI_DEF_INSTANCE,
          UDP_DTI_HL_INTERFACE,
          UDP_DTI_DEF_CHANNEL,
          p_dl->dti_data_ind
        );
        p_dl->dti_data_ind = NULL;
        SET_STATE (LOLA, IDLE);

        /* Send DTI2_GETDATA_REQ and indicate ready for new packet */

        dti_start (
          udp_hDTI,
          UDP_DTI_DEF_INSTANCE,
          UDP_DTI_LL_INTERFACE,
          UDP_DTI_DEF_CHANNEL
        );
      }
      else
      {
        /* No data packet to be sent - change state */
        SET_STATE (LOLA, WAIT);
      }
    }
    break;
  default:
    break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP                           MODULE  : udp_kerp.c       |
| STATE   : code                          ROUTINE : ker_udp_bind_cnf |
+--------------------------------------------------------------------+

  PURPOSE : Process primitive T_UDP_BIND_CNF
*/

static void ker_udp_bind_cnf (U16 port, U8 err)
{
  PALLOC (udp_bind_cnf, UDP_BIND_CNF);

  TRACE_FUNCTION ("ker_udp_bind_cnf()");

  udp_bind_cnf->port = port;
  udp_bind_cnf->err = err;
  PSENDX (HL, udp_bind_cnf);
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP                           MODULE  : udp_kerp.c       |
| STATE   : code                          ROUTINE : ker_udp_bind_req |
+--------------------------------------------------------------------+

  PURPOSE : Process primitive T_UDP_BIND_REQ
*/

void ker_udp_bind_req (T_UDP_BIND_REQ * udp_bind_req)
{
  TRACE_FUNCTION ("ker_udp_bind_req()");
  PACCESS (udp_bind_req);

  switch (GET_STATE (KER))
  {
  case ACTIVE_NC:
    ker_udp_bind_cnf (udp_bind_req->port, UDP_BIND_UDPDOWN);
    break;

  case CONNECTED:
    {
      T_KER * p_ker = & udp_data->ker;

      if (p_ker->port_state EQ PORT_DOWN)
      {
        if (udp_bind_req->port EQ NO_PORT)
        {
          p_ker->src_port = 1025;
        }
        else
        {
          p_ker->src_port = udp_bind_req->port;
        }
        p_ker->port_state = PORT_BOUND;
        ker_udp_bind_cnf (p_ker->src_port, UDP_BIND_NOERROR);
      }
      else /* Port in use */
      {
        ker_udp_bind_cnf (udp_bind_req->port, UDP_BIND_PORTINUSE);
      }
    }
    break;

  case DEACTIVATED:
    TRACE_ERROR ("unexpected UDP_BIND_REQ");
    break;

  default:
    break;
  }
  PFREE (udp_bind_req);
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP                      MODULE  : udp_kerp.c            |
| STATE   : code                     ROUTINE : ker_udp_closeport_req |
+--------------------------------------------------------------------+

  PURPOSE : Process primitive T_UDP_CLOSEPORT_REQ
*/

void ker_udp_closeport_req (T_UDP_CLOSEPORT_REQ * udp_closeport_req)
{
  T_KER * p_ker;

  TRACE_FUNCTION ("ker_udp_closeport_req()");
  PACCESS (udp_closeport_req);

  p_ker = & udp_data->ker;

  switch (GET_STATE (KER))
  {
  case ACTIVE_NC:
  case CONNECTED:
    /* Close port */
    p_ker->src_port = NO_PORT;
    p_ker->port_state = PORT_DOWN;
    {
      PALLOC (udp_closeport_cnf, UDP_CLOSEPORT_CNF);
      PSENDX (HL, udp_closeport_cnf);
    }
    break;

  case DEACTIVATED:
    TRACE_ERROR ("unexpected UDP_CLOSEPORT_REQ");
    break;

  default:
    break;
  }
  PFREE (udp_closeport_req);
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP                          MODULE  : udp_kerp.c        |
| STATE   : code                         ROUTINE : ker_udp_error_res |
+--------------------------------------------------------------------+

  PURPOSE : Process primitive T_UDP_ERROR_RES
*/

void ker_udp_error_res (T_UDP_ERROR_RES * udp_error_res)
{
  TRACE_FUNCTION ("ker_udp_error_res()");
  PACCESS (udp_error_res);

  /* Confirm the error message from ACI */

  switch (GET_STATE (KER))
  {
  case CONNECTED:
    {
      T_LOLA * p_dl = & udp_data->lola;

      if (p_dl->state_err EQ STATE_DL_ERROR)
        p_dl->state_err = STATE_DL_NO_ERROR;
      else
        dti_start (
          udp_hDTI,
          UDP_DTI_DEF_INSTANCE,
          UDP_DTI_LL_INTERFACE,
          UDP_DTI_DEF_CHANNEL
        );
    }
    break;
  default:
    break;
  }
  PFREE (udp_error_res);
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP       MODULE  : UDP_KERP                             |
| STATE   : code      ROUTINE : sig_dti_ker_connection_opened_hl_ind |
+--------------------------------------------------------------------+

  PURPOSE : Process signal sig_dti_ker_connection_opened_hl_ind
*/

void sig_dti_ker_connection_opened_hl_ind ()
{
  TRACE_FUNCTION ("sig_dti_ker_connection_opened_hl_ind()");

  if (GET_STATE (HILA) EQ CONNECTING)
  {
    UBYTE state = GET_STATE (LOLA);
    SET_STATE (HILA, IDLE);
    if (state NEQ CONNECTING AND state NEQ DOWN)
    {
      SET_STATE (KER, ACTIVE_NC);
    }
    {
      PALLOC (udpa_dti_cnf, UDPA_DTI_CNF);
      udpa_dti_cnf->link_id = udp_data->hila.link_id;
      udpa_dti_cnf->dti_conn = UDPA_CONNECT_DTI;
      PSENDX (ACI, udpa_dti_cnf);
    }
  }
  else
  {
    TRACE_ERROR ("unexpected dti_connect_ind (from higher layer)");
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP       MODULE  : UDP_KERP                             |
| STATE   : code      ROUTINE : sig_dti_ker_connection_opened_ll_ind |
+--------------------------------------------------------------------+

  PURPOSE : Process signal sig_dti_ker_connection_opened_ll_ind
*/

void sig_dti_ker_connection_opened_ll_ind ()
{
  TRACE_FUNCTION ("sig_dti_ker_connection_opened_ll_ind()");

  if (GET_STATE (LOLA) EQ CONNECTING)
  {
    UBYTE state = GET_STATE (HILA);
    SET_STATE (LOLA, IDLE);
    if (state NEQ CONNECTING AND state NEQ DOWN)
    {
      SET_STATE (KER, ACTIVE_NC);
    }
    {
      PALLOC (udpa_dti_cnf, UDPA_DTI_CNF);
      udpa_dti_cnf->link_id = udp_data->lola.link_id;
      udpa_dti_cnf->dti_conn = UDPA_CONNECT_DTI;
      PSENDX (ACI, udpa_dti_cnf);
    }
  }
  else
  {
    TRACE_ERROR ("unexpected dti_connect_ind (from lower layer)");
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP                       MODULE  : udp_kerp.c           |
| STATE   : code                      ROUTINE : ker_udp_shutdown_ind |
+--------------------------------------------------------------------+

  PURPOSE :
*/

static void ker_udpa_dti_ind (ULONG link_id)
{
  PALLOC (udpa_dti_ind, UDPA_DTI_IND);
  udpa_dti_ind->link_id = link_id;
  PSENDX (ACI, udpa_dti_ind);
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP                       MODULE  : udp_kerp.c           |
| STATE   : code                      ROUTINE : ker_udp_shutdown_ind |
+--------------------------------------------------------------------+

  PURPOSE :
*/

static void ker_udp_shutdown_ind (void)
{
  PALLOC (udp_shutdown_ind, UDP_SHUTDOWN_IND);
  PSENDX (HL, udp_shutdown_ind);
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP                    MODULE  : udp_kerp.c              |
| STATE   : code                   ROUTINE : check_port_shutdown_ind |
+--------------------------------------------------------------------+

  PURPOSE :
*/

static void check_port_shutdown_ind (void)
{
  T_KER * p_ker = & udp_data->ker;

  TRACE_FUNCTION ("check_port_shutdown_ind()");

  if (p_ker->port_state EQ PORT_ACTIVE)
  {
    p_ker->src_port = NO_PORT;
    p_ker->port_state = PORT_DOWN;
    ker_udp_shutdown_ind ();
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP       MODULE  : UDP_KERP                             |
| STATE   : code      ROUTINE : sig_dti_ker_connection_closed_hl_ind |
+--------------------------------------------------------------------+

  PURPOSE : Process signal sig_dti_ker_connection_closed_hl_ind
*/

void sig_dti_ker_connection_closed_hl_ind ()
{
  TRACE_FUNCTION ("sig_dti_ker_connection_closed_hl_ind()");

  switch (GET_STATE (KER))
  {
  case CONNECTED:
    /*XXX bad case, switch to DEACTIVATED, prune buffers... XXX*/
    TRACE_ERROR ("unexpected DTI connection close from higher layer");
    check_port_shutdown_ind ();
    SET_STATE (KER, DEACTIVATED);
    break;
  case ACTIVE_NC:
    SET_STATE (KER, DEACTIVATED);
    break;
  default:
    break;
  }
  vsi_c_close (VSI_CALLER hCommHL);
  hCommHL = VSI_ERROR;

  SET_STATE (HILA, DOWN);
  *udp_data->hila.entity_name = 0;
  ker_udpa_dti_ind (udp_data->hila.link_id);
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP       MODULE  : UDP_KERP                             |
| STATE   : code      ROUTINE : sig_dti_ker_connection_closed_ll_ind |
+--------------------------------------------------------------------+

  PURPOSE : Process signal sig_dti_ker_connection_closed_ll_ind
*/

void sig_dti_ker_connection_closed_ll_ind ()
{
  TRACE_FUNCTION ("sig_dti_ker_connection_closed_ll_ind()");

  switch (GET_STATE (KER))
  {
  case CONNECTED:
    /*XXX bad case, switch to DEACTIVATED, prune buffers... XXX*/
    TRACE_ERROR ("unexpected DTI connection close from lower layer");
    check_port_shutdown_ind ();
    SET_STATE (KER, DEACTIVATED);
    break;
  case ACTIVE_NC:
    SET_STATE (KER, DEACTIVATED);
    break;
  default:
    break;
  }
  SET_STATE (LOLA, DOWN);
  *udp_data->lola.entity_name = 0;
  ker_udpa_dti_ind (udp_data->lola.link_id);
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP                        MODULE  : udp_kerp.c          |
| STATE   : code                       ROUTINE : ker_udpa_config_req |
+--------------------------------------------------------------------+

  PURPOSE : Process primitive T_UDPA_CONFIG_REQ
*/

void ker_udpa_config_req (T_UDPA_CONFIG_REQ * udpa_config_req)
{
  TRACE_FUNCTION ("ker_udpa_config_req()");
  PACCESS (udpa_config_req);

  /* Configuration of lower layer -> change to state CONNECTED */

  switch (GET_STATE (KER))
  {
  case CONNECTED:
    switch (udpa_config_req->cmd)
    {
    case UDPA_CONFIG_DOWN:
      check_port_shutdown_ind ();
      SET_STATE (KER, ACTIVE_NC);
      {
        PALLOC (udpa_config_cnf, UDPA_CONFIG_CNF);
        PSENDX (ACI, udpa_config_cnf);
      }
     break;
    default:
      break;
    }
    break;

  case ACTIVE_NC:
    switch (udpa_config_req->cmd)
    {
    case UDPA_CONFIG_UP:
      dti_start (
        udp_hDTI,
        UDP_DTI_DEF_INSTANCE,
        UDP_DTI_LL_INTERFACE,
        UDP_DTI_DEF_CHANNEL
      );
      SET_STATE (KER, CONNECTED);
      TRACE_EVENT ("KER -> CONNECTED");
      {
        PALLOC (udpa_config_cnf, UDPA_CONFIG_CNF);
        PSENDX (ACI, udpa_config_cnf);
      }
      break;
    case UDPA_CONFIG_DOWN:
      {
        PALLOC (udpa_config_cnf, UDPA_CONFIG_CNF);
        PSENDX (ACI, udpa_config_cnf);
      }
      break;
    default:
      break;
    }
    break;
  default:
    break;
  }
  PFREE (udpa_config_req);
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP                       MODULE  : udp_kerp.c           |
| STATE   : code                      ROUTINE : ker_udp_shutdown_res |
+--------------------------------------------------------------------+

  PURPOSE : Process primitive T_UDP_SHUTDOWN_RES
*/

void ker_udp_shutdown_res (T_UDP_SHUTDOWN_RES * udp_shutdown_res)
{
  TRACE_FUNCTION ("DUMMY ker_udp_shutdown_res()");
  PACCESS (udp_shutdown_res);
  PFREE (udp_shutdown_res);
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP          MODULE  : udp_kerp.c                        |
| STATE   : code         ROUTINE : sig_dti_ker_tx_buffer_full_hl_ind |
+--------------------------------------------------------------------+

  PURPOSE : Process signal SIG_DTI_KER_TX_BUFFER_FULL_UP_IND
*/

void sig_dti_ker_tx_buffer_full_hl_ind ()
{
  TRACE_FUNCTION ("DUMMY sig_dti_ker_tx_buffer_full_hl_ind()");
}

/*
+--------------------------------------------------------------------+
| PROJECT : WAP          MODULE  : UDP_KERP                          |
| STATE   : code         ROUTINE : sig_dti_ker_tx_buffer_full_ll_ind |
+--------------------------------------------------------------------+

  PURPOSE : Process signal SIG_DTI_KER_TX_BUFFER_FULL_DN_IND
*/

void sig_dti_ker_tx_buffer_full_ll_ind ()
{
  TRACE_FUNCTION ("DUMMY sig_dti_ker_tx_buffer_full_ll_ind()");
}

/*-------------------------------------------------------------------------*/