view src/g23m-aci/dti/dti_int.c @ 303:f76436d19a7a default tip

!GPRS config: fix long-standing AT+COPS chance hanging bug There has been a long-standing bug in FreeCalypso going back years: sometimes in the AT command bring-up sequence of an ACI-only MS, the AT+COPS command would produce only a power scan followed by cessation of protocol stack activity (only L1 ADC traces), instead of the expected network search sequence. This behaviour was seen in different FC firmware versions going back to Citrine, and seemed to follow some law of chance, not reliably repeatable. This bug has been tracked down and found to be specific to !GPRS configuration, stemming from our TCS2/TCS3 hybrid and reconstruction of !GPRS support that was bitrotten in TCS3.2/LoCosto version. ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3 version and had to be pulled from TCS2 - but as it turns out, there is a new field in the MMR_REG_REQ primitive that needs to be set correctly, and that psa_mms.c module is the place where this initialization needed to be added.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Jun 2023 08:23:37 +0000
parents fa8dc04885d8
children
line wrap: on
line source

/*
+-----------------------------------------------------------------------------
|  Project :  DTILIB
|  Modul   :  DTI
+-----------------------------------------------------------------------------
|  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 :  Definitions for the Protocol Stack Library
|             DTI
+-----------------------------------------------------------------------------

  MODULE  : DTI

  PURPOSE : Internal functions of the Protocol Stack Library DTI
*/

#ifndef DTI_INT_C
#define DTI_INT_C
#endif

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

#include <string.h>
#include "typedefs.h"
#include "pconst.cdg"
#include "vsi.h"
#include "custom.h"
#include "gsm.h"
#include "prim.h"
#include "dti.h"
#include "dti_int_def.h"
#include "dti_int_prot.h"


#ifdef FF_TCP_IP
#include "atp/atp_api.h"
#endif /* FF_TCP_IP */

/*
+---------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                  |
| STATE   : code                  ROUTINE : set_default_para_data_base|
+---------------------------------------------------------------------+

 *
 *  Set the default parameter for the DTI data base
 *
 */

GLOBAL void set_default_para_data_base(DTI_HANDLE hDTI)
{
  hDTI->first_link = D_LINK;
  hDTI->handle     = D_LINK_HANDLE;
  hDTI->max_links  = D_MAX_LINKS;

#ifdef FF_TCP_IP
  hDTI->entity_id_p = D_ATP_SW_ENTITY_ID;
#endif /* FF_TCP_IP */
}

/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : free_dti_packets_queue   |
+--------------------------------------------------------------------+

 *
 *  Free dti packets in the queue
 *
 */

LOCAL void free_dti_data_ind_packets_queue(DTI_HANDLE hDTI, T_DTI2_DATA_IND * p_data_ind)
{
  T_DTI2_DATA_IND *p_ind;

  BOOL go = TRUE;

  trace_function( hDTI->handle,
    "free_dti_data_ind_packets_queue()",
    hDTI->entity_options);

   /*
    * Are there any packets in the queue ?
    */

  if (p_data_ind EQ NO_DATA_PACKET )
    return;

  p_ind = p_data_ind;

  /*
   *  Check if DTILIB is supported
   */

  /*
   *  Free the packets
   */

  do {
    T_DTI2_DATA_IND *p_last_ind;
    p_last_ind = p_ind;

    if(p_ind->link_id NEQ 0)
      p_ind = (T_DTI2_DATA_IND *) p_ind->link_id;
    else
      go = FALSE;

    /*
     *  Free the descs at first
     */
    mfree_desc(hDTI, &p_last_ind->desc_list2);

    /*
     *  Free the primitive
     */
    PFREE (p_last_ind);

  } while( go );
} /* free_dti_data_ind_packets_queue() */



/*
+-----------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                    |
| STATE   : code                  ROUTINE : set_default_para_link_table |
+-----------------------------------------------------------------------+
 *
 *  Set the default parameter for DTI_LINK
 *
 */

