diff src/g23m-gprs/sndcp/sndcp_nuf.c @ 183:219afcfc6250

src/g23m-gprs: initial import from TCS3.2/LoCosto
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 13 Oct 2016 04:24:13 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/g23m-gprs/sndcp/sndcp_nuf.c	Thu Oct 13 04:24:13 2016 +0000
@@ -0,0 +1,778 @@
+/*
++-----------------------------------------------------------------------------
+|  Project :  GPRS (8441)
+|  Modul   :  sndcp_nuf.c
++-----------------------------------------------------------------------------
+|  Copyright 2002 Texas Instruments Berlin, AG
+|                 All rights reserved.
+|
+|                 This file is confidential and a trade secret of Texas
+|                 Instruments Berlin, AG
+|                 The receipt of or possession of this file does not convey
+|                 any rights to reproduce or disclose its contents or to
+|                 manufacture, use, or sell anything it may describe, in
+|                 whole, or in part, without the specific written consent of
+|                 Texas Instruments Berlin, AG.
++-----------------------------------------------------------------------------
+|  Purpose :  This modul is part of the entity SNDCP and implements all
+|             procedures and functions as described in the
+|             SDL-documentation (NU-statemachine)
++-----------------------------------------------------------------------------
+*/
+
+/*---- HISTORY --------------------------------------------------------------*/
+#define ENTITY_SNDCP
+
+/*==== INCLUDES =============================================================*/
+
+#include "typedefs.h"    /* to get Condat data types */
+#include "vsi.h"        /* to get a lot of macros */
+#include "macdef.h"
+#include "gsm.h"        /* to get a lot of macros */
+#include "prim.h"       /* to get the definitions of used SAP and directions */
+
+#include "dti.h"
+
+#include "sndcp.h"        /* to get the global entity definitions */
+#include "sndcp_f.h"       /* to get the functions to access the global arrays*/
+
+#ifndef NCONFIG
+#include "sndcp_nuf.h"
+#include "sndcp_suas.h"
+#include "sndcp_sus.h"
+#endif
+
+/*==== CONST ================================================================*/
+
+/*==== LOCAL VARS ===========================================================*/
+
+/*==== PRIVATE FUNCTIONS ====================================================*/
+
+LOCAL void nu_delete (T_NPDU_BUFFER* npdu_buffer);
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : nu_delete
++------------------------------------------------------------------------------
+| Description : The function nu_delete() deletes one buffered N-PDU.
+|               It is used to delete one N-PDU in form of an SN_DATA_REQ
+|               pointer.
+|               It will be useful when one N-PDU is deleted in case of
+|               LL_DATA_CNF orwhen every N-PDU for one NSAPI is deleted in case
+|               of SIG_MG_DELETE_NPDUS.
+|               First every descriptor in the SN_DATA_REQ is deleted, then the
+|               primitive is deleted, then the T_NPDU_BUFFER* is deleted. (This
+|               type is only specified in the code.)
+| Parameter   : the one N-PDU to be deleted.
+|
++------------------------------------------------------------------------------
+*/
+LOCAL void nu_delete (T_NPDU_BUFFER* npdu_buffer)
+{
+
+  TRACE_FUNCTION( "nu_delete" );
+
+  if (npdu_buffer == NULL) {
+    return;
+  }
+  /*
+   * Free the SN_DATA_REQ.
+   */
+#ifdef _SNDCP_DTI_2_
+  if (npdu_buffer->sn_data_req != NULL) {
+    MFREE_PRIM(npdu_buffer->sn_data_req);
+    npdu_buffer->sn_data_req = NULL;
+  }
+#else /*_SNDCP_DTI_2_*/
+  if (npdu_buffer->sn_data_req != NULL) {
+    PFREE_DESC(npdu_buffer->sn_data_req);
+    npdu_buffer->sn_data_req = NULL;
+  }
+#endif /*_SNDCP_DTI_2_*/
+  /*
+   * If this was the next to send in recovery state, move to next now.
+   */
+  if (npdu_buffer == sndcp_data->nu->next_resend) {
+    sndcp_data->nu->next_resend = npdu_buffer->next;
+  }
+  if (npdu_buffer == sndcp_data->nu->first_buffered_npdu) {
+    sndcp_data->nu->first_buffered_npdu = npdu_buffer->next;
+  }
+  /*
+   * Free the T_NPDU_BUFFER
+   */
+  MFREE(npdu_buffer);
+  npdu_buffer = NULL;
+} /* nu_delete() */
+
+
+/*==== PUBLIC FUNCTIONS =====================================================*/
+
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : nu_buffer_npdu
++------------------------------------------------------------------------------
+| Description : The function nu_buffer_npdu() buffers the given SN_DATA_REQ
+|               together with the given N-PDU number.
+|
+| Parameters  : N-PDU number, SN_DATA_REQ primitive.
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void nu_buffer_npdu (UBYTE npdu_number, T_SN_DATA_REQ* sn_data_req)
+{
+  T_NPDU_BUFFER* npdu_buffer = 0;
+
+  TRACE_FUNCTION( "nu_buffer_npdu" );
+
+  /*
+   * Allocate the T_NPDU_BUFFER struct for
+   */
+  MALLOC(npdu_buffer, sizeof(T_NPDU_BUFFER));
+  /*
+   * Insert the given values.
+   */
+  npdu_buffer->npdu_number = npdu_number;
+  npdu_buffer->sn_data_req = sn_data_req;
+  npdu_buffer->next = NULL;
+  if (sndcp_data->nu->first_buffered_npdu == NULL) {
+    sndcp_data->nu->first_buffered_npdu = npdu_buffer;
+    sndcp_data->nu->next_resend = npdu_buffer;
+  } else {
+    T_NPDU_BUFFER* help = sndcp_data->nu->first_buffered_npdu;
+
+    if (help->next == NULL) {
+      help->next = npdu_buffer;
+    } else {
+      while (help->next != NULL) {
+        help = help->next;
+      }
+      help->next = npdu_buffer;
+    }
+
+  }
+
+
+} /* nu_buffer_npdu() */
+
+#ifndef NCONFIG
+
+/*
++------------------------------------------------------------------------------
+| Function    : nu_config_discard
++------------------------------------------------------------------------------
+| Description : reaction to config prim
+|
+| Parameters  : nsapi
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void nu_config_discard (UBYTE nsapi)
+{
+  TRACE_FUNCTION( "nu_config_discard" );
+
+  sndcp_data->nu = &sndcp_data->nu_base[nsapi];
+  sndcp_data->nu->discard = TRUE;
+}
+
+/*
++------------------------------------------------------------------------------
+| Function    : nu_config_resume
++------------------------------------------------------------------------------
+| Description : reaction to config prim
+|
+| Parameters  : nsapi
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void nu_config_resume (UBYTE nsapi)
+{
+  TRACE_FUNCTION( "nu_config_resume" );
+
+  sndcp_data->nu = &sndcp_data->nu_base[nsapi];
+  sndcp_data->nu->discard = FALSE;
+}
+
+/*
++------------------------------------------------------------------------------
+| Function    : nu_config_send
++------------------------------------------------------------------------------
+| Description : reaction to config prim
+|
+| Parameters  : nsapi, number of octets
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void nu_config_send (UBYTE nsapi, U32 octets)
+{
+  U32 *data_count = NULL;
+
+  TRACE_FUNCTION( "nu_config_send" );
+
+  sndcp_data->nu = &sndcp_data->nu_base[nsapi];
+  
+  data_count = &sndcp_data->data_count[nsapi];
+
+  if (*data_count == 0) {
+    *data_count = octets;
+  } else {
+    *data_count += octets;
+    return;
+  }
+
+  switch( GET_STATE( NU ) )
+  {
+    case NU_ACK_SUA_RECEPTIVE:
+    case NU_SEND_ACK_SUA_RECEPTIVE:
+      SET_STATE(NU, NU_SEND_ACK_SUA_NOT_RECEPTIVE);
+      nu_config_send_next(nsapi);
+      sndcp_data->nu->sn_ready_ind_pending = FALSE;
+      break;
+    case NU_ACK_SUA_NOT_RECEPTIVE:
+      SET_STATE(NU, NU_SEND_ACK_SUA_NOT_RECEPTIVE);
+      break;
+    case NU_SEND_ACK_SUA_NOT_RECEPTIVE:
+      SET_STATE(NU, NU_SEND_ACK_SUA_NOT_RECEPTIVE);
+      *data_count += octets;
+      sndcp_data->nu->sn_ready_ind_pending = FALSE;
+      break;
+    case NU_UNACK_SU_NOT_RECEPTIVE:
+      SET_STATE(NU, NU_SEND_UNACK_SU_NOT_RECEPTIVE);
+      break;
+    case NU_SEND_UNACK_SU_NOT_RECEPTIVE:
+      SET_STATE(NU, NU_SEND_UNACK_SU_NOT_RECEPTIVE);
+      *data_count += octets;
+      sndcp_data->nu->sn_unitready_ind_pending = FALSE;
+      break;
+    case NU_UNACK_SU_RECEPTIVE:
+    case NU_SEND_UNACK_SU_RECEPTIVE:
+      SET_STATE(NU, NU_SEND_UNACK_SU_NOT_RECEPTIVE);
+      nu_config_send_next(nsapi);
+      sndcp_data->nu->sn_unitready_ind_pending = FALSE;
+      break;
+    case NU_REC_SUA_NOT_RECEPTIVE:
+      SET_STATE(NU, NU_SEND_REC_SUA_NOT_RECEPTIVE);
+      break;
+    case NU_SEND_REC_SUA_NOT_RECEPTIVE:
+      break;
+    case NU_SUS_SUA_NOT_RECEPTIVE:
+      SET_STATE(NU, NU_SEND_SUS_SUA_NOT_RECEPTIVE);
+      break;
+    case NU_SEND_SUS_SUA_NOT_RECEPTIVE:
+      break;
+    case NU_SUS_SUA_RECEPTIVE:
+      SET_STATE(NU, NU_SEND_SUS_SUA_RECEPTIVE);
+      break;
+    case NU_SEND_SUS_SUA_RECEPTIVE:
+      break;
+
+    default:
+      TRACE_ERROR( "config prim SEND unexpected" );
+      break;
+  }
+
+
+} /* nu_config_send() */
+
+/*
++------------------------------------------------------------------------------
+| Function    : nu_config_send_next
++------------------------------------------------------------------------------
+| Description : sends data with 'data_count' octets. State is not changed.
+|
+| Parameters  : nsapi
+| Pre         : data_count > 0
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void nu_config_send_next (UBYTE nsapi)
+{
+  BOOL ack = FALSE;
+  /*
+   * Index and number in pattern.
+   */
+  USHORT i = 0;
+  USHORT r = 0;
+  UBYTE sapi = 0;
+  USHORT k    = 0;
+  UBYTE sapi_index = 0;
+  USHORT send_size = 0;
+  U16 ip_size = 0;
+  U32 length;
+  U32* data_count = NULL;
+#ifdef _SNDCP_DTI_2_
+  T_desc2* desc = NULL,*help;
+#else /*_SNDCP_DTI_2_*/
+  T_desc* desc = NULL;
+#endif /*_SNDCP_DTI_2_*/
+
+  T_SN_DATA_REQ* sn_data_req = NULL;
+  T_SN_UNITDATA_REQ* sn_unitdata_req = NULL;
+
+  data_count = &sndcp_data->data_count[nsapi];
+  length = *data_count;
+
+  TRACE_FUNCTION( "nu_config_send_next" );
+
+  if (length == 0) {
+    sndcp_get_nsapi_ack(nsapi, &ack);
+    if (ack) {
+      SET_STATE(NU, NU_SEND_ACK_SUA_RECEPTIVE);
+    } else {
+      SET_STATE(NU, NU_SEND_UNACK_SU_RECEPTIVE);
+    }
+    return;
+  }
+
+  sndcp_get_nsapi_sapi(sndcp_data->nu->nsapi, &sapi);
+  sndcp_get_sapi_index(sapi, &sapi_index);
+
+  sndcp_data->nu = &sndcp_data->nu_base[nsapi];
+  sndcp_get_nsapi_ack(nsapi, &ack);
+
+  if (ack) {
+    send_size =
+      sndcp_data->sua_base[sapi_index].n201_i - SN_DATA_PDP_HDR_LEN_BIG;
+    TRACE_EVENT_P1("send_size: %d", send_size);
+  } else {
+    send_size =
+      sndcp_data->su_base[sapi_index].n201_u - SN_UNITDATA_PDP_HDR_LEN_BIG;
+    TRACE_EVENT_P1("send_size: %d", send_size);
+  }
+
+  /*
+   * The amount of data to be segmented
+   * shall be a multiple of N201_I or N201_U respectively
+   */
+  if(ack)
+  {
+    ip_size = 2 * sndcp_data->sua_base[sapi_index].n201_i + 100;
+    if (length > ip_size)
+    {
+      if ( sndcp_data->sua_base[sapi_index].n201_i < ip_size)
+      {
+        k = (ip_size - (ip_size % 
+             sndcp_data->sua_base[sapi_index].n201_i))/
+             sndcp_data->sua_base[sapi_index].n201_i;
+        length = k * (sndcp_data->sua_base[sapi_index].n201_i)
+                 -(k-1)- SN_DATA_PDP_HDR_LEN_BIG;
+      }
+      else
+      {
+        length = sndcp_data->sua_base[sapi_index].n201_i - 
+                 SN_DATA_PDP_HDR_LEN_BIG;
+      }
+    }
+  }
+  else
+  {
+    ip_size = 2 * sndcp_data->su_base[sapi_index].n201_u + 100;
+    if (length > ip_size)
+    {
+      if ( sndcp_data->su_base[sapi_index].n201_u < ip_size)
+      {
+        k = (ip_size - (ip_size % 
+             sndcp_data->su_base[sapi_index].n201_u))/
+             sndcp_data->su_base[sapi_index].n201_u;
+        length = k * (sndcp_data->su_base[sapi_index].n201_u) 
+                 - (k * (SN_UNITDATA_PDP_HDR_LEN_BIG -1) +1);
+      }
+      else
+      {
+        length = sndcp_data->su_base[sapi_index].n201_u - 
+                 SN_UNITDATA_PDP_HDR_LEN_BIG;
+      }
+    }
+  }
+
+  TRACE_EVENT_P2("data to segment: %d, data to send: %d", 
+                  length, *data_count);
+
+  *data_count -= length;
+
+  /*
+   * Allocates small segments
+   */
+  k = (U16)(length / 100); /* Number of 'full' 100 byte descriptors*/
+  r = (U16)(length % 100); /* Number of rest bytes */
+
+  if(r > 0){
+#ifdef _SNDCP_DTI_2_
+    MALLOC (desc, (USHORT)(sizeof(T_desc2) - 1 + r));
+#else /*_SNDCP_DTI_2_*/
+    MALLOC (desc, (USHORT)(sizeof(T_desc) - 1 + r));
+#endif /*_SNDCP_DTI_2_*/
+
+  desc->next  = (ULONG)NULL;
+  desc->len   = r;
+
+#ifdef _SNDCP_DTI_2_
+  desc->offset = 0;
+  desc->size = r;
+#endif
+  }
+
+  for ( i=0; i < k; i++){
+    /*
+     * Allocate memory for descriptor
+     */
+    MALLOC (help, (USHORT)(sizeof(T_desc2) - 1 + 100));
+
+
+
+
+    /*
+     * Fill descriptor control information.
+     */
+    help->next  = (ULONG)desc;
+    help->len   = 100;
+    help->offset = 0;
+    help->size = help->len;
+
+    desc = help;
+  } /* for k */
+
+
+
+  if (ack) {
+#ifdef _SNDCP_DTI_2_    
+    MALLOC(sn_data_req, sizeof(T_SN_DATA_REQ));
+    sn_data_req->desc_list2.first = (ULONG) desc;
+    sn_data_req->desc_list2.list_len = (U16)length;
+#else /*_SNDCP_DTI_2_*/
+    PALLOC_DESC (sn_data_req, SN_DATA_REQ);
+    sn_data_req->desc_list.first = (ULONG) desc;
+    sn_data_req->desc_list.list_len = (U16)length;
+#endif /*_SNDCP_DTI_2_*/
+
+
+    sn_data_req->nsapi = nsapi;
+#ifdef SNDCP_UPM_INCLUDED 
+    sn_data_req->p_id = DTI_PID_IP;
+#else
+    sn_data_req->p_id = PPP_PID_IP;
+#endif /*SNDCP_UPM_INCLUDED*/
+    /*
+     * Buffer the given N-PDU
+     */
+    nu_buffer_npdu(sndcp_data->nu->send_npdu_number_ack, sn_data_req);
+
+    sndcp_data->nu->send_npdu_number_ack =
+      (U8)((sndcp_data->nu->send_npdu_number_ack + 1) % MAX_NPDU_NUMBER_ACK);
+    sig_nu_sua_data_req(sn_data_req,
+                       (U8)((sndcp_data->nu->send_npdu_number_ack - 1
+                       + MAX_NPDU_NUMBER_ACK) % MAX_NPDU_NUMBER_ACK),
+                       sn_data_req->nsapi,
+                       sapi);
+
+
+  } else {
+#ifdef _SNDCP_DTI_2_
+    MALLOC(sn_unitdata_req, sizeof(T_SN_UNITDATA_REQ));
+    sn_unitdata_req->desc_list2.first = (ULONG) desc;
+    sn_unitdata_req->desc_list2.list_len = (U16)length;
+#else /*_SNDCP_DTI_2_*/
+    PALLOC_DESC (sn_unitdata_req, SN_UNITDATA_REQ);
+    sn_unitdata_req->desc_list.first = (ULONG) desc;
+    sn_unitdata_req->desc_list.list_len = (U16)length;
+#endif /*_SNDCP_DTI_2_*/
+    sn_unitdata_req->nsapi = nsapi;
+#ifdef SNDCP_UPM_INCLUDED 
+    sn_unitdata_req->p_id = DTI_PID_IP;
+#else
+    sn_unitdata_req->p_id = PPP_PID_IP;
+#endif /*SNDCP_UPM_INCLUDED*/
+
+    sndcp_data->nu->send_npdu_number_unack =
+      (sndcp_data->nu->send_npdu_number_unack + 1) % MAX_NPDU_NUMBER_UNACK;
+    sig_nu_su_unitdata_req(sn_unitdata_req,
+                           (U16)((sndcp_data->nu->send_npdu_number_unack - 1
+                           + MAX_NPDU_NUMBER_UNACK) % MAX_NPDU_NUMBER_UNACK),
+                           sndcp_data->nu->nsapi,
+                           sapi);
+
+  }
+
+} /* nu_config_send_next() */
+
+#endif
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : nu_delete_npdu
++------------------------------------------------------------------------------
+| Description : The function nu_delete_npdu() searches and deletes one
+|               buffered N-PDU.
+| Parameter   : nsapi, npdu_number.
+| Pre         : correct nu instance must be active, NPDU must exist.
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void nu_delete_npdu (UBYTE nsapi, UBYTE npdu_number)
+{
+  T_NPDU_BUFFER* npdu_buffer = NULL;
+  T_NPDU_BUFFER* pre = NULL;
+  BOOL found = FALSE;
+
+  TRACE_FUNCTION( "nu_delete_npdu" );
+
+  /*
+   * Find the npdu.
+   */
+  npdu_buffer = sndcp_data->nu->first_buffered_npdu;
+  while (!found && npdu_buffer != NULL) {
+    if (sndcp_data->nu->nsapi == nsapi &&
+        npdu_buffer->npdu_number == npdu_number)
+    {
+      found = TRUE;
+      if (pre != NULL) {
+        pre->next = npdu_buffer->next;
+      }
+    } else {
+      pre = npdu_buffer;
+      npdu_buffer = npdu_buffer->next;
+    }
+  }
+  /*
+   * Delete it.
+   */
+  if (npdu_buffer != NULL) {
+    nu_delete(npdu_buffer);
+  }
+} /* nu_delete_npdu() */
+
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : nu_delete_npdus
++------------------------------------------------------------------------------
+| Description : The function nu_delete_npdus() deletes all buffered N-PDUs.
+|
+| Pre         : The correct nu instance has to be "active".
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void nu_delete_npdus (void)
+{
+  T_NPDU_BUFFER* help = NULL;
+
+  TRACE_FUNCTION( "nu_delete_npdus" );
+
+  while (sndcp_data->nu->first_buffered_npdu != NULL) {
+    help = sndcp_data->nu->first_buffered_npdu->next;
+    /*
+     * Delete the first one.
+     */
+    nu_delete(sndcp_data->nu->first_buffered_npdu);
+    /*
+     * Go to the next.
+     */
+    sndcp_data->nu->first_buffered_npdu = help;
+  }
+  sndcp_data->nu->next_resend = NULL;
+
+} /* nu_delete_npdus() */
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : nu_init
++------------------------------------------------------------------------------
+| Description : The function nu_init() ....
+|
+| Parameters  :
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void nu_init (void)
+{
+
+  UBYTE nsapi = 0;
+
+  TRACE_FUNCTION( "nu_init" );
+
+  sndcp_data->nu = & sndcp_data->nu_base[0];
+  INIT_STATE(NU_0, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[1];
+  INIT_STATE(NU_1, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[2];
+  INIT_STATE(NU_2, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[3];
+  INIT_STATE(NU_3, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[4];
+  INIT_STATE(NU_4, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[5];
+  INIT_STATE(NU_5, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[6];
+  INIT_STATE(NU_6, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[7];
+  INIT_STATE(NU_7, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[8];
+  INIT_STATE(NU_8, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[9];
+  INIT_STATE(NU_9, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[10];
+  INIT_STATE(NU_10, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[11];
+  INIT_STATE(NU_11, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[12];
+  INIT_STATE(NU_12, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[13];
+  INIT_STATE(NU_13, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[14];
+  INIT_STATE(NU_14, NU_UNACK_SU_RECEPTIVE);
+
+  sndcp_data->nu = & sndcp_data->nu_base[15];
+  INIT_STATE(NU_15, NU_UNACK_SU_RECEPTIVE);
+
+  for (nsapi = 0; nsapi < SNDCP_NUMBER_OF_NSAPIS; nsapi++) {
+    sndcp_data->nu = & sndcp_data->nu_base[nsapi];
+
+    sndcp_data->nu->nsapi = nsapi;
+    sndcp_data->nu->send_npdu_number_unack = 0;
+    sndcp_data->nu->send_npdu_number_ack = 0;
+    sndcp_data->nu->rec_npdu_number_ack = 0;
+    sndcp_data->nu->first_buffered_npdu = NULL;
+    sndcp_data->nu->next_resend = NULL;
+    sndcp_data->nu->sn_ready_ind_pending = FALSE;
+    sndcp_data->nu->sn_unitready_ind_pending = FALSE;
+    sndcp_data->nu->connection_is_opened = FALSE;
+    sndcp_data->nu->discard = FALSE;
+    sndcp_data->nu->discarded_data = 0;
+    sndcp_data->nu->sent_data = 0;
+  }
+} /* nu_init() */
+
+
+/*
++------------------------------------------------------------------------------
+| Function    : nu_ready_ind_if_nec
++------------------------------------------------------------------------------
+| Description : Sends an SN_READY_IND if none is pending and DTI connection is
+|               opened.
+|
+| Parameters  : nsapi
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void nu_ready_ind_if_nec (UBYTE nsapi)
+{
+  BOOL used = FALSE;
+  USHORT stat = MG_IDLE;
+  UBYTE sapi = 0;
+
+  TRACE_FUNCTION( "nu_ready_ind_if_nec" );
+#ifdef SNDCP_TRACE_ALL
+  if (sndcp_data->nu->sn_ready_ind_pending) {
+    TRACE_EVENT("sn_ready_ind_pending TRUE");
+  } else {
+    TRACE_EVENT("sn_ready_ind_pending FALSE");
+  }
+  if (sndcp_data->nu->connection_is_opened) {
+    TRACE_EVENT("connection_is_opened TRUE");
+  } else {
+    TRACE_EVENT("connection_is_opened FALSE");
+  }
+#endif /* SNDCP_TRACE_ALL */
+
+  /*
+   * set service instance according to nsapi parameter
+   */
+  sndcp_data->nu = & sndcp_data->nu_base[nsapi];
+
+  sndcp_get_nsapi_sapi(nsapi, &sapi);
+  sndcp_get_sapi_state(sapi, &stat);
+  sndcp_is_nsapi_used(nsapi, &used);
+
+  if (! sndcp_data->nu->sn_ready_ind_pending
+      &&
+      sndcp_data->nu->connection_is_opened
+      &&
+      used
+     ) {
+
+    sndcp_data->nu->sn_ready_ind_pending = TRUE;
+
+#ifdef SNDCP_UPM_INCLUDED    
+    dti_start(sndcp_data->hDTI, 0, SNDCP_INTERFACE_UNACK, nsapi);
+#else
+    dti_start(sndcp_data->hDTI, 0, SNDCP_INTERFACE_ACK, nsapi);
+#endif
+  }
+
+} /* nu_ready_ind_if_nec() */
+
+/*
++------------------------------------------------------------------------------
+| Function    : nu_unitready_ind_if_nec
++------------------------------------------------------------------------------
+| Description : Sends an SN_UNITREADY_IND if none is pending and DTI connection
+|               is opened.
+|
+| Parameters  : nsapi
+| Pre         : The correct nu instance has to be "active".
+|
++------------------------------------------------------------------------------
+*/
+GLOBAL void nu_unitready_ind_if_nec (UBYTE nsapi)
+{
+  BOOL used = FALSE;
+  USHORT stat = MG_IDLE;
+  UBYTE sapi = 0;
+
+  TRACE_FUNCTION( "nu_unitready_ind_if_nec" );
+#ifdef SNDCP_TRACE_ALL
+  if (sndcp_data->nu->sn_unitready_ind_pending) {
+    TRACE_EVENT("sn_unitready_ind_pending TRUE");
+  } else {
+    TRACE_EVENT("sn_unitready_ind_pending FALSE");
+  }
+  if (sndcp_data->nu->connection_is_opened) {
+    TRACE_EVENT("connection_is_opened TRUE");
+  } else {
+    TRACE_EVENT("connection_is_opened FALSE");
+  }
+#endif
+
+  sndcp_get_nsapi_sapi(nsapi, &sapi);
+  sndcp_get_sapi_state(sapi, &stat);
+  sndcp_is_nsapi_used(nsapi, &used);
+
+  if (! sndcp_data->nu->sn_unitready_ind_pending
+      &&
+      sndcp_data->nu->connection_is_opened
+      &&
+      used
+     ) {
+#ifdef SNDCP_TRACE_ALL
+      TRACE_EVENT("trying to palloc/send SN_UNITREADY_IND");
+#endif
+
+
+    sndcp_data->nu->sn_unitready_ind_pending = TRUE;
+
+    dti_start(sndcp_data->hDTI, 0, SNDCP_INTERFACE_UNACK, nsapi);
+
+  }
+} /* nu_unitready_ind_if_nec() */