view src/g23m-aci/aci/psa_tcpipf.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 :  WAPoverGPRS
|  Modul   :  PSA_TCPIPF
+----------------------------------------------------------------------------- 
|  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 :  Functions for interfacing to TCP/IP-related entities. At
|             the moment, these are IP(v4) and UDP. In the future, TCP and IPv6
|             and perhaps others will follow, so we try to be as general as
|             possible.
|             
|             Main exports:
|             psaTCPIP_Activate()
|             psaTCPIP_Configure()
|             psaTCPIP_Deactivate()
|             
|             Declarations and definitions are in psa_tcpip.h.
+----------------------------------------------------------------------------- 
*/ 
#if defined (CO_UDP_IP) || defined (FF_GPF_TCPIP)

#ifndef PSA_TCPIPF_C
#define PSA_TCPIPF_C
#endif /* !PSA_TCPIPF_C */

#include "aci_all.h"
/*==== INCLUDES ===================================================*/
#include "dti.h"      /* functionality of the dti library */
#include "dti_conn_mng.h"
#include "aci_cmh.h"
#include "ati_cmd.h"
#include "aci_cmd.h"
#include "aci_fd.h"
#include "psa.h"
#include "psa_tcpip.h"
#include "psa_cc.h"
#include "cmh.h"
#include "psa_ra.h"
#include "cmh_ra.h"
#include "cmh_l2r.h"

#include "ksd_utl.h"

#if defined (FF_SAT_E) 
#include "cmh_cc.h"
#include "psa_sat.h"
#endif /* SAT E */ 

#ifdef FF_GPF_TCPIP
#include "dcm_utils.h"
#include "dcm_state.h"
#include "dcm_env.h"
#endif
#include "dcm_f.h"



/*==== CONSTANTS ==================================================*/

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


/*==== EXPORT =====================================================*/
GLOBAL void psaTCPIP_Initialize_Req(void);
GLOBAL void psaTCPIP_Shutdown_Req(void);
GLOBAL void psaTCPIP_Config (ULONG ipaddr, ULONG dns1, ULONG dns2, UBYTE dirc);
GLOBAL ULONG bytes2ipv4addr(UBYTE *host);

/*==== VARIABLES ==================================================*/

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

/* Convert an IP address in an array of 4 bytes (network order
 * assumed) into an unsigned long value representing the same IP
 * address, also in network order. This is purely a matter of
 * alignment, so a simple copy will do.
 */
ULONG psaTCPIP_bytes2ipv4addr(UBYTE *ip_address)
{
  ULONG result;
  UBYTE i;
  BYTE buf[4];

  for (i=0; i<4; i++)
  {
    utl_string2Byte ((CHAR*)(ip_address+(i*4)), 3, &buf[3-i]);
  }
  memcpy(&result, buf, 4);
  return result;
}

GLOBAL char* wap_state_to_string(T_ACI_WAP_STATES wap_state)
{
  switch(wap_state)
  {
    case Wap_Not_Init: return "wap-not_init";
#ifdef FF_GPF_TCPIP
    case TCPIP_Initialization:  return "TCPIP_Initialization";
    case TCPIP_Initialized:     return "TCPIP_Initialized";
    case TCPIP_Activation:      return "TCPIP_Activation";
    case TCPIP_Activated:       return "TCPIP_Activated";
#endif /*FF_GPF_TCPIP*/
  	case UDPA_Activation:       return "UDPA_Activation";
  	case UDPA_Activated:        return "UDPA_Activated";
    case IPA_Activation:        return "IPA_Activation";
  	case IPA_Activated:         return "IPA_Activated";
  	case IPA_Configuration:     return "IPA_Configuration";
  	case IPA_Configurated:      return "IPA_Configurated";
   	case UDPA_Configuration:    return "UDPA_Configuration";
  	case UDPA_Configurated:     return "UDPA_Configurated";
#ifdef FF_GPF_TCPIP	
  	case TCPIP_Configuration:   return "TCPIP_Configuration";
    case TCPIP_Configurated:    return "TCPIP_Configurated";
#endif /*FF_GPF_TCPIP*/
  	case IPA_Deconfiguration:   return "IPA_Deconfiguration";
   	case IPA_Deconfigurated:    return "IPA_Deconfigurated";
   	case UDPA_Deconfiguration:  return "UDPA_Deconfiguration";
   	case UPDA_Deconfigurated:   return "UPDA_Deconfigurated";
#ifdef FF_GPF_TCPIP	
   	case TCPIP_Deconfiguration: return "TCPIP_Deconfiguration";
   	case TCPIP_Deconfigurated:  return "TCPIP_Deconfigurated";
    case TCPIP_Deactivation:    return "TCPIP_Deactivation";
   	case TCPIP_Deactivated:     return "TCPIP_Deactivated";
#endif /*FF_GPF_TCPIP*/
    case UDPA_Deactivation:     return "UDPA_Deactivation";
  	case UDPA_Deactivated:      return "UDPA_Deactivated";
  	case IPA_Deactivation:      return "IPA_Deactivation";
   	case IPA_Deactivated:       return "IPA_Deactivated";
    default:                    return "<Unknown wap_state>";
  }
}