GLOBAL void set_default_para_link_table (DTI_HANDLE hDTI,
                                         DTI_LINK *link,
                                         U32 link_id,
                                         U8 direction)
{
  /*
   * Free primitives and descs if there are any in the queue
   */
  free_dti_data_ind_packets_queue(hDTI, link->dti_data_ind);
  link->dti_data_ind = NULL;
  /*
   * Set the other parameter to default
   */
  link->link_id       = link_id;
  link->direction     = direction;
  link->version       = D_VERSION;
  link->link_options  = D_LINK_OPTIONS;
  link->instance      = D_INSTANCE;
  link->interfac      = D_INTERFACE;
  link->channel       = D_CHANNEL;
  link->link_handle   = D_LINK_HANDLE;
  link->queue_size    = D_QUEUE_SIZE;
  link->queue_len     = 0;
  link->connect_state = D_CONNECT_STATE;
  link->rx_state      = DTI_RX_IDLE;
  link->tx_state      = DTI_TX_IDLE;
} /* set_default_para_link_table() */



/*
+-----------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_int										                    |
| STATE   : code                  ROUTINE : init_link_table             									|
+-----------------------------------------------------------------------+
 *
 *  Set the init parameter for DTI_LINK
 *
 */

GLOBAL void init_link_table (DTI_LINK *link)
{
  link->link_id          = D_FREE_LINK_ID;
  link->direction        = D_DIRECTION;
  link->version          = D_VERSION;
  link->link_options     = D_LINK_OPTIONS;
  link->instance         = D_INSTANCE;
  link->interfac         = D_INTERFACE;
  link->link_handle      = D_LINK_HANDLE;
  link->queue_size       = D_QUEUE_SIZE;
  link->queue_len        = 0;
  link->channel          = D_CHANNEL;
  link->dti_data_ind     = NULL;
  link->connect_state    = D_CONNECT_STATE;
  link->rx_state         = DTI_RX_IDLE;
  link->tx_state         = DTI_TX_IDLE;
  link->next_link        = D_LINK;
#ifdef FF_TCP_IP
  link->ul_next_atp_data = 0;
  link->atp_tx_state     = ATP_TX_FLOW_ON;
  link->dti_id           = 0;
  link->entity_db        = (U32) NULL;
  link->port_nb          = 0;
#endif /* FF_TCP_IP */
} /* init_link_table() */



/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : free_dti_link_structure  |
+--------------------------------------------------------------------+

 *
 *  Free DTI link structures, DTI_LINK.
 *
 */

GLOBAL void free_dti_link_structure(DTI_HANDLE hDTI)
{
  DTI_LINK *link_last, *link;
  BOOL go = TRUE;

  trace_function(hDTI->handle,
                 "free_dti_link_structure()", /*lint !e605 Increase in pointer capability */
                 hDTI->entity_options);

  /*
   *    Check if there are any packets to free
   */
  if(hDTI->first_link EQ D_LINK)
    return;

  link = (DTI_LINK *) hDTI->first_link;

  do {
    link_last = link;

    if(link->next_link NEQ D_LINK)
      link = (DTI_LINK *) link->next_link;
    else
      go = FALSE;

     /*
      *  Free the dti_queue
      */
    free_dti_data_ind_packets_queue(hDTI, link_last->dti_data_ind);

    /*
     *  Free a link structure
     */
    MFREE (link_last);

  } while( go );

} /* free_dti_link_structure() */

/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : trace_message            |
+--------------------------------------------------------------------+

 *
 *  Create a string
 *
 */

GLOBAL void trace_message (T_HANDLE handle,
                          char *str,
                          U32 entity_options)
{
  if(! (entity_options & DTI_NO_TRACE) )
  {
    TRACE_EVENT(str);
  }
} /*lint !e715 handle not referenced trace_message() */



/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : trace_message_link_id    |
+--------------------------------------------------------------------+

 *
 *  Create a string and a number
 *
 */

GLOBAL void trace_message_link_id (T_HANDLE handle,
                                  char *str,
                                  U32 link_id,
                                  U32 entity_options)
{
  if(! (entity_options & DTI_NO_TRACE) )
  {
    TRACE_EVENT_P2("%s - link_id=%d", str, link_id);
  }
} /*lint !e715 handle not referenced trace_message_link_id() */



/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : trace_message_l_dl       |
+--------------------------------------------------------------------+

 *
 *  Create a string with link_id and data length
 *
 */

GLOBAL void trace_message_l_dl (T_HANDLE handle,
                                char *str,
                                U32 link_id,
                                U16 length,
                                U32 entity_options)
{
  if(! (entity_options & DTI_NO_TRACE) )
  {
    TRACE_EVENT_P3("%s - link_id=%d length=%d", str, link_id, length);
  }
} /* trace_message_l_dl() */



/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : trace_message_iic        |
+--------------------------------------------------------------------+

 *
 *  Create a string and a number
 *
 */

GLOBAL void trace_message_iic (T_HANDLE handle,
                              char *str,
                              U8 instance,
                              U8 interfac,
                              U8 channel,
                              U32 entity_options)
{
  if(!(entity_options & DTI_NO_TRACE))
  {
    TRACE_EVENT_P4("%s - instance=%d interface=%d channel=%d",
                   str,
                   instance,
                   interfac,
                   channel);
  }
} /*lint !e715 handle not referenced trace_message_iic() */



/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : trace_message_l_e        |
+--------------------------------------------------------------------+

 *
 *  Create a string and a number
 *
 */

GLOBAL void trace_message_l_e (T_HANDLE handle,
                              char *str,
                              U32 link_id,
                              char* entity,
                              U32 entity_options)
{
  if(!(entity_options & DTI_NO_TRACE))
  {
    TRACE_EVENT_P3("%s - link_id=%d neighbor_entity=%s",
                   str,
                   link_id,
                   entity);
  }
} /*lint !e715 handle not referenced trace_message_l_e() */

/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : trace_function           |
+--------------------------------------------------------------------+

 *
 * Call macro TRACE_FUNKTION if traces are enabled
 *
 */

GLOBAL void trace_function( T_HANDLE handle, char *str, U32 entity_options)
{
  if(! (entity_options & DTI_NO_TRACE) )
  {
    TRACE_FUNCTION (str);
  }
} /*lint !e715 handle not referenced trace_function() */



/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB       MODULE  :    DTI_KERF                       |
| STATE   : code         ROUTINE :  get_pointer_link_table_channel   |
+--------------------------------------------------------------------+

 *
 *  The function searchs an instance and a channel in the database link list
 *  and returns a pointer to the link list. If there is no link with the same channel and
 *  the same interface it returns NULL.
 */

GLOBAL DTI_LINK * get_pointer_link_table_channel (DTI_HANDLE hDTI,
                                                 U8 instance,
                                                 U8 interfac,
                                                 U8 channel)
{
  DTI_LINK *link_last, *link;
  BOOL go = TRUE;

  trace_function(hDTI->handle,
                 "get_pointer_link_table_channel()", /*lint !e605 Increase in pointer capability */
                 hDTI->entity_options);

  link = (DTI_LINK *) hDTI->first_link;

  /*
   *  Check if the link is not set
   */

  if(link EQ NULL)
    return NULL;

  do {
    link_last = link;

    /*
     *  Search on instance, interface and channal
     */

    if((link_last->instance EQ instance) AND (link_last->channel EQ channel) AND
      (link_last->interfac EQ interfac) AND
      (link_last->link_id NEQ D_FREE_LINK_ID))

      return link_last;

    if(link->next_link NEQ D_LINK)
      link = (DTI_LINK *) link->next_link;
    else
      go = FALSE;

  } while( go );

  return NULL;
}


/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : get_pointer_link_table   |
+--------------------------------------------------------------------+

 *
 *  The function searchs a link id in the databank link list and returns a
 *  pointer to the link list. If there is no link_id with the selected direction it
 *  returns NULL. Note: the direction is used to select between to equal
 *  links in a link list because it could be 2 channels are connected on one
 *  instance.
 */

GLOBAL DTI_LINK * get_pointer_link_table (DTI_HANDLE hDTI,
                                          U32 select_link_id,
                                          U8 select_direction)
{
  DTI_LINK* link;

  trace_function(hDTI->handle,
                 "get_pointer_link_table()",
                 hDTI->entity_options);

  link = (DTI_LINK *) hDTI->first_link;

  /*
   *  Find the link and return it
   */
  while(link NEQ NULL)
  {
    if(link->link_id EQ select_link_id)
      return link;

    link = (DTI_LINK *) link->next_link;
  }

  return NULL;
} /* get_pointer_link_table() */



/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : get_pointer_free_link    |
+--------------------------------------------------------------------+

PURPOSE : The function searches a free link in the database link list
          and returns a pointer to the link structure. If there is no
          linkin the database then it returns NULL.
*/

GLOBAL DTI_LINK * get_pointer_free_link (DTI_HANDLE hDTI)
{
  DTI_LINK* link;

  trace_function( hDTI->handle,
    "get_pointer_free_link()",
    hDTI->entity_options);

  /*
   * Search for unused link
   */
  link = (DTI_LINK *) hDTI->first_link;
  while(link)
  {
    if(link->connect_state EQ DTI_CLOSED)
      return link;
    link = (DTI_LINK*)link->next_link;
  }

  /*
   * Search for a link where only DTI_CONNECT_REQ has been received.
   * This solves the situation when dti_open() is called for a new link
   * and all links are used by existing links
   * which are going to be closed and reopened with an other link_id
   */
  link = (DTI_LINK *) hDTI->first_link;
  while(link)
  {
    if(link->connect_state EQ DTI_CONNECTING)
      return link;
    link = (DTI_LINK*)link->next_link;
  }

  return NULL;
} /* get_pointer_free_link() */



/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : open_comm_channel        |
+--------------------------------------------------------------------+

 *
 *  This function opens a VSI communication channel. If it's open it will be closed
 *  and opened new again. The opened handle is returned in the parameter com_handle.
 */

GLOBAL void open_comm_channel(T_HANDLE entity_handle,
                             T_HANDLE *com_handle,
                             char *name,
                             U32 entity_options)
{

  trace_function( entity_handle,
    "open_comm_channel()",
    entity_options);

  /* Be sure the channel is closed if it was opened before */
  vsi_c_close (entity_handle, *com_handle);

  /* Open */
  *com_handle = vsi_c_open(entity_handle, name);
}

/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : check_dti_version        |
+--------------------------------------------------------------------+

 *
 *  This function checks the version in a link table.
 *  and returns TRUE if the same version is found as in the request_version.
 */

GLOBAL BOOL check_dti_version (DTI_HANDLE hDTI, U32 request_version)
{
  trace_function(hDTI->handle,
                 "check_dti_version()", /*lint !e605 Increase in pointer capability */
                 hDTI->entity_options);

  /*
   *  DTILIB has to be able to use older versions too.
   *  NOTE: this has been D_VERSION <= request_version until Aug-2002
   *        just an error or some sort of intricate reasoning??
   */
  if(D_VERSION >= request_version)
    return TRUE;
  else
    return FALSE;
}

/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : validate_open_parameters |
+--------------------------------------------------------------------+

 *
 *  This function validates the open-parameters
 */
GLOBAL DTI_RESULT validate_open_parameters(DTI_HANDLE hDTI,
                                          U32 link_id,
                                          U8 *queue_size,
                                          U8 *direction,
                                          U32 *link_options,
                                          U32 version,
                                          U8 *neighbor_entity)
{
  trace_function(hDTI->handle,
                 "validate_open_parameters()", /*lint !e605 Increase in pointer capability */
                 hDTI->entity_options);

  /*
   *  Check version of peer dtilib
   */
  if (
    check_dti_version
      (
      hDTI,
      version
      ) EQ FALSE
    )
  {
    trace_message_link_id(hDTI->handle,
      "DTI ERROR: Wrong DTI version", /*lint !e605 Increase in pointer capability */
      link_id,
      hDTI->entity_options);
    return DTI_E_FAIL;
  }

  /*
   * Legacy
   */

  /*
   *  Check if open with the NULL device.
   */
  if (strcmp ((CHAR*)neighbor_entity, NULL_NAME) EQ 0)
  {
    *direction = DTI_NULL_LINK;
  }
  if (*link_options EQ FLOW_CNTRL_ENABLED)
  {
    if (*queue_size EQ DTI_QUEUE_DISABLED)
    {
      *link_options = DTI_QUEUE_UNUSED;
    }
    else if (*queue_size EQ DTI_QUEUE_UNLIMITED)
    {
      *link_options = DTI_QUEUE_UNBOUNDED;
    }
    else
    {
      /*
       * Set default behaviour
       */
      *link_options = DTI_QUEUE_RM_LIFO;
    }
  }

  /*
   * Ensure consistency
   */
  if((*link_options EQ DTI_QUEUE_UNUSED) OR
     (*link_options EQ DTI_FLOW_CNTRL_DISABLED) OR
     (*link_options EQ DTI_QUEUE_UNBOUNDED))
  {
    *queue_size = 0;
  }
  else if(*queue_size EQ 0)
  {
    *link_options = DTI_QUEUE_UNUSED;
  }

  return DTI_S_OK;
}


/*
+-----------------------------------------------------------------------+
| PROJECT : DTILIB                    MODULE  : DTI_KERF                |
| STATE   : code                      ROUTINE : set_link_parameter      |
+-----------------------------------------------------------------------+

 *
 *  Set parameter in a link desc.
 */

GLOBAL void set_open_para_link_table (DTI_HANDLE hDTI,
                                      DTI_LINK *link,
                                      U32   version,
                                      U32   link_options,
                                      U8    instance,
                                      U8    interfac,
                                      U8    channel,
                                      U8    queue_size,
                                      U8    connect_state)
{
  trace_function(hDTI->handle,
                 "set_open_para_link_table()",
                 hDTI->entity_options);

  /*
   * Free primitives and descs if there are any in the queue.
   */
  free_dti_data_ind_packets_queue(hDTI, link->dti_data_ind);
  link->dti_data_ind = NULL;
  /*
   * set parameters as requested
   */
  link->version       = version;
  link->instance      = instance;
  link->interfac      = interfac;
  link->channel       = channel;
  link->link_handle   = D_LINK_HANDLE;
  link->queue_len     = 0;
  link->rx_state      = DTI_RX_IDLE;
  link->tx_state      = DTI_TX_BUFFER_FULL;
  link->connect_state = connect_state;
  link->queue_size    = queue_size;
  link->link_options  = link_options;
  /*
   * the following structure is needed for ATP links
   */
#ifdef FF_TCP_IP
  link->entity_db     = D_HANDLE;
  link->port_nb       = 0;
#endif /* FF_TCP_IP */
} /* set_open_para_link_table() */



/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : dti_resolve_link_id      |
+--------------------------------------------------------------------+

 *
 * This function returns the link_id for the given
 * instance/interface/channel.
 *
 * This is to be used to identify primitives sent from the entity to ACI
 *
 * return value:  TRUE if associated link_id is found
 *                FALSE, otherwise
 */

GLOBAL BOOL dti_resolve_link_id (DTI_HANDLE hDTI,
                                 U8 instance,
                                 U8 interfac,
                                 U8 channel,
                                 U32 *link_id)
{
  DTI_LINK *link;

  trace_function(hDTI->handle,
                 "dti_resolve_link_id()", /*lint !e605 Increase in pointer capability */
                 hDTI->entity_options);

  if((link = get_pointer_link_table_channel(hDTI,
                                            instance,
                                            interfac,
                                            channel)) EQ NULL)
  {
    return FALSE;
  }

  *link_id = link->link_id;
  return TRUE;
} /* dti_resolve_link_id() */

/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                 |
| STATE   : code                  ROUTINE : put_dti_data_ind_in_queue|
+--------------------------------------------------------------------+

 *
 *  This function puts a dti_data_req primitive in queue.
 */

GLOBAL void put_dti_data_ind_in_queue( DTI_HANDLE hDTI, DTI_LINK *link,
  T_DTI2_DATA_IND *dti_data_ind)
{

  if (hDTI->handle NEQ 0)
  {
    trace_function( hDTI->handle,
      "put_dti_data_ind_in_queue()",
      hDTI->entity_options);
  }

  dti_data_ind->link_id = 0;

  /*
   * Put in the first data packet.
   * When using the old SAP the link->queue len can be 0 or 1
   */
  {
    T_DTI2_DATA_IND *p_ind;
    U8 chk     = 1;

    if(link->queue_len EQ 0)
    {
      link->dti_data_ind = dti_data_ind;
      link->queue_len++;
      return;
    }


    /* Now put more packets in the queue and put the new one on the last position */
    p_ind = link->dti_data_ind;

    /*
     *    Search the last packet in queue.
     */
    while(p_ind->link_id NEQ 0)
    {
      p_ind = (T_DTI2_DATA_IND *) p_ind->link_id;
      chk++;
    }

    p_ind->link_id = (U32) dti_data_ind;

    /*
     * Check the queue length.
     */
    if(chk != link->queue_len)
    {
      trace_message_link_id(hDTI->handle,
        "DTI ERROR: Write to queue error", /*lint !e605 Increase in pointer capability */
        link->link_id,
        hDTI->entity_options);
      return;
    }
    link->queue_len++;
  }
}



/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB             MODULE  : DTI_KERF                    |
| STATE   : code               ROUTINE : get_dti_data_ind_from_queue |
+--------------------------------------------------------------------+

 *
 *  This function gets a dti_data_ind primitive from queue. If there is
 *  no packet in the queue it returns NULL.
 */

GLOBAL T_DTI2_DATA_IND * get_dti_data_ind_from_queue(DTI_HANDLE hDTI,
                                                     DTI_LINK *link)
{
  T_DTI2_DATA_IND *ret_dti_data_ind;

  trace_function( hDTI->handle,
    "get_dti_data_ind_from_queue()",
    hDTI->entity_options);

  /*
   *    Is there any packet in the queue ?
   */
  if(link->queue_len EQ 0)
  {
    return NULL;
  }
  /*
   *    Set the second data packet on the first position.
   */
  ret_dti_data_ind = link->dti_data_ind;
  /*
   *    Set the queue length
   */
  link->queue_len--;
  /*
   *  Put the next data packet in position.
   */
  link->dti_data_ind = (T_DTI2_DATA_IND *)link->dti_data_ind->link_id;

  return (ret_dti_data_ind);
} /* get_dti_data_ind_from_queue() */



/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB        MODULE  : DTI_KERF                         |
| STATE   : code          ROUTINE : get_last_dti_data_ind_from_queue |
+--------------------------------------------------------------------+

 *
 * This function gets a dti_data_ind primitive from queue. If there is
 * no packet in the queue it returns NULL.
 */

LOCAL T_DTI2_DATA_IND * get_last_dti_data_ind_from_queue(DTI_HANDLE hDTI,
                                                         DTI_LINK *link)
{
  T_DTI2_DATA_IND **last_dti_data_ind;
  T_DTI2_DATA_IND *ret_dti_data_ind;

  trace_function(hDTI->handle,
    "get_last_dti_data_ind_from_queue()",
    hDTI->entity_options);

  /*
   * Is there any packet in the queue?
   */
  if(link->queue_len EQ 0)
  {
    return NULL;
  }
  /*
   * Get the last data packet
   */
  last_dti_data_ind = &(link->dti_data_ind);
  while((*last_dti_data_ind)->link_id NEQ 0)
  {
    last_dti_data_ind = (T_DTI2_DATA_IND **) &((*last_dti_data_ind)->link_id);
  }
  ret_dti_data_ind = *last_dti_data_ind;
  /*
   * Set the queue length
   */
  link->queue_len--;
  /*
   * remove the data packet from queue.
   */
  *last_dti_data_ind = 0;

  return (ret_dti_data_ind);
} /* get_last_dti_data_ind_from_queue() */



/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB        MODULE  : DTI_KERF                         |
| STATE   : code          ROUTINE : put_dti_data_ind_in_queue_managed|
+--------------------------------------------------------------------+

 *
 *  This function puts a dti_data_req primitive in queue.
 *  If the queue is full, it acts accordingly
 */

GLOBAL void put_dti_data_ind_in_queue_managed (DTI_HANDLE hDTI,
                                              DTI_LINK *link,
                                              T_DTI2_DATA_IND *dti_data_ind)
{
  trace_function(hDTI->handle,
                 "put_dti_data_ind_in_queue_managed()", /*lint !e605 Increase in pointer capability */
                 hDTI->entity_options);

  /*
   * Put new data packet into the queue.
   */
  if(link->link_options NEQ DTI_QUEUE_UNUSED)
  {
    put_dti_data_ind_in_queue(hDTI, link, dti_data_ind);
  }

  /*
   * If queue full - send signal to entity.
   */
  switch (link->link_options)
  {
  case DTI_QUEUE_UNBOUNDED:
  case DTI_QUEUE_WATERMARK:
    break;

  case DTI_QUEUE_UNUSED:
    /* free data primitive since we cannot handle it */

    trace_message_link_id(hDTI->handle,
      "DTI ERROR: No send queue available, discarding data packet", /*lint !e605 Increase in pointer capability */
      link->link_id,
      hDTI->entity_options);

    mfree_desc (hDTI, &dti_data_ind->desc_list2);
    PFREE (dti_data_ind);
    break;

  case DTI_QUEUE_RM_FIFO:
    if (link->queue_len > link->queue_size)
    {
      T_DTI2_DATA_IND *free_dti_data_ind
        = get_dti_data_ind_from_queue(hDTI, link);

      trace_message_link_id(hDTI->handle,
        "Send queue full, discarding oldest data packet", /*lint !e605 Increase in pointer capability */
        link->link_id,
        hDTI->entity_options);

      mfree_desc (hDTI, &free_dti_data_ind->desc_list2);
      PFREE (free_dti_data_ind);
    }
    break;

  case DTI_QUEUE_RM_LIFO:
    if (link->queue_len > link->queue_size)
    {
      T_DTI2_DATA_IND *free_dti_data_ind
        = get_last_dti_data_ind_from_queue(hDTI, link);

      trace_message_link_id(hDTI->handle,
        "Send queue full, discarding newest data packet", /*lint !e605 Increase in pointer capability */
        link->link_id,
        hDTI->entity_options);

      mfree_desc (hDTI, &free_dti_data_ind->desc_list2);
      PFREE (free_dti_data_ind);
    }
    break;

  default:
    trace_message_link_id(hDTI->handle,
      "DTI ERROR: Unknown state for link_options", /*lint !e605 Increase in pointer capability */
      link->link_id,
      hDTI->entity_options);
    break;
  }
} /* put_dti_data_ind_in_queue_managed() */



/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                    MODULE  : DTI_KERF             |
| STATE   : code                      ROUTINE : dti_make_new_desc    |
+--------------------------------------------------------------------+

 *
 *  Malloc a knew desc. Init a buffer 0 if buff_init_0 is TRUE.
 *
 */

BOOL dti_make_new_desc( DTI_HANDLE hDTI, T_desc2 **p_desc_new,
  U16 malloc_len, BOOL buff_init_0)
{
#define VSI_CALLER hDTI->handle,

  trace_function( hDTI->handle,
    "dti_make_new_desc()",
    hDTI->entity_options);

  MALLOC ((*p_desc_new), ((U16)(sizeof(T_desc2)-1 + malloc_len)));

  if(*p_desc_new EQ 0)
    return(FALSE);

  if(buff_init_0)
  {
    U16 i;
    for(i=0; i<malloc_len; i++)
      (*p_desc_new)->buffer[i] = 0;
  }
  (*p_desc_new)->len    = malloc_len;
  (*p_desc_new)->next   = 0;
  (*p_desc_new)->offset = 0;
  (*p_desc_new)->size   = (*p_desc_new)->len + (*p_desc_new)->offset;
  return(TRUE);

#undef VSI_CALLER
}


/*
+--------------------------------------------------------------------+
| PROJECT : DTILIB                    MODULE  : DTI_KERF             |
| STATE   : code                      ROUTINE : mfree_desc           |
+--------------------------------------------------------------------+

 *
 *  Free the descs in a desc list.
 *
 */


GLOBAL void mfree_desc(DTI_HANDLE hDTI, T_desc_list2 * desc_list2)
{
  BOOL go = TRUE;
  T_desc2 *p_desc_last, *p_desc;

  trace_function( hDTI->handle,
    "mfree_desc()",
    hDTI->entity_options);

  if (desc_list2 EQ NULL)
    return;

  if (desc_list2->first EQ 0)
    return;

  p_desc = (T_desc2 *) desc_list2->first;

  do {
    p_desc_last = p_desc;

    if(p_desc->next >0)
      p_desc = (T_desc2 *) p_desc->next;
    else
      go = FALSE;

    MFREE (p_desc_last);

  } while( go );
}


/*
+-----------------------------------------------------------------------+
| PROJECT : DTILIB                    MODULE  : DTI_KERF                |
| STATE   : code                      ROUTINE : close_link_with_signal  |
+-----------------------------------------------------------------------+

 *
 *  Close a link.
 */

GLOBAL void close_link_with_signal(DTI_HANDLE hDTI, DTI_LINK *link)
{
  U8 hlp_instance, hlp_interface;
  U8 hlp_channel;

  trace_function( hDTI->handle,
    "close_link_with_signal()",
    hDTI->entity_options);

  /*
   *  Close communication channel
   */
  vsi_c_close (hDTI->handle, link->link_handle);

  hlp_instance   =   link->instance;
  hlp_interface  =   link->interfac;
  hlp_channel    =   link->channel;

  /*
   *  Set the default parameter and call the callback function.
   */

  set_default_para_link_table(hDTI,link, D_FREE_LINK_ID, D_DIRECTION);

  /*
   *  Call the callback function.
   */

  hDTI->sig_callback(hlp_instance, hlp_interface, hlp_channel,
    DTI_REASON_CONNECTION_CLOSED, NULL);

  /*
   * Note: Any flow control and any data primitive are now silently discarded.
   */
}



/*
+-------------------------------------------------------------------------+
| PROJECT : DTILIB                MODULE  : DTI_KERF                      |
| STATE   : code                  ROUTINE : set_reset_req_para_link_table |
+-------------------------------------------------------------------------+
 *
 *  Set parameter by reset.
 *
 */

GLOBAL void set_reset_req_para_link_table(DTI_HANDLE hDTI, DTI_LINK *link)
{
  /*
   * Free primitives and descs if there are any in the queue.
   */
  free_dti_data_ind_packets_queue(hDTI, link->dti_data_ind);
  link->dti_data_ind = NULL;
  /*
   * Set the other parameters
   */
  link->queue_len     = 0;
  link->connect_state = DTI_IDLE;
} /* set_reset_req_para_link_table() */