diff src/g23m-fad/ip/ip_kerp.c @ 174:90eb61ecd093

src/g23m-fad: initial import from TCS3.2/LoCosto
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 12 Oct 2016 05:40:46 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/g23m-fad/ip/ip_kerp.c	Wed Oct 12 05:40:46 2016 +0000
@@ -0,0 +1,1237 @@
+/*
++----------------------------------------------------------------------------
+|  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_IP
+
+/*==== INCLUDES ===================================================*/
+
+#include <string.h>
+#include "typedefs.h"
+#include "pconst.cdg"
+#include "vsi.h"
+#include "macdef.h" /* Get PFREE_DESC2 */
+#include "pconst.cdg"
+#include "custom.h"
+#include "gsm.h"
+#include "cnf_ip.h"
+#include "mon_ip.h"
+#include "prim.h"
+#include "pei.h"
+#include "tok.h"
+#include "ccdapi.h"
+
+#include "dti.h" /* To get DTI lib */
+#include "ip.h"
+#include "ip_udp.h"
+
+/*==== CONST =======================================================*/
+
+/*==== TYPES =======================================================*/
+
+/*==== VAR EXPORT ==================================================*/
+
+/*==== VAR LOCAL ===================================================*/
+
+/*==== MACROS ======================================================*/
+
+/*==== Prototypes ==================================================*/
+
+/*==== FUNCTIONS ===================================================*/
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : WAP       MODULE  : IP_KERP                              |
+| STATE   : code      ROUTINE : ker_ipa_dti_req                      |
++--------------------------------------------------------------------+
+
+  PURPOSE : Process IPA_DTI_REQ primitive
+*/
+void ker_ipa_dti_req (T_IPA_DTI_REQ * ipa_dti_req)
+{
+  T_KER * p_ker = & ip_data->ker;
+  BOOL confirm = TRUE;
+  UBYTE dti_conn = IPA_DISCONNECT_DTI;
+
+  PACCESS (ipa_dti_req);
+  TRACE_FUNCTION ("ker_ipa_dti_req()");
+
+  switch (GET_STATE (KER)) {
+  case DEACTIVATED:
+    switch (ipa_dti_req->dti_conn) {
+    case IPA_CONNECT_DTI:
+      switch (ipa_dti_req->dti_direction) {
+      case IPA_DTI_TO_HIGHER_LAYER:
+        if (p_ker->entity_name_hl[0] EQ 0)
+        {
+          hCommHL = vsi_c_open (
+            VSI_CALLER (char *) ipa_dti_req->entity_name
+          );
+          if (hCommHL > VSI_OK)
+          {
+            p_ker->link_id_hl = ipa_dti_req->link_id;
+            strcpy (
+              p_ker->entity_name_hl,
+              (char *) ipa_dti_req->entity_name
+            );
+            SET_STATE (HILA, CONNECTING);
+            if (dti_open (
+              ip_hDTI,
+              IP_DTI_DEF_INSTANCE,
+              IP_DTI_HL_INTERFACE,
+              IP_DTI_DEF_CHANNEL,
+              IP_DTI_UPLINK_QUEUE_SIZE,
+              DTI_CHANNEL_TO_HIGHER_LAYER,
+              FLOW_CNTRL_ENABLED,
+              DTI_VERSION_10,
+              (U8 *) ipa_dti_req->entity_name,
+              ipa_dti_req->link_id
+            ) == 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 IPA_DTI_TO_LOWER_LAYER:
+        if (p_ker->entity_name_ll[0] EQ 0)
+        {
+          p_ker->link_id_ll = ipa_dti_req->link_id;
+          strcpy (
+            p_ker->entity_name_ll,
+            (char *) ipa_dti_req->entity_name
+          );
+          SET_STATE (LOLA, CONNECTING);
+          if (dti_open (
+            ip_hDTI,
+            IP_DTI_DEF_INSTANCE,
+            IP_DTI_LL_INTERFACE,
+            IP_DTI_DEF_CHANNEL,
+            IP_DTI_DOWNLINK_QUEUE_SIZE,
+            DTI_CHANNEL_TO_LOWER_LAYER,
+            FLOW_CNTRL_ENABLED,
+            DTI_VERSION_10,
+            (U8 *) ipa_dti_req->entity_name,
+            ipa_dti_req->link_id
+          ) == TRUE)
+          {
+            confirm = FALSE;
+          }
+        }
+        else
+        {
+          TRACE_ERROR ("DTI link to lower layer already requested");
+        }
+        break;
+      default:
+        TRACE_ERROR ("illegal parameter (ipa_dti_req->dti_direction)");
+      } /* End "switch (ipa_dti_req->dti_direction)" */
+      dti_conn = IPA_DISCONNECT_DTI;
+      break;
+    case IPA_DISCONNECT_DTI:
+      if (p_ker->link_id_hl == ipa_dti_req->link_id)
+      {
+        dti_close (
+          ip_hDTI,
+          IP_DTI_DEF_INSTANCE,
+          IP_DTI_HL_INTERFACE,
+          IP_DTI_DEF_CHANNEL,
+          FALSE
+        );
+        p_ker->link_id_hl = IPA_LINK_ID_DEFAULT;
+        p_ker->entity_name_hl[0] = '\0';
+        vsi_c_close (VSI_CALLER hCommHL);
+        hCommHL = VSI_ERROR;
+        SET_STATE (HILA, DOWN);
+        dti_conn = IPA_DISCONNECT_DTI;
+        /*XXX check for remaining UP/DOWN-LINK DTI connections, XXX*/
+        /*XXX terminate_ip() if nothing left open               XXX*/
+      }
+      else if (p_ker->link_id_ll == ipa_dti_req->link_id)
+      {
+        dti_close (
+          ip_hDTI,
+          IP_DTI_DEF_INSTANCE,
+          IP_DTI_LL_INTERFACE,
+          IP_DTI_DEF_CHANNEL,
+          FALSE
+        );
+        p_ker->link_id_ll = IPA_LINK_ID_DEFAULT;
+        p_ker->entity_name_ll[0] = '\0';
+        SET_STATE (LOLA, DOWN);
+        dti_conn = IPA_DISCONNECT_DTI;
+        /*XXX check for remaining UP/DOWN-LINK DTI connections, XXX*/
+        /*XXX terminate_ip() if nothing left open               XXX*/
+      }
+      else
+      {
+        TRACE_ERROR ("illegal parameter (ipa_dti_req->dti_conn)");
+        dti_conn = IPA_CONNECT_DTI;
+      }
+      break;
+    } /* End "switch (ipa_dti_req->dti_conn)" */
+    break;
+  case ACTIVE_NC:
+    switch (ipa_dti_req->dti_conn) {
+    case IPA_DISCONNECT_DTI:
+      if (p_ker->link_id_hl == ipa_dti_req->link_id)
+      {
+        dti_close (
+          ip_hDTI,
+          IP_DTI_DEF_INSTANCE,
+          IP_DTI_HL_INTERFACE,
+          IP_DTI_DEF_CHANNEL,
+          FALSE
+        );
+        p_ker->link_id_hl = IPA_LINK_ID_DEFAULT;
+        p_ker->entity_name_hl[0] = '\0';
+        vsi_c_close (VSI_CALLER hCommHL);
+        hCommHL = VSI_ERROR;
+        SET_STATE (HILA, DOWN);
+        dti_conn = IPA_DISCONNECT_DTI;
+        SET_STATE (KER, DEACTIVATED);
+      }
+      else if (p_ker->link_id_ll == ipa_dti_req->link_id)
+      {
+        dti_close (
+          ip_hDTI,
+          IP_DTI_DEF_INSTANCE,
+          IP_DTI_LL_INTERFACE,
+          IP_DTI_DEF_CHANNEL,
+          FALSE
+        );
+        p_ker->link_id_ll = IPA_LINK_ID_DEFAULT;
+        p_ker->entity_name_ll[0] = '\0';
+        SET_STATE (LOLA, DOWN);
+        dti_conn = IPA_DISCONNECT_DTI;
+        SET_STATE (KER, DEACTIVATED);
+      }
+      break;
+    default:
+      TRACE_ERROR ("unexpected parameter (ipa_dti_req->dti_conn)");
+      dti_conn = IPA_DISCONNECT_DTI;
+      break;
+    } /* End "switch (ipa_dti_req->dti_conn)" */
+    break;
+  case CONNECTED:
+  default:
+    TRACE_ERROR ("unexpected IPA_DTI_REQ");
+    if (ipa_dti_req->dti_conn == IPA_CONNECT_DTI)
+      dti_conn = IPA_DISCONNECT_DTI;
+    else
+      dti_conn = IPA_CONNECT_DTI;
+    break;
+  } /* End "switch (GET_STATE (KER))" */
+
+  if (confirm)
+  {
+    PALLOC (ipa_dti_cnf, IPA_DTI_CNF);
+    ipa_dti_cnf->dti_conn = dti_conn;
+    ipa_dti_cnf->link_id = ipa_dti_req->link_id;
+    PSENDX (MMI, ipa_dti_cnf);
+  }
+  PFREE (ipa_dti_req);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : WAP       MODULE  : IP_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 ()
+{
+  T_KER * p_ker = & ip_data->ker;
+
+  TRACE_FUNCTION ("sig_dti_ker_connection_opened_hl_ind()");
+
+  if (GET_STATE (HILA) EQ CONNECTING)
+  {
+    SET_STATE (HILA, IDLE);
+    switch (GET_STATE (LOLA)) {
+    case IDLE:
+    case SEND:
+    case WAIT:
+      SET_STATE (KER, ACTIVE_NC);
+      dti_start (
+        ip_hDTI,
+        IP_DTI_DEF_INSTANCE,
+        IP_DTI_LL_INTERFACE,
+        IP_DTI_DEF_CHANNEL
+      );
+      break;
+    default:
+      break;
+    }
+    {
+      PALLOC (ipa_dti_cnf, IPA_DTI_CNF);
+      ipa_dti_cnf->link_id = p_ker->link_id_hl;
+      ipa_dti_cnf->dti_conn = IPA_CONNECT_DTI;
+      PSENDX (MMI, ipa_dti_cnf);
+    }
+  } else {
+    TRACE_ERROR ("unexpected dti_connect_ind (from higher layer)");
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : WAP       MODULE  : IP_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 ()
+{
+  T_KER * p_ker = & ip_data->ker;
+
+  TRACE_FUNCTION ("sig_dti_ker_connection_opened_ll_ind()");
+
+  if (GET_STATE (LOLA) EQ CONNECTING)
+  {
+    SET_STATE (LOLA, IDLE);
+    switch (GET_STATE (HILA)) {
+    case IDLE:
+    case SEND:
+    case WAIT:
+      SET_STATE (KER, ACTIVE_NC);
+      dti_start (
+        ip_hDTI,
+        IP_DTI_DEF_INSTANCE,
+        IP_DTI_HL_INTERFACE,
+        IP_DTI_DEF_CHANNEL
+      );
+      break;
+    default:
+      break;
+    }
+    {
+      PALLOC (ipa_dti_cnf, IPA_DTI_CNF);
+      ipa_dti_cnf->link_id = p_ker->link_id_ll;
+      ipa_dti_cnf->dti_conn = IPA_CONNECT_DTI;
+      PSENDX (MMI, ipa_dti_cnf);
+    }
+  } else {
+    TRACE_ERROR ("unexpected dti_connect_ind (from lower layer)");
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : WAP       MODULE  : IP_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 ()
+{
+  T_KER * p_ker = & ip_data->ker;
+
+  TRACE_FUNCTION ("sig_dti_ker_connection_closed_hl_ind()");
+
+  SET_STATE (HILA, DOWN);
+
+  switch (GET_STATE (KER)) {
+  case CONNECTED:
+    /*XXX bad case, switch to DEACTIVATED, prune buffers ... XXX*/
+    TRACE_ERROR ("unexpected DTI connection close by peer (UPLINK)");
+    SET_STATE (KER, DEACTIVATED);
+    break;
+  case ACTIVE_NC:
+    SET_STATE (KER, DEACTIVATED);
+    break;
+  default:
+    break;
+  } /* End "switch (GET_STATE (KER))" */
+
+  {
+    PALLOC (ipa_dti_ind, IPA_DTI_IND);
+    ipa_dti_ind->link_id = p_ker->link_id_hl;
+    p_ker->link_id_hl = IPA_LINK_ID_DEFAULT;
+    vsi_c_close (VSI_CALLER hCommHL);
+    hCommHL = VSI_ERROR;
+    p_ker->entity_name_hl[0] = '\0';
+    PSENDX (MMI, ipa_dti_ind);
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : WAP       MODULE  : IP_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 ()
+{
+  T_KER * p_ker = & ip_data->ker;
+
+  TRACE_FUNCTION ("sig_dti_ker_connection_closed_ll_ind()");
+
+  /* Caution!!! this return is absolut necessary for WAP over GPRS. Otherwise IP will
+  close itself after SNDCP went down. Unfortunately not everything is deinitialized and
+  IP will never come up on subsequent activation requests (eg. p_ker->entity_name_ll[0]
+  is not wiped). Since the Dti-Manager of ACI closes each DTI-Connection itself, we can
+  suspend this automatism for now */
+  /* return; out-commented at the moment: jk */
+
+  /* If this automatism is re-enabled at least the following lines are necessary
+  and were missing in previous versions!!! But at least we should not store an indication
+  of an connected peer inside the p_ker->entity_name_ll ... */
+
+  /* p_ker->link_id_ll = IPA_LINK_ID_DEFAULT; out-commented at the moment: jk */
+  /* p_ker->entity_name_ll[0] = '\0'; out-commented at the moment: jk */
+  /* SET_STATE (LOLA, DOWN); out-commented at the moment: jk */
+
+  switch (GET_STATE (KER)) {
+  case CONNECTED:
+    /*XXX bad case, switch to DEACTIVATED, prune buffers ... XXX*/
+    TRACE_ERROR ("unexpected DTI connection close by peer (DOWNLINK)");
+    SET_STATE (KER, DEACTIVATED);
+    break;
+  case ACTIVE_NC:
+    SET_STATE (KER, DEACTIVATED);
+    break;
+  default:
+    break;
+  } /* End "switch (GET_STATE (KER))" */
+
+  {
+    PALLOC (ipa_dti_ind, IPA_DTI_IND);
+
+    ipa_dti_ind->link_id = p_ker->link_id_ll; /* Initialize the only one parameter of the prim */
+    p_ker->link_id_ll = IPA_LINK_ID_DEFAULT; /* Set the state of the entity properly */
+    p_ker->entity_name_ll[0] = '\0';
+    SET_STATE (LOLA, DOWN);
+    SET_STATE (KER, DEACTIVATED);
+
+    PSENDX (MMI, ipa_dti_ind); /* Send indication to the MMI */
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : WAP       MODULE  : IP_KERP                              |
+| STATE   : code      ROUTINE : sig_dti_ker_tx_buffer_full_ll_ind    |
++--------------------------------------------------------------------+
+
+  PURPOSE : Process signal SIG_DTI_KER_TX_BUFFER_FULL_LL_IND
+*/
+void sig_dti_ker_tx_buffer_full_ll_ind ()
+{
+  TRACE_FUNCTION ("sig_dti_ker_tx_buffer_full_ll_ind()");
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : WAP          MODULE  : IP_KERP
+| STATE   : code         ROUTINE : sig_dti_ker_tx_buffer_full_hl_ind |
++--------------------------------------------------------------------+
+
+  PURPOSE : Process signal SIG_DTI_KER_TX_BUFFER_FULL_HL_IND
+*/
+void sig_dti_ker_tx_buffer_full_hl_ind ()
+{
+  TRACE_FUNCTION ("sig_dti_ker_tx_buffer_full_hl_ind()");
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : WAP                       MODULE  : IP_KERP              |
+| STATE   : code                      ROUTINE : ker_ipa_config_req   |
++--------------------------------------------------------------------+
+
+  PURPOSE : Process primitive IPA_CONFIG_REQ received from ACI
+*/
+void ker_ipa_config_req (T_IPA_CONFIG_REQ * ipa_config_req)
+{
+  T_KER * p_ker = & ip_data->ker;
+  PALLOC (ipa_config_cnf, IPA_CONFIG_CNF);
+
+  TRACE_FUNCTION ("ker_ipa_config_req()");
+
+  PACCESS (ipa_config_req);
+
+  switch (GET_STATE (KER)) {
+  case DEACTIVATED:
+    ipa_config_cnf->ack_flag = IPA_CONFIG_NAK;
+    ipa_config_cnf->all_down = IPA_ALLDOWN_TRUE;
+    break;
+  case ACTIVE_NC:
+    switch (ipa_config_req->cmd) {
+    case IPA_CONFIG_UP:
+      p_ker->source_addr= ipa_config_req->ip;
+      p_ker->peer_addr = ipa_config_req->peer_ip;
+      p_ker->mtu = ipa_config_req->mtu;
+      SET_STATE (KER, CONNECTED);
+      dti_start (
+        ip_hDTI,
+        IP_DTI_DEF_INSTANCE,
+        IP_DTI_LL_INTERFACE,
+        IP_DTI_DEF_CHANNEL
+      );
+      ipa_config_cnf->ack_flag = IPA_CONFIG_ACK;
+      ipa_config_cnf->all_down = IPA_ALLDOWN_FALSE;
+      break;
+    case IPA_CONFIG_DOWN:
+      ipa_config_cnf->ack_flag = IPA_CONFIG_NAK;
+      ipa_config_cnf->all_down = IPA_ALLDOWN_TRUE;
+      break;
+    }
+    break;
+  case CONNECTED:
+    switch (ipa_config_req->cmd) {
+    case IPA_CONFIG_UP:
+      ipa_config_cnf->ack_flag = IPA_CONFIG_NAK;
+      ipa_config_cnf->all_down = IPA_ALLDOWN_FALSE;
+      break;
+    case IPA_CONFIG_DOWN:
+      /*XXX prune buffers + config data XXX*/
+      SET_STATE (KER, ACTIVE_NC);
+      ipa_config_cnf->ack_flag = IPA_CONFIG_ACK;
+      ipa_config_cnf->all_down = IPA_ALLDOWN_TRUE;
+      config_down_ll ();
+      break;
+    }
+    break;
+  } /* End "switch (GET_STATE (KER))" */
+
+  PSENDX (MMI, ipa_config_cnf);
+  PFREE (ipa_config_req);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : WAP                       MODULE  : IP_KERP              |
+| STATE   : code                      ROUTINE : ker_ip_addr_req      |
++--------------------------------------------------------------------+
+
+  PURPOSE : Process primitive IP_ADDR_REQ received from higher layer
+*/
+void ker_ip_addr_req (T_IP_ADDR_REQ * ip_addr_req)
+{
+  T_KER * p_ker = & ip_data->ker;
+
+  TRACE_FUNCTION ("ker_ip_addr_req()");
+
+  PACCESS (ip_addr_req);
+
+  switch (GET_STATE (KER)) {
+  case DEACTIVATED:
+    if (GET_STATE (HILA) NEQ DOWN)
+    {
+      PALLOC (ip_addr_cnf, IP_ADDR_CNF);
+      ip_addr_cnf->src_addr = p_ker->source_addr;
+      ip_addr_cnf->err = IP_ADDR_NOROUTE;
+      ip_addr_cnf->trans_prot = ip_addr_req->trans_prot;
+      PSENDX (HL, ip_addr_cnf);
+    }
+    else
+    {
+      TRACE_ERROR ("IP_ADDR_REQ received but no higher layer known");
+    }
+    break;
+  case ACTIVE_NC:
+    {
+      PALLOC (ip_addr_cnf, IP_ADDR_CNF);
+      ip_addr_cnf->src_addr = p_ker->source_addr;
+      ip_addr_cnf->err = IP_ADDR_NOROUTE;
+      ip_addr_cnf->trans_prot = ip_addr_req->trans_prot;
+      PSENDX (HL, ip_addr_cnf);
+    }
+    break;
+  case CONNECTED:
+    {
+      PALLOC (ip_addr_cnf, IP_ADDR_CNF);
+      ip_addr_cnf->src_addr = p_ker->source_addr;
+      ip_addr_cnf->err = IP_ADDR_NOERROR;
+      ip_addr_cnf->trans_prot = ip_addr_req->trans_prot;
+      PSENDX (HL, ip_addr_cnf);
+    }
+    break;
+  } /* End "switch (GET_STATE (KER))" */
+
+  PFREE (ip_addr_req);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : WAP           MODULE  : ip_kerp.c                        |
+| STATE   : code          ROUTINE : sig_dti_ker_data_received_hl_ind |
++--------------------------------------------------------------------+
+
+    UDP
+     |
+     V
+    IP
+
+  PURPOSE : Process signal SIG_DTI_KER_DATA_RECEIVED_HL_IND
+*/
+void sig_dti_ker_data_received_hl_ind (T_DTI2_DATA_REQ * dti_data_req)
+{
+  T_HILA * p_hl = & ip_data->hila;
+  T_KER * p_ker = & ip_data->ker;
+  BOOL dest_addresses[MAX_ADDR_TYPES];
+  BOOL src_addresses[MAX_ADDR_TYPES];
+  BOOL send_ready = FALSE;
+
+  TRACE_FUNCTION ("sig_dti_ker_data_received_hl_ind()");
+
+  if (dti_data_req == NULL)
+    return;
+
+  PACCESS (dti_data_req);
+
+  switch (GET_STATE (KER)) {
+  case DEACTIVATED:
+  case ACTIVE_NC: /* Fall through */
+    PFREE_DESC2 (dti_data_req);
+    break;
+  case CONNECTED:
+    if (ip_packet_validator (& dti_data_req->desc_list2))
+    {
+      T_desc_list2 * desc_list;
+      T_desc2 * desc;
+      UBYTE * ip_header, to_do;
+      USHORT packet_len;
+
+      p_hl->dti_data_req = dti_data_req;
+      desc_list = & p_hl->dti_data_req->desc_list2;
+      desc = (T_desc2 *) desc_list->first;
+      ip_header = desc->buffer;
+      to_do = B_NORMAL_PACKET;
+
+      dti_stop (
+        ip_hDTI,
+        IP_DTI_DEF_INSTANCE,
+        IP_DTI_HL_INTERFACE,
+        IP_DTI_DEF_CHANNEL
+      );
+
+      /* Check destination and source address */
+      {
+        ULONG dest_addr = GET_IP_DEST_ADDR (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
+        check_ip_address (
+          dest_addresses,
+          src_addresses,
+          dest_addr,
+          p_ker->source_addr
+        );
+        if (src_addresses[BAD_UL_SRC_ADDR] OR dest_addresses[BAD_UL_DEST_ADDR])
+          p_hl->drop_packet = TRUE;
+      }
+
+      /* Check if ICMP message from higher layer and build the ICMP packet */
+      if ((GET_IP_PROT (ip_header) EQ ICMP_PROT) AND (! p_hl->drop_packet))/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
+        build_ip_packet (TRUE, B_ICMP_PACKET);
+
+      /* Check if fragmenting necessary - build the fragment */
+      packet_len = p_hl->dti_data_req->desc_list2.list_len;
+
+      if ((packet_len > p_ker->mtu) AND (! p_hl->drop_packet))
+      {
+        to_do = B_SEGMENT;
+        build_ip_packet (TRUE, to_do);
+      }
+
+      /* Build "normal" IP packet */
+      if ((to_do EQ B_NORMAL_PACKET) AND (! p_hl->drop_packet))
+        build_ip_packet (TRUE, to_do);
+
+      /* Check if ICMP message is to be send */
+      if ((p_ker->send_icmp) AND (GET_STATE (HILA) EQ WAIT))
+      {
+        T_DTI2_DATA_REQ * data_req = p_ker->icmp_dti_data_req;
+        data_req->parameters.p_id = DTI_PID_IP;
+        data_req->parameters.st_lines.st_flow = DTI_FLOW_ON;
+        data_req->parameters.st_lines.st_line_sa = DTI_SA_ON;
+        data_req->parameters.st_lines.st_line_sb = DTI_SB_ON;
+        data_req->parameters.st_lines.st_break_len = DTI_BREAK_OFF;
+
+        {
+          PPASS (data_req, dti_data_ind, DTI2_DATA_IND);
+          dti_send_data (
+            ip_hDTI,
+            IP_DTI_DEF_INSTANCE,
+            IP_DTI_HL_INTERFACE,
+            IP_DTI_DEF_CHANNEL,
+            dti_data_ind
+          );
+        }
+        SET_STATE (HILA, IDLE);
+        dti_start (
+          ip_hDTI,
+          IP_DTI_DEF_INSTANCE,
+          IP_DTI_HL_INTERFACE,
+          IP_DTI_DEF_CHANNEL
+        );
+      }
+
+      /* Bad packet - drop */
+      if (p_hl->drop_packet)
+      {
+        p_hl->drop_packet = FALSE;
+        PFREE_DESC2 (p_hl->dti_data_req);
+        send_ready = TRUE;
+      }
+      else
+      {
+        if (GET_STATE (HILA) EQ WAIT)
+        {
+          /* Send dti2_data_req */
+          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 (
+              ip_hDTI,
+              IP_DTI_DEF_INSTANCE,
+              IP_DTI_LL_INTERFACE,
+              IP_DTI_DEF_CHANNEL,
+              dti_data_ind
+            );
+          }
+          p_hl->dti_data_req = NULL;
+          if (p_hl->state_segment EQ NO_SEGMENTS)
+          {
+            SET_STATE (HILA, IDLE);
+            send_ready = TRUE;
+          }
+          else
+          {
+            /* When the ready_ind is received, we don't know whether
+             * the first segment has been sent or not (state is sent
+             * in any case), so we don't know whether we have to transmit
+             * the first or to build the next one. To avoid the problem
+             * we build the next packet here. */
+            build_ip_packet (TRUE, B_SEGMENT);
+            SET_STATE (HILA, SEND);
+            send_ready = FALSE;
+          }
+        }
+        else
+        {
+          SET_STATE (HILA, SEND);
+        }
+      }
+      /* Send ready indication to higher layer */
+      if (send_ready)
+      {
+        dti_start (
+          ip_hDTI,
+          IP_DTI_DEF_INSTANCE,
+          IP_DTI_HL_INTERFACE,
+          IP_DTI_DEF_CHANNEL
+        );
+      }
+    }
+    else
+    {
+      PFREE_DESC2 (dti_data_req);
+    }
+    break;
+  } /* End "switch (GET_STATE (KER))" */
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : WAP           MODULE  : ip_kerp.c                        |
+| STATE   : code          ROUTINE : sig_dti_ker_data_received_ll_ind |
++--------------------------------------------------------------------+
+
+    IP
+     ^
+     |
+    PPP
+
+  PURPOSE : Process signal SIG_DTI_KER_DATA_RECEIVED_LL_IND
+*/
+void sig_dti_ker_data_received_ll_ind (T_DTI2_DATA_IND * dti_data_ind)
+{
+  T_LOLA * p_ll = & ip_data->lola;
+  T_KER * p_ker = & ip_data->ker;
+
+  TRACE_FUNCTION ("sig_dti_ker_data_received_ll_ind()");
+
+  if (dti_data_ind == NULL)
+    return;
+
+  PACCESS (dti_data_ind);
+
+  switch (GET_STATE (KER)) {
+  case DEACTIVATED:
+  case ACTIVE_NC: /* Fall through */
+    PFREE_DESC2 (dti_data_ind);
+    break;
+  case CONNECTED:
+    if (ip_packet_validator (& dti_data_ind->desc_list2))
+    {
+      BOOL send_getdata_req;
+      T_desc_list2 * desc_list;
+      T_desc2 * desc;
+      UBYTE * ip_header, to_do, ip_prot;
+      USHORT header_len_b;
+      USHORT header_chksum, chksum;
+      ULONG source_addr, dest_addr;
+      BOOL dest_addresses[MAX_ADDR_TYPES];
+      BOOL src_addresses[MAX_ADDR_TYPES];
+
+      send_getdata_req = FALSE;
+      p_ll->dti_data_ind = dti_data_ind;
+      desc_list = & p_ll->dti_data_ind->desc_list2;
+      desc = (T_desc2 *) desc_list->first;
+      ip_header = desc->buffer;
+      to_do = BUILD_NO_PACKET;
+      header_len_b = (USHORT) GET_IP_HEADER_LEN_B (ip_header);
+      source_addr = p_ker->source_addr;
+      ip_prot = GET_IP_PROT (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
+
+      /* Check IP protocol */
+      if (GET_IP_VERSION (ip_header) NEQ IP_VERSION)
+        p_ll->drop_packet = TRUE;
+      else
+      {
+        UBYTE chk_len_ind;
+        USHORT desc_len;
+
+        /* Check the datagram length */
+        chk_len_ind = chk_packet_len (ip_header, desc_list);
+
+        if (chk_len_ind NEQ NO_ERROR)
+        {
+          /* Datagram > length indicated in header - truncate */
+          if (chk_len_ind EQ CHANGE_PACKET_LEN)
+          {
+            desc_len = (USHORT) GET_IP_TOTAL_LEN (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
+            truncate_descs (desc_list, desc_len);
+          }
+          else
+            p_ll->drop_packet = TRUE;
+        }
+      }
+
+      /* Checksum */
+      if (! p_ll->drop_packet)
+      {
+        desc = (T_desc2 *) desc_list->first;
+        header_chksum = (USHORT) GET_IP_CHECKSUM (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
+        RESET_IP_CHECKSUM (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
+        chksum = inet_checksum (ip_header, header_len_b);
+        SET_IP_CHECKSUM (ip_header, chksum);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
+        if (header_chksum NEQ chksum)
+        {
+          p_ll->drop_packet = TRUE;
+          TRACE_EVENT ("header checksum error indicated") ;
+        }
+      }
+
+      /* Check destination address and source address */
+      if (! p_ll->drop_packet)
+      {
+        dest_addr = GET_IP_DEST_ADDR (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
+        check_ip_address (
+          dest_addresses,
+          src_addresses,
+          dest_addr,
+          source_addr
+        );
+        if (src_addresses[BAD_DL_SRC_ADDR] OR dest_addresses[BAD_DL_DEST_ADDR])
+          p_ll->drop_packet = TRUE;
+
+        if (dest_addresses[NO_DEST_ADDR])
+        {
+          /* Send ICMP message if the IP address is ok and
+           * we have not got more than one segment. */
+          if (
+            (ip_prot EQ ICMP_PROT) OR
+            (p_ll->state_reassembly[p_ll->pos_server] EQ READ_SEGMENT) OR
+            dest_addresses[LINK_LAYER_BCAST] OR
+            dest_addresses[BCAST_ADDR_255] OR
+            src_addresses[BCAST_ADDR_255] OR
+            src_addresses[MCAST_ADDR] OR
+            src_addresses[NETW_ADDR] OR
+            src_addresses[LOOP_BACK_ADDR] OR
+            src_addresses[CLASS_E_ADDR]
+          )
+            p_ll->drop_packet = TRUE;
+          else
+          {
+            to_do = B_ICMP_NO_FORWARD;
+            p_ker->send_icmp = TRUE;
+          }
+        }
+      }
+
+      /* Check fragmenting */
+      if ((! p_ll->drop_packet) AND (to_do NEQ B_ICMP_NO_FORWARD))
+      {
+        BOOL df_flag, mf_flag;
+        USHORT fragm_offset;
+        BOOL first_segment, middle_segment, last_segment;
+
+        df_flag = GET_IP_DF_FLAG (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
+        mf_flag = GET_IP_MF_FLAG (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
+
+        fragm_offset = (USHORT) GET_IP_FRAG_OFFSET (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
+        first_segment =
+          (df_flag EQ FLAG_NOT_SET) AND
+          (mf_flag EQ FLAG_SET) AND
+          (fragm_offset EQ 0);
+        middle_segment =
+          (df_flag EQ FLAG_NOT_SET) AND
+          (mf_flag EQ FLAG_SET) AND
+          (fragm_offset > 0);
+        last_segment =
+          (df_flag EQ FLAG_NOT_SET) AND
+          (mf_flag EQ FLAG_NOT_SET) AND
+          (fragm_offset > 0);
+
+        if (first_segment OR middle_segment OR last_segment)
+
+          /* Filter out ICMP fragments - not supported */
+          if (ip_prot EQ ICMP_PROT)
+            p_ll->drop_packet = TRUE;
+          else
+            /* Start reassemble fragments */
+            reassemble_fragments (
+              & p_ll->dti_data_ind,
+              p_ll,
+              ip_header,
+              first_segment,
+              /* middle_segment, */
+              last_segment /*,*/
+              /* fragm_offset */
+            );
+      }
+
+      /* Incoming ICMP message */
+      if (! p_ll->drop_packet)
+        if (ip_prot EQ ICMP_PROT)
+          if (GET_ICMP_TYPE (ip_header, header_len_b) EQ ICMP_TYP_ECHO)
+          {
+            to_do = B_ICMP_ECHO_REPLY;
+            p_ker->send_icmp = TRUE;
+          }
+
+      /* Build selected packets */
+      if ((! p_ll->drop_packet) AND (to_do NEQ BUILD_NO_PACKET))
+        build_ip_packet (FALSE, to_do);
+
+      /* Skip by reading fragments - only send dti_getdata_req */
+      if (p_ll->state_reassembly[p_ll->pos_server] EQ READ_SEGMENT)
+        send_getdata_req = TRUE;
+
+      /* Drop packet and free resources */
+      else if (p_ll->drop_packet)
+      {
+        p_ll->drop_packet = FALSE;
+        PFREE_DESC2 (p_ll->dti_data_ind);
+        p_ll->dti_data_ind = NULL;
+        send_getdata_req = TRUE;
+      }
+      else
+      {
+        /* Send an ICMP message first */
+        if (p_ker->send_icmp EQ TRUE)
+        {
+          if (GET_STATE (HILA) EQ WAIT)
+          {
+            T_DTI2_DATA_REQ * data_req;
+            p_ker->send_icmp = FALSE;
+
+            data_req = p_ker->icmp_dti_data_req;
+            data_req->parameters.p_id = DTI_PID_IP;
+            data_req->parameters.st_lines.st_flow = DTI_FLOW_ON;
+            data_req->parameters.st_lines.st_line_sa = DTI_SA_ON;
+            data_req->parameters.st_lines.st_line_sb = DTI_SB_ON;
+            data_req->parameters.st_lines.st_break_len = DTI_BREAK_OFF;
+
+            PACCESS (data_req);
+            {
+              PPASS (data_req, dti_data_indication, DTI2_DATA_IND);
+              dti_send_data (
+                ip_hDTI,
+                IP_DTI_DEF_INSTANCE,
+                IP_DTI_LL_INTERFACE,
+                IP_DTI_DEF_CHANNEL,
+                dti_data_indication
+              );
+              SET_STATE (HILA, IDLE);
+              p_ker->send_icmp = FALSE;
+              p_ker->icmp_dti_data_req = NULL;
+              send_getdata_req = TRUE; /*XXX not clear to me XXX*/
+            }
+          }
+        }
+        else
+        {
+          /* Check we are not in the middle of a reassembly process */
+          if (p_ll->state_reassembly[p_ll->pos_server] EQ NO_SEGMENTS)
+          {
+            if (GET_STATE (LOLA) EQ WAIT)
+            {
+              T_DTI2_DATA_IND * data_ind;
+
+              SET_STATE (LOLA, IDLE);
+
+              data_ind = p_ll->dti_data_ind;
+              data_ind->parameters.p_id = DTI_PID_IP;
+              data_ind->parameters.st_lines.st_flow = DTI_FLOW_ON;
+              data_ind->parameters.st_lines.st_line_sa = DTI_SA_ON;
+              data_ind->parameters.st_lines.st_line_sb = DTI_SB_ON;
+              data_ind->parameters.st_lines.st_break_len = DTI_BREAK_OFF;
+              dti_send_data (
+                ip_hDTI,
+                IP_DTI_DEF_INSTANCE,
+                IP_DTI_HL_INTERFACE,
+                IP_DTI_DEF_CHANNEL,
+                data_ind
+              );
+              p_ll->dti_data_ind = NULL;
+
+              send_getdata_req = TRUE;
+            }
+            else
+            {
+              SET_STATE (LOLA, SEND);
+            }
+          }
+        }
+      }
+
+      if (send_getdata_req)
+      {
+        dti_start (
+          ip_hDTI,
+          IP_DTI_DEF_INSTANCE,
+          IP_DTI_LL_INTERFACE,
+          IP_DTI_DEF_CHANNEL
+        );
+      }
+    }
+    else
+    {
+      PFREE_DESC2 (dti_data_ind);
+    }
+    break;
+  } /* End "switch (GET_STATE (KER))" */
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : WAP         MODULE  : ip_kerp.c                          |
+| STATE   : code        ROUTINE : sig_dti_ker_tx_buffer_ready_ll_ind |
++--------------------------------------------------------------------+
+
+  "DTI2_READY_IND received"
+  PURPOSE : Process signal SIG_DTI_KER_TX_BUFFER_READY_LL_IND
+*/
+void sig_dti_ker_tx_buffer_ready_ll_ind ()
+{
+  T_HILA * p_hl = & ip_data->hila;
+  T_KER * p_ker = & ip_data->ker;
+  BOOL send_ready = FALSE;
+
+  TRACE_FUNCTION ("sig_dti_ker_tx_buffer_ready_ll_ind()");
+
+  switch (GET_STATE (KER)) {
+  case DEACTIVATED:
+  case ACTIVE_NC: /* Fall through */
+  SET_STATE (HILA, WAIT);
+    break;
+  case CONNECTED:
+    {
+      /* Check if ICMP message */
+      if (p_ker->send_icmp)
+      {
+        T_DTI2_DATA_REQ * dti_data_req;
+        p_ker->send_icmp = FALSE;
+        dti_data_req = p_ker->icmp_dti_data_req;
+        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 (
+            ip_hDTI,
+            IP_DTI_DEF_INSTANCE,
+            IP_DTI_LL_INTERFACE,
+            IP_DTI_DEF_CHANNEL,
+            dti_data_ind
+          );
+        }
+        dti_start (
+          ip_hDTI,
+          IP_DTI_DEF_INSTANCE,
+          IP_DTI_HL_INTERFACE,
+          IP_DTI_DEF_CHANNEL
+        );
+        p_ker->send_icmp = FALSE;
+        p_ker->icmp_dti_data_req = NULL;
+      }
+      else if (GET_STATE (HILA) EQ SEND)
+      {
+        /* Send waiting data packet */
+        p_hl->dti_data_req->parameters.p_id = DTI_PID_IP;
+        p_hl->dti_data_req->parameters.st_lines.st_flow = DTI_FLOW_ON;
+        p_hl->dti_data_req->parameters.st_lines.st_line_sa = DTI_SA_ON;
+        p_hl->dti_data_req->parameters.st_lines.st_line_sb = DTI_SB_ON;
+        p_hl->dti_data_req->parameters.st_lines.st_break_len = DTI_BREAK_OFF;
+
+        PACCESS (p_hl->dti_data_req);
+        {
+          PPASS (p_hl->dti_data_req, dti_data_ind, DTI2_DATA_IND);
+          dti_send_data (
+            ip_hDTI,
+            IP_DTI_DEF_INSTANCE,
+            IP_DTI_LL_INTERFACE,
+            IP_DTI_DEF_CHANNEL,
+            dti_data_ind
+          );
+        }
+        p_hl->dti_data_req = NULL;
+        dti_start (
+          ip_hDTI,
+          IP_DTI_DEF_INSTANCE,
+          IP_DTI_LL_INTERFACE,
+          IP_DTI_DEF_CHANNEL
+        );
+        p_hl->dti_data_req = NULL;
+
+        /* Check if fragmenting - stay in the same state */
+        if (p_hl->state_segment EQ NO_SEGMENTS)
+        {
+          SET_STATE (HILA, IDLE);
+          send_ready = TRUE;
+        }
+        else
+        {
+          /* Fragmentation -> build next packet */
+          build_ip_packet (TRUE, B_SEGMENT);
+          if (p_hl->drop_packet)
+          {
+            p_hl->drop_packet = FALSE;
+            PFREE_DESC2 (p_hl->dti_data_req);
+            SET_STATE (HILA, IDLE);
+            send_ready = TRUE;
+          }
+        }
+        if (send_ready)
+          dti_start (
+            ip_hDTI,
+            IP_DTI_DEF_INSTANCE,
+            IP_DTI_HL_INTERFACE,
+            IP_DTI_DEF_CHANNEL
+          );
+      }
+      else
+      {
+        SET_STATE (HILA, WAIT);
+      }
+    }
+    break;
+  } /* End "switch (GET_STATE (KER))" */
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : WAP         MODULE  : ip_kerp.c                          |
+| STATE   : code        ROUTINE : sig_dti_ker_tx_buffer_ready_hl_ind |
++--------------------------------------------------------------------+
+
+  "DTI2_GETDATA_REQ received"
+  PURPOSE : Process signal SIG_DTI_KER_TX_BUFFER_READY_HL_IND
+*/
+void sig_dti_ker_tx_buffer_ready_hl_ind ()
+{
+  T_LOLA * p_ll = & ip_data->lola;
+
+  TRACE_FUNCTION ("sig_dti_ker_tx_buffer_ready_hl_ind()");
+
+  switch (GET_STATE (KER)) {
+  case DEACTIVATED:
+  case ACTIVE_NC: /* Fall through */
+    /*XXX ???? XXX*/
+    break;
+  case CONNECTED:
+    {
+      /* state_send - primitive can be sended */
+      if (GET_STATE (LOLA) EQ SEND)
+      {
+        SET_STATE (LOLA, IDLE);
+        p_ll->dti_data_ind->parameters.p_id = DTI_PID_IP;
+        p_ll->dti_data_ind->parameters.st_lines.st_flow = DTI_FLOW_ON;
+        p_ll->dti_data_ind->parameters.st_lines.st_line_sa = DTI_SA_ON;
+        p_ll->dti_data_ind->parameters.st_lines.st_line_sb = DTI_SB_ON;
+        p_ll->dti_data_ind->parameters.st_lines.st_break_len = DTI_BREAK_OFF;
+
+        dti_send_data (
+          ip_hDTI,
+          IP_DTI_DEF_INSTANCE,
+          IP_DTI_HL_INTERFACE,
+          IP_DTI_DEF_CHANNEL,
+          p_ll->dti_data_ind
+        );
+        p_ll->dti_data_ind = NULL;
+
+        /* Send DTI2_GETDATA_REQ and indicate ready for new packet */
+        dti_start (
+          ip_hDTI,
+          IP_DTI_DEF_INSTANCE,
+          IP_DTI_LL_INTERFACE,
+          IP_DTI_DEF_CHANNEL
+        );
+        SET_STATE (LOLA, IDLE);
+      }
+      else
+      {
+        SET_STATE (LOLA, WAIT);
+      }
+    }
+    break;
+  } /* End "switch (GET_STATE (KER))" */
+}
+
+/*-------------------------------------------------------------------------*/
+