/*
+-------------------------------------------------------------------+
| PROJECT : WAPoverGPRS           MODULE  : PSA_TCPIP               |
|                                 ROUTINE : psaTCPIP_Init           |
+-------------------------------------------------------------------+

  PURPOSE : Initialize the protocol stack adapter for TCP/IP.

*/
GLOBAL void psaTCPIP_Init(void)
{
  memset (&tcpipShrdPrm, 0, sizeof (T_TCPIP_SHRD_PRM));
  wap_state = Wap_Not_Init ;    /* This is redundant at the moment,
                                 * but will be set only here
                                 * eventually. */
  tcpipShrdPrm.connection_type    = TCPIP_CONNECTION_TYPE_UNKNOWN;
  tcpipShrdPrm.connection_buildup = TCPIP_CONNECTION_BUILDUP_UNKNOWN;
}


/* Activate TCP/IP-related entities. See psa_tcpip.h for a detailed
 * description.
 */
void psaTCPIP_Activate(UBYTE src_id,
                       UBYTE dti_id,
                       SHORT wap_call_id,
                       UBYTE options,
                       UBYTE connection_type,
                       void (*callback_function)(T_ACI_RETURN result))
{
  /* The `options' parameter is not yet used, since we have only UDP
   * and IPv4. This will change in the future, including related
   * changes to other parts of the ACI. (At the moment the completion
   * of UDP activation calls IP activation directly, but this will
   * have to be torn apart. [ni 2001-10-02]
   */

  TRACE_FUNCTION ("psaTCPIP_Activate()") ;
  
  tcpipShrdPrm.src_id             = src_id ;
  tcpipShrdPrm.connection_type    = connection_type;
  tcpipShrdPrm.connection_buildup = TCPIP_CONNECTION_BUILDUP_UP;
  tcpipShrdPrm.wap_call_id        = wap_call_id ;
  tcpipShrdPrm.options            = options ;
  tcpipShrdPrm.callback_function  = callback_function ;

  if(is_gpf_tcpip_call()) {
    GPF_TCPIP_STATEMENT(wap_state = TCPIP_Initialization);
    psaTCPIP_config_dispatch();
  }
  else {
    wap_state = Wap_Not_Init ;
    psaUDPIP_config_dispatch();
  }
}


/* Configure TCP/IP-related entities.
 */
void psaTCPIP_Configure(UBYTE *ip_address,
                        void *pdp_addrp,
                        UBYTE *peer_address,
                        UBYTE *dns1,
                        UBYTE *dns2,
                        short  mtu,
                        void (*callback_function)(T_ACI_RETURN result))
{
  TRACE_FUNCTION("psaTCPIP_Configure()") ;

  if (ip_address AND pdp_addrp) {
    TRACE_ERROR("psaTCPIP_Configure(): both ip_address and pdp_addrp non-null!") ;
    return ;
  }

  if (!ip_address AND !pdp_addrp) {
    TRACE_ERROR("psaTCPIP_Configure(): both ip_address and pdp_addrp null!") ;
    return ;
  }

  if (ip_address)               /* From PPP, IP over CSD. */
  {
    memcpy(tcpipShrdPrm.ipaddr, ip_address, 16) ;
  }
#ifdef GPRS
  else if (pdp_addrp)           /* From SNDCP, IP over GPRS. */
  {
    memcpy(tcpipShrdPrm.ipaddr, pdp_addrp, 16/*sizeof(tcpipShrdPrm.ipaddr)*/);
  }
#endif

  if (peer_address) {
    memcpy(tcpipShrdPrm.peer_addr, peer_address, 16) ;
  }
  if(dns1) {
    memcpy(tcpipShrdPrm.dns1,dns1,16);
  }

  if(dns2) {
    memcpy(tcpipShrdPrm.dns2,dns2,16);
  }
  tcpipShrdPrm.mtu = mtu ;
  tcpipShrdPrm.callback_function = callback_function ;

  if(is_gpf_tcpip_call()) {
    GPF_TCPIP_STATEMENT(wap_state = TCPIP_Configuration);
    psaTCPIP_config_dispatch();
  }
  else {
  wap_state = IPA_Configuration ;
    psaUDPIP_config_dispatch();
  }
}


/* Deactivate TCP/IP-related entities.
 */
void psaTCPIP_Deactivate(void (*callback_function)(T_ACI_RETURN result))
{
  TRACE_FUNCTION("psaTCPIP_Deactivate()") ;
  TRACE_EVENT_P1("wap_state: %d", wap_state) ;

  tcpipShrdPrm.connection_buildup = TCPIP_CONNECTION_BUILDUP_DOWN;
  tcpipShrdPrm.callback_function = callback_function ;

  if(is_gpf_tcpip_call()) {
    #ifdef FF_GPF_TCPIP
    if ( wap_state EQ TCPIP_Configurated ) {
      wap_state = TCPIP_Deconfiguration ;
    }
    #endif
    psaTCPIP_config_dispatch() ;
  }
  else {
    if ( wap_state EQ UDPA_Configurated ) {
    wap_state = IPA_Deconfiguration ;
  }
    psaUDPIP_config_dispatch();
  }
}


/********************** Dispatcher functions **********************/

/* State machine for UDP/TCP/IP activation, configuration, and
 * deactivation. At the moment some of this is still handled elsewhere
 * in the ACI (see comments to psaTCPIP_Configure() and
 * psaTCPIP_Activate() above), but I plan to tear this apart and keep
 * all control over these activities in this place, including status
 * checks and transitions. [ni 2001-10-02]
 */

void psaUDPIP_config_dispatch(void)
{
#ifdef CO_UDP_IP // to avoid linker errors in simulation

  TRACE_FUNCTION("psaUDPIP_config_dispatch()") ;
  TRACE_EVENT_P1("wap_state: %s", wap_state_to_string(wap_state)) ;
  switch (wap_state)
  {
    /* Entry point for activation. */
    case Wap_Not_Init:
      cmhUDPA_Activate((T_ACI_CMD_SRC)tcpipShrdPrm.src_id, tcpipShrdPrm.wap_call_id) ;
      break ;
    case UDPA_Activation:       /* Unused at the moment; handled elsewhere. */
      break ;
    case UDPA_Activated:        /* Unused at the moment; handled elsewhere. */
      break ;
    case IPA_Activation:        /* Unused at the moment; handled elsewhere. */
      break ;
    case IPA_Activated:
      switch (tcpipShrdPrm.connection_buildup)
      {
        case TCPIP_CONNECTION_BUILDUP_UP:
          if (tcpipShrdPrm.callback_function)
          {
            tcpipShrdPrm.callback_function(AT_CMPL) ;
          }
          break ;
        case TCPIP_CONNECTION_BUILDUP_DOWN:
          cmhUDPA_Deactivate(tcpipShrdPrm.src_id);
          break;
        default:
          TRACE_ERROR("Unknown build up state in psaTCPIP_config_dispatch()");
          return;
      }
      break;
      /* Entry point for configuration. */
    case IPA_Configuration:
      switch (tcpipShrdPrm.connection_buildup)
      {
        case TCPIP_CONNECTION_BUILDUP_UP:
          psaIPA_Config(psaTCPIP_bytes2ipv4addr(tcpipShrdPrm.ipaddr),
                        tcpipShrdPrm.mtu, IPA_CONN) ;
          break;
        case TCPIP_CONNECTION_BUILDUP_DOWN:
          psaIPA_Config(psaTCPIP_bytes2ipv4addr(tcpipShrdPrm.ipaddr),
                        tcpipShrdPrm.mtu, IPA_DSC) ;
          break;
        default:
          TRACE_ERROR("Unknown build up state in psaTCPIP_config_dispatch()");
          return;
      }
      break;
    case IPA_Configurated:      /* Unused at the moment; handled elsewhere. */
      break ;
    case UDPA_Configuration:    /* Unused at the moment; handled elsewhere. */
      break ;
    case UDPA_Configurated:
      if (tcpipShrdPrm.callback_function)
      {
        tcpipShrdPrm.callback_function(AT_CMPL) ;
      }
      break ;

      /* Entry point for deactivation. */
    case IPA_Deconfiguration:
      psaIPA_Config(0, 0, IPA_DSC) ;
      break ;
    case IPA_Deconfigurated:    /* Unused at the moment; handled elsewhere. */
      break ;
    case UDPA_Deactivation:     /* Unused at the moment; handled elsewhere. */
#if defined (FF_SAT_E) 
        /* If transport layer is UDP, reset wap_call flag 
           UDP is not busy anymore */
        if( satShrdPrm.chnTb.chnTPL EQ UDP )
        {
          sAT_PercentWAP ( CMD_SRC_NONE, 0 );
        }
#endif /* SAT E */ 
      break ;
    case UDPA_Deactivated:      /* Unused at the moment; handled elsewhere. */
      break ;
    case IPA_Deactivation:
      wap_state = IPA_Deactivated ;
      tcpipShrdPrm.connection_type = TCPIP_CONNECTION_TYPE_UNKNOWN;

      if (tcpipShrdPrm.callback_function)
      {
        tcpipShrdPrm.callback_function(AT_CMPL) ;
      }
      /*lint -fallthrough*/
    case IPA_Deactivated:
      wap_state = Wap_Not_Init ;
      
      if(ccShrdPrm.wapStat EQ CC_WAP_STACK_DOWN)
      {
        /* WAP-dedicated variables shall be reinitialized */
        wapId     = NO_ENTRY;
        Wap_Call  = FALSE;
      
        TRACE_EVENT ("WAP parameter reseted");
      }
      break ;

    default:
      TRACE_ERROR("Unknown wap state in psaTCPIP_config_dispatch()") ;
  }
#else
  ACI_ASSERT(FALSE);
#endif  
}


/******************************************************************************/
void psaTCPIP_config_dispatch(void)
{
#ifdef FF_GPF_TCPIP // to avoid linker errors in simulation

  TRACE_FUNCTION("psaTCPIP_config_dispatch()") ;
  TRACE_EVENT_P1("wap_state: %s", wap_state_to_string(wap_state)) ;
  switch (wap_state)
  {
    case TCPIP_Initialization :
      switch(tcpipShrdPrm.connection_buildup)
      {
        case TCPIP_CONNECTION_BUILDUP_UP:
          psaTCPIP_Initialize_Req();      
          break;

        case TCPIP_CONNECTION_BUILDUP_DOWN:
          psaTCPIP_Shutdown_Req();
          break;

        default:
          TRACE_ERROR("Error: Unknown build_up state in psaTCPIP_config_dispatch()");
          return;   
      }

    case TCPIP_Initialized :
       break;

    case TCPIP_Activation :        
      switch(tcpipShrdPrm.connection_buildup)
      {
        case TCPIP_CONNECTION_BUILDUP_UP:
          if(tcpipShrdPrm.callback_function)
          {
            tcpipShrdPrm.callback_function(AT_CMPL);
          }
          break ;

        case TCPIP_CONNECTION_BUILDUP_DOWN:
          wap_state = TCPIP_Deactivation;
          psaTCPIP_Shutdown_Req();
          break;
          
        default:
          TRACE_ERROR("Error: Unknown build up state in psaTCPIP_config_dispatch()");
          return;
      }
      break;

    case TCPIP_Configuration:
      switch(tcpipShrdPrm.connection_buildup)
      {
        case TCPIP_CONNECTION_BUILDUP_UP:
          psaTCPIP_Config(bytes2ipv4addr(tcpipShrdPrm.ipaddr),
                          bytes2ipv4addr(tcpipShrdPrm.dns1),
                          bytes2ipv4addr(tcpipShrdPrm.dns2),
                          TCPIP_IFCONFIG_UP);
          break;
        case TCPIP_CONNECTION_BUILDUP_DOWN:
          psaTCPIP_Config(0,0,0,TCPIP_IFCONFIG_DOWN);
          break;
                
        default:
          TRACE_ERROR("Error: Unknown build up state in psaTCPIP_config_dispatch()");
          return;  
      }
      break;

    case TCPIP_Configurated:
      if(tcpipShrdPrm.callback_function)
      {
        tcpipShrdPrm.callback_function(AT_CMPL) ;
      }
      break;
	     
    case TCPIP_Deconfiguration :
      psaTCPIP_Config(0,0,0,TCPIP_IFCONFIG_DOWN);
      break;
         
  	case TCPIP_Deconfigurated :
	    break;
	     
    case TCPIP_Deactivation :
      psaTCPIP_Shutdown_Req();         
      break;
         
    case TCPIP_Deactivated:    
      tcpipShrdPrm.connection_type = TCPIP_CONNECTION_TYPE_UNKNOWN;
      if(tcpipShrdPrm.callback_function)
      {
        tcpipShrdPrm.callback_function(AT_CMPL) ;
      }
      wap_state = Wap_Not_Init ;
      break ;

    default:
      TRACE_ERROR("Error: Unknown wap_state in psaTCPIP_config_dispatch()") ;
  }
#else
  ACI_ASSERT(FALSE);
#endif  
}


/********************** Callbacks, several ***********************/

/* TCP/IP activation callback for circuit-switched data, to be called
 * when activation is completed.
 */
void psaTCPIP_act_csd_callback(T_ACI_RETURN result)
{
  TRACE_FUNCTION("psaTCPIP_act_csd_callback()");

  if (!psaCC_ctbIsValid (tcpipShrdPrm.wap_call_id))
  {
    /* Avoid to dereference NULL */
    TRACE_ERROR ("Call table entry disappeared");
    return;
  }

  /*
   * activate RA connection: in case of failure clear call !
   */
  ccShrdPrm.datStat = DS_ACT_REQ;

  if(cmhRA_Activate((T_ACI_CMD_SRC)psaCC_ctb(tcpipShrdPrm.wap_call_id)->curSrc,
                    (T_ACI_AT_CMD)psaCC_ctb(tcpipShrdPrm.wap_call_id)->curCmd,
                    tcpipShrdPrm.wap_call_id)
      NEQ AT_EXCT)
  {
    TRACE_EVENT("RA ACTIVATION FAILURE -> DISC CALL");
    ccShrdPrm.datStat = DS_IDL ;
    psaCC_ctb(tcpipShrdPrm.wap_call_id)->nrmCs = MNCC_CAUSE_CALL_CLEAR ;
    psaCC_ClearCall (tcpipShrdPrm.wap_call_id);
  }
}


/* TCP/IP configuration callback for circuit-switched data, to be called
 * when configuration is completed.
 */
void psaTCPIP_conf_csd_callback(T_ACI_RETURN result)
{
  TRACE_FUNCTION("psaTCPIP_conf_csd_callback()") ;

  R_AT ( RAT_CONNECT, (T_ACI_CMD_SRC)tcpipShrdPrm.src_id )
    ( AT_CMD_NONE, -1, tcpipShrdPrm.wap_call_id, FALSE );
  if(is_gpf_tcpip_call()) {
    #ifdef FF_GPF_TCPIP
    T_DCM_STATUS_IND_MSG msg;
    msg.hdr.msg_id = DCM_NEXT_CMD_READY_MSG;
	  dcm_send_message(msg, DCM_SUB_WAIT_SATDN_CNF);
    #endif // #ifdef FF_GPF_TCPIP
  }
}


/* TCP/IP deactivation callback for circuit-switched data, to be called
 * when deactivation is completed.
 */
void psaTCPIP_deact_csd_callback(T_ACI_RETURN result)
{
  TRACE_FUNCTION("psaTCPIP_deact_csd_callback()") ;

  /*
   * deactivate L2R connection: 
   */
  if (cmhL2R_Deactivate() NEQ AT_EXCT)
  {
    TRACE_EVENT("L2R DEACTIVATION FAILURE ");
    if (psaCC_ctbIsValid (tcpipShrdPrm.wap_call_id)) /* To be sure */
      psaCC_ctb(tcpipShrdPrm.wap_call_id)->nrmCs = MNCC_CAUSE_CALL_CLEAR;
    psaCC_ClearCall (tcpipShrdPrm.wap_call_id);     /* Changed in OMAPS00049111 */
  }

  if(is_gpf_tcpip_call())
  {
#ifdef FF_GPF_TCPIP
    {
      T_DCM_STATUS_IND_MSG msg;
      msg.hdr.msg_id = DCM_NEXT_CMD_READY_MSG;
      dcm_send_message(msg, DCM_SUB_WAIT_SATH_CNF);
    }
#endif /* #ifdef FF_GPF_TCPIP */
  }
}

#endif /*defined(FF_WAP) OR defined(FF_GPF_TCPIP) */

/* EOF */