view src/g23m-gprs/sm/sm.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 :  3G PS
|  Module  :  SM
+-----------------------------------------------------------------------------
|             Copyright 2003 Texas Instruments.
|             All rights reserved. 
| 
|             This file is confidential and a trade secret of Texas 
|             Instruments .
|             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. 
+-----------------------------------------------------------------------------
| Purpose:    Utility functions implementation in the SM entity.
|             For design details, see:
|             8010.908 SM Detailed Specification
+---------------------------------------------------------------------------*/

/*==== DECLARATION CONTROL =================================================*/

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

#include <stdio.h>
#include "sm.h"

/*==== CONSTS ===============================================================*/

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

/*==== LOCALS ===============================================================*/

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

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

/*
+------------------------------------------------------------------------------
| Function    : sm_nsapi2nsapi_set
+------------------------------------------------------------------------------
| Description : Returns nsapi_set corresponding to the input NSAPI
|
| Parameters  : nsapi               - NSAPI to convert to nsapi_set
+------------------------------------------------------------------------------
*/
U16 sm_nsapi2nsapi_set(int /*@alt U8@*/ nsapi)
{
  return (U16)(1UL << (U8)nsapi);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_add_nsapi_to_nsapi_set
+------------------------------------------------------------------------------
| Description : Returns nsapi_set with nsapi added to it (1 << nsapi).
|
| Parameters  : nsapi               - NSAPI to add
|               nsapi_set           - nsapi_set to which to add NSAPI
+------------------------------------------------------------------------------
*/
U16 sm_add_nsapi_to_nsapi_set(int /*@alt U8@*/ nsapi, U16 nsapi_set)
{
  return (nsapi_set | sm_nsapi2nsapi_set(nsapi));
}

/*
+------------------------------------------------------------------------------
| Function    : sm_remove_nsapi_from_nsapi_set
+------------------------------------------------------------------------------
| Description : Returns nsapi_set with nsapi removed from it (1 << nsapi).
|
| Parameters  : nsapi               - NSAPI to remove
|               nsapi_set           - nsapi_set in which to remove NSAPI
+------------------------------------------------------------------------------
*/
U16 sm_remove_nsapi_from_nsapi_set(int /*@alt U8@*/ nsapi, U16 nsapi_set)
{
  return (nsapi_set & (0xffff ^ sm_nsapi2nsapi_set(nsapi)));
}

/*
+------------------------------------------------------------------------------
| Function    : sm_is_nsapi_in_nsapi_set
+------------------------------------------------------------------------------
| Description : Returns TRUE iff the input NSAPI (converted to nsapi_set) is
|               set in the input nsapi_set.
|
| Parameters  : nsapi               - NSAPI whose presence to check
|               nsapi_set           - nsapi_set to compare
+------------------------------------------------------------------------------
*/
BOOL sm_is_nsapi_in_nsapi_set(int /*@alt U8,U16@*/ nsapi, U16 nsapi_set)
{
  return ((nsapi_set & sm_nsapi2nsapi_set(nsapi)) != 0);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nsapi_to_index
+------------------------------------------------------------------------------
| Description : Returns array index corresponding to NSAPI (nsapi - 5)
|
| Parameters  : nsapi               - NSAPI value
+------------------------------------------------------------------------------
*/
U16 /*@alt int@*/ sm_nsapi_to_index(U16 /*@alt U8,int@*/nsapi)
{
  TRACE_ASSERT((T_NAS_nsapi)nsapi >= NAS_NSAPI_5 && nsapi <= NAS_NSAPI_15);
  return (nsapi - (U16)NAS_NSAPI_5);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_index_to_nsapi
+------------------------------------------------------------------------------
| Description : Returns nsapi value corresponding to array index (index + 5)
|
| Parameters  : index               - index value
+------------------------------------------------------------------------------
*/
U16 /*@alt int@*/ sm_index_to_nsapi(U16 /*@alt U8,int@*/index)
{
  TRACE_ASSERT(index < SM_MAX_NSAPI_OFFSET);
  return (index + (U16)NAS_NSAPI_5);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_get_pdp_context_status
+------------------------------------------------------------------------------
| Description : Get the network status of all NSAPIs.  A bit is set in the
|               nsapi_set, iff the context corresponding to the NSAPI is
|               not in network state INACTIVE.
|
| Parameters  : None
+------------------------------------------------------------------------------
*/
U16 sm_get_pdp_context_status(void)
{
  return sm_data.sm_context_activation_status;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_get_current_rat
+------------------------------------------------------------------------------
| Description : Returns the RAT in which SM is currently active
|
| Parameters  : None
+------------------------------------------------------------------------------
*/
T_PS_rat /*@alt U8@*/sm_get_current_rat(void)
{
  return sm_data.sm_current_rat;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_set_current_rat
+------------------------------------------------------------------------------
| Description : Sets the RAT in which SM is currently active
|
| Parameters  : rat                 - Active RAT (GSM / UMTS)
+------------------------------------------------------------------------------
*/
void sm_set_current_rat(T_PS_rat rat)
{
  if (rat == PS_RAT_GSM || rat == PS_RAT_UMTS_FDD) {
    sm_data.sm_current_rat = rat;
  } else {
    (void)TRACE_ERROR("Tried to set unknown RAT! (This is OK for EDGE)");
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_get_current_nw_release
+------------------------------------------------------------------------------
| Description : Returns the core network release of the network in which SM
|               is currently active
|
| Parameters  : None
+------------------------------------------------------------------------------
*/
T_PS_sgsn_rel /*@alt U8@*/ sm_get_current_nw_release(void)
{
  return sm_data.sm_current_nw_release;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_is_suspended
+------------------------------------------------------------------------------
| Description : Returns TRUE if SM is suspended, i.e. has received an
|               MMPM_SUSPEND_IND primitive from MM.
|
| Parameters  : None
+------------------------------------------------------------------------------
*/
BOOL sm_is_suspended(void)
{
  return sm_data.sm_suspended;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_is_attached
+------------------------------------------------------------------------------
| Description : Returns TRUE if SM is attached, i.e. has received an
|               MMPM_ATTACH_IND primitive from MM.
|
| Parameters  : None
+------------------------------------------------------------------------------
*/
BOOL sm_is_attached(void)
{
  return sm_data.sm_attached;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_is_secondary
+------------------------------------------------------------------------------
| Description : Returns TRUE if secondary flag is set for the context.
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
BOOL sm_is_secondary(struct T_SM_CONTEXT_DATA *context)
{
  return (context->flags & (U8)SM_CONTEXT_FLAG_SECONDARY_CONTEXT) != (U8)0;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_set_secondary
+------------------------------------------------------------------------------
| Description : Set secondary flag for the input context
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
void sm_set_secondary(struct T_SM_CONTEXT_DATA *context)
{
  context->flags |= (U8)SM_CONTEXT_FLAG_SECONDARY_CONTEXT;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_set_started_during_suspend
+------------------------------------------------------------------------------
| Description : Set started during suspend flag for the context
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
void sm_set_started_during_suspend(struct T_SM_CONTEXT_DATA *context)
{
  if (sm_is_suspended()) {
    context->flags |= (U8)SM_CONTEXT_FLAG_STARTED_DURING_SUSPEND;
  } else {
    context->flags &= 0xff ^ (U8)SM_CONTEXT_FLAG_STARTED_DURING_SUSPEND;
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_clear_started_during_suspend
+------------------------------------------------------------------------------
| Description : Clear started during suspend flag for the context
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
void sm_clear_started_during_suspend(struct T_SM_CONTEXT_DATA *context)
{
  context->flags &= 0xff ^ (U8)SM_CONTEXT_FLAG_STARTED_DURING_SUSPEND;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_is_started_during_suspend
+------------------------------------------------------------------------------
| Description : Return TRUE if started during suspend flag is set for the
|               context.
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
BOOL sm_is_started_during_suspend(struct T_SM_CONTEXT_DATA *context)
{
  return (context->flags & (U8)SM_CONTEXT_FLAG_STARTED_DURING_SUSPEND) != (U8)0;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_mark_context_for_deallocation
+------------------------------------------------------------------------------
| Description : Set pending deallocation flag for the context
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
void sm_mark_context_for_deallocation(struct T_SM_CONTEXT_DATA *context)
{
  context->flags |= (U8)SM_CONTEXT_FLAG_PENDING_DEALLOCATION;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_is_context_pending_deallocation
+------------------------------------------------------------------------------
| Description : Returns TRUE if pending deallocation flag is set for the context
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
BOOL sm_is_context_pending_deallocation(struct T_SM_CONTEXT_DATA *context)
{
  return (context->flags & (U8)SM_CONTEXT_FLAG_PENDING_DEALLOCATION) != (U8)0;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_set_context_pending_reactivation
+------------------------------------------------------------------------------
| Description : Set or clear pending reactivation flag for the context
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
void sm_set_context_pending_reactivation(struct T_SM_CONTEXT_DATA *context, BOOL flag)
{
  if (flag)
  {
    context->flags |= (U8)(U8)SM_CONTEXT_FLAG_PENDING_REACTIVATION;
  } else {
    context->flags &= 0xff ^ (U8)(U8)SM_CONTEXT_FLAG_PENDING_REACTIVATION;
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_is_context_pending_reactivation
+------------------------------------------------------------------------------
| Description : Returns TRUE if pending reactivation flag is set for the context
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
BOOL sm_is_context_pending_reactivation(struct T_SM_CONTEXT_DATA *context)
{
  return (context->flags & (U8)SM_CONTEXT_FLAG_PENDING_REACTIVATION) != (U8)0;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_is_aci_update_required
+------------------------------------------------------------------------------
| Description : Returns TRUE if one of the flags affecting the SMREG interface
|               have changed/are set.
|
| Parameters  : update_flags        - Update flags
+------------------------------------------------------------------------------
*/
BOOL sm_is_aci_update_required(T_SM_UPDATE_FLAGS update_flags)
{
  if ((int)(update_flags & SM_UPDATE_QOS)           != 0 ||
      (int)(update_flags & SM_UPDATE_QOS_DOWNGRADE) != 0 ||
      (int)(update_flags & SM_UPDATE_ADDRESS)       != 0 ||
      (int)(update_flags & SM_UPDATE_COMP_PARAMS)   != 0) {
    return TRUE;
  }
  return FALSE;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_is_user_plane_update_required
+------------------------------------------------------------------------------
| Description : Returns TRUE if one of the flags affecting the SM interface
|               have changed/are set.
|
| Parameters  : update_flags        - Update flags
+------------------------------------------------------------------------------
*/
BOOL sm_is_user_plane_update_required(T_SM_UPDATE_FLAGS update_flags)
{
  if ((int)(update_flags & SM_UPDATE_QOS)                 != 0 ||
      (int)(update_flags & SM_UPDATE_COMP_PARAMS)         != 0 ||
      (int)(update_flags & SM_UPDATE_SAPI_RADIO_PRIO_PFI) != 0) {
    return TRUE;
  }
  return FALSE;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_set_pfi_included
+------------------------------------------------------------------------------
| Description : Set PFI included flag for the context
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
void sm_set_pfi_included(struct T_SM_CONTEXT_DATA *context, BOOL flag)
{
  if (flag)
  {
    context->flags |= (U8)SM_CONTEXT_FLAG_PFI_PRESENT;
  } else {
    context->flags &= 0xff ^ (U8)SM_CONTEXT_FLAG_PFI_PRESENT;
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_is_pfi_included
+------------------------------------------------------------------------------
| Description : Return TRUE if PFI included flag is set for the context.
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
BOOL sm_is_pfi_included(struct T_SM_CONTEXT_DATA *context)
{
  return (context->flags & (U8)SM_CONTEXT_FLAG_PFI_PRESENT) != (U8)0;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_is_llc_sapi_valid
+------------------------------------------------------------------------------
| Description : Return TRUE if the LLC SAPI provided is valid, FALSE otherwise.
|
| Parameters  : llc_sapi            - LLC SAPI
|               ti                  - TI for context
+------------------------------------------------------------------------------
*/
BOOL sm_is_llc_sapi_valid(U8 llc_sapi, U8 ti)
{
  /* This check is only valid in non-UMTS-single mode configurations */
#if !defined(TI_UMTS) || defined(TI_DUAL_MODE)
  T_CAUSE_ps_cause          cause;

  if ( (llc_sapi == PS_SAPI_3) ||
       (llc_sapi == PS_SAPI_5) ||
       (llc_sapi == PS_SAPI_9) ||
       (llc_sapi == PS_SAPI_11) )
  {
    /* LLC SAPI is OK.  Return TRUE. */
    return TRUE;
  } else {
    /* LLC SAPI has a reserved value. Send a status message. */
    cause.ctrl_value       = CAUSE_is_from_nwsm;
    cause.value.nwsm_cause = (U16)CAUSE_NWSM_INVALID_MANDATORY_ELEMENT;
    send_msg_sm_status(ti, &cause);
    return FALSE;
  } 
#else
  /* In UMTS single mode, this check is disabled */
  return TRUE;
#endif
}

/*
+------------------------------------------------------------------------------
| Function    : sm_set_current_nw_release
+------------------------------------------------------------------------------
| Description : Sets the core network release of the network in which SM
|               is currently active
|
| Parameters  : sgsn_rel            - Network release (pre-R99 / R99)
+------------------------------------------------------------------------------
*/
void sm_set_current_nw_release(T_PS_sgsn_rel sgsn_rel)
{
  if (sgsn_rel == PS_SGSN_98_OLDER || sgsn_rel == PS_SGSN_99_ONWARDS) {
    sm_data.sm_current_nw_release = sgsn_rel;
  } 
  else { /*The Berlin way*/
    /*If SGSN release is unknown set the value to R98*/
    (void)TRACE_ERROR("Tried to set unknown core network release. \
                         Setting R97 as default !");
    sm_data.sm_current_nw_release = PS_SGSN_98_OLDER;
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_set_aci_cause
+------------------------------------------------------------------------------
| Description : Sets the cause value for a context. Used during retransmissions
|               etc.
|
| Parameters  : context             - context data
|               ctrl_cause          - cause originator
|               cause               - vause value
+------------------------------------------------------------------------------
*/
void sm_set_aci_cause(struct T_SM_CONTEXT_DATA *context,
		  T_CAUSE_ctrl_value ctrl_cause, U16 cause)
{
  (void)TRACE_EVENT_P2("sm_set_aci_cause(ctrl=%d, cause=%04x)", (int)ctrl_cause, cause);
  TRACE_ASSERT(context != NULL);
  /*lint -e613 (Possible use of null pointer 'context' in left argument to operator '->') */
  context->aci_cause.ctrl_value       = ctrl_cause;
  context->aci_cause.value.nwsm_cause = cause;
  /*lint +e613 (Possible use of null pointer 'context' in left argument to operator '->') */
}

/*
+------------------------------------------------------------------------------
| Function    : sm_get_aci_cause
+------------------------------------------------------------------------------
| Description : Gets the cause value for a context. Used during retransmissions
|               etc.
|
| Parameters  : context             - context data
+------------------------------------------------------------------------------
*/
/*@observer@*/
T_CAUSE_ps_cause *sm_get_aci_cause(struct T_SM_CONTEXT_DATA *context)
{
  TRACE_ASSERT(context != NULL);
  /*lint -e613 (Possible use of null pointer 'context' in left argument to operator '->') */
  return &context->aci_cause;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_set_nw_cause
+------------------------------------------------------------------------------
| Description : Sets the cause value for a context. Used during retransmissions
|               etc.
|
| Parameters  : context             - context data
|               ctrl_cause          - cause originator
|               cause               - vause value
+------------------------------------------------------------------------------
*/
void sm_set_nw_cause(struct T_SM_CONTEXT_DATA *context,
		  T_CAUSE_ctrl_value ctrl_cause, U16 cause)
{
  TRACE_ASSERT(context != NULL);
  /*lint -e613 (Possible use of null pointer 'context' in left argument to operator '->') */
  context->nw_cause.ctrl_value       = ctrl_cause;
  context->nw_cause.value.nwsm_cause = cause;
  /*lint +e613 (Possible use of null pointer 'context' in left argument to operator '->') */
}

/*
+------------------------------------------------------------------------------
| Function    : sm_get_nw_cause
+------------------------------------------------------------------------------
| Description : Gets the cause value for a context. Used during retransmissions
|               etc.
|
| Parameters  : context             - context data
+------------------------------------------------------------------------------
*/
/*@observer@*/
T_CAUSE_ps_cause *sm_get_nw_cause(struct T_SM_CONTEXT_DATA *context)
{ 
TRACE_ASSERT(context != NULL);
/*lint -e613 (Possible use of null pointer 'context' in left argument to operator '->') */
#ifdef DEBUG
  if (context->nw_cause.ctrl_value != CAUSE_is_from_nwsm &&
      context->nw_cause.ctrl_value != CAUSE_is_from_sm) {
    (void)TRACE_EVENT_P2("sm_get_nw_cause(): ERROR! Cause element not "
			 "initialized or not from SM (ctrl=%d, cause=%d)",
		   context->nw_cause.ctrl_value, context->nw_cause.value.nwsm_cause);
  }
#endif
  return &context->nw_cause;
/*lint +e613 (Possible use of null pointer 'context' in left argument to operator '->') */
}

/*==== END OF FILE ==========================================================*/