view src/g23m-gprs/sm/sm_dispatcher.c @ 263:b5e8dfd114a7

Switch_ON(): go into charging boot mode on either CHGSTS or CHGPRES If someone were to plug and then unplug a charger into a switched-off phone in an extremely brief "glitch" manner, we should do an automatic power-off on boot in this condition. When we were checking only CHGPRES in Switch_ON(), we would go into Misc boot state instead, which is undesirable. Now if we have a CHGSTS but not CHGPRES condition, we will go into charging boot mode, and FCBM will then do the automatic power-off upon detecting absence of the charger in its periodic polling.
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 14 May 2021 05:50:36 +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:    This module implements the process dispatcher
|             for the Session Management (SM) entity.
|             For design details, see:
|             8010.908 SM Detailed Specification
+---------------------------------------------------------------------------*/

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

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

#include "sm.h"
#include "sm_sequencer.h"

#include "sm_network_control.h"
#include "sm_aci_output_handler.h"
#include "sm_timer_handler.h"

#include "sm_dispatcher.h"

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

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

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

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

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_allocate_context
+------------------------------------------------------------------------------
| Description : Allocate memory for a context data structure and initialize
|               memory and state machines.  Returns address of data structure.
|
| Parameters  : nsapi               - NSAPI of context to allocate
+------------------------------------------------------------------------------
*/
/*@null@*/ /*@only@*/static struct T_SM_CONTEXT_DATA *
sm_disp_allocate_context(int /*@alt U8@*/ nsapi)
{
  struct T_SM_CONTEXT_DATA *context;

  context                = sm_allocate_context_data();

  if (context != NULL) {
    memset(context, 0, sizeof(struct T_SM_CONTEXT_DATA));

    context->nsapi       = nsapi;

    sm_context_control_init           (context);
    sm_context_deactivate_control_init(context);
    sm_network_control_init           (context);
    sm_user_plane_control_init        (context);
  }

  return context;
}

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

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_smreg_pdp_activate_req
+------------------------------------------------------------------------------
| Description : Dispatch SMREG_PDP_ACTIVATE_REQ
|
| Parameters  : prim        - received primitive
+------------------------------------------------------------------------------
*/
void sm_disp_smreg_pdp_activate_req(T_SMREG_PDP_ACTIVATE_REQ *prim)
{
  struct T_SM_CONTEXT_DATA *context;
  T_CAUSE_ps_cause          cause;
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_smreg_pdp_activate_req");
#endif


  if (!sm_is_attached() OR
     (sm_is_suspended() AND
     (sm_data.sm_suspend_cause EQ CAUSE_MM_LIMITED_SERVICE OR 
      sm_data.sm_suspend_cause EQ CAUSE_MM_NO_SERVICE)))
  {
    /*In case of limited service or no service, where GPRS is not present,
      SM should reject the request immediately T3380 rule is not followed.*/
      (void)TRACE_ERROR("PDP Activation rejected - limited service or no service. ");

      cause.ctrl_value     = CAUSE_is_from_nwsm;
      cause.value.sm_cause = (U16)CAUSE_NWSM_ACTIVATE_REJECTED_UNSPECIFIED;
      send_smreg_pdp_activate_rej(prim->nsapi, &cause);
      return;
  }


  /* If context was MT activated, context data already exists for the TI. */
  if (prim->ti != (U8)SM_TI_NONE) {
    context                = sm_extract_mt_context_data(prim->ti);

    if (context == NULL) {
      (void)TRACE_ERROR("Unable to find data structure allocated by MT activation request!");

      cause.ctrl_value     = CAUSE_is_from_nwsm;
      cause.value.sm_cause = (U16)CAUSE_NWSM_INVALID_TI;
      send_smreg_pdp_activate_rej(prim->nsapi, &cause);
      return;
    } else {
      context->nsapi       = prim->nsapi;
    }
    TRACE_ASSERT(context != NULL);
  } else {
    if (sm_get_context_data_from_nsapi(prim->nsapi) != NULL) {
      /* Context already exists: Reject */
      (void)TRACE_EVENT_P1("ERROR: Context already activated on NSAPI %d; "
			   "activation rejected...", (int)prim->nsapi);
      cause.ctrl_value     = CAUSE_is_from_nwsm;
      cause.value.sm_cause = (U16)CAUSE_NWSM_NSAPI_IN_USE;
      send_smreg_pdp_activate_rej(prim->nsapi, &cause);
      return;
    }
    /* MO activation: Allocate new structure */
    context = sm_disp_allocate_context(prim->nsapi);

    if (context == NULL) {
      (void)TRACE_ERROR("Unable to allocate data structure for new context!");
      return;
    }
  } 

  /*If this is not done comp params will not be passed to UPM*/
  if ( (prim->comp_params.hcomp  != NAS_HCOMP_OFF) || 
       (prim->comp_params.dcomp  != NAS_DCOMP_OFF) )
  {
    (void)TRACE_EVENT("Compression parameters included ");
    context->flags |= (U8)SM_CONTEXT_FLAG_COMP_PARAMS;
    if(prim->comp_params.msid == 0){
      prim->comp_params.msid = 16;
    }
  } else {
    (void)TRACE_EVENT("Compression parameters not included ");
  }

  /* Set SM_CONTEXT_FLAG_STARTED_DURING_SUSPEND flag according to suspend status */
  sm_set_started_during_suspend(context);

  sm_assign_context_data_to_nsapi(context, prim->nsapi);

  context = sm_get_context_data_from_nsapi(prim->nsapi);

  sm_context_control(context, SM_P_SMREG_PDP_ACTIVATE_REQ, prim);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_smreg_pdp_activate_sec_req
+------------------------------------------------------------------------------
| Description : Dispatch SMREG_PDP_ACTIVATE_SEC_REQ
|
| Parameters  : prim        - received primitive
+------------------------------------------------------------------------------
*/
void sm_disp_smreg_pdp_activate_sec_req(T_SMREG_PDP_ACTIVATE_SEC_REQ *prim)
{
  struct T_SM_CONTEXT_DATA *context;
  T_CAUSE_ps_cause          cause;
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_smreg_pdp_activate_req");
#endif

  if (sm_get_context_data_from_nsapi(prim->nsapi) != NULL) {
    /* Context already exists: Reject */
    (void)TRACE_EVENT_P1("ERROR: Context already activated on NSAPI %d; "
			 "activation rejected...", (int)prim->nsapi);
    cause.ctrl_value     = CAUSE_is_from_nwsm;
    cause.value.sm_cause = (U16)CAUSE_NWSM_NSAPI_IN_USE;
    send_smreg_pdp_activate_sec_rej(prim->nsapi, &cause);
    return;
  }

  if (sm_get_current_nw_release() == PS_SGSN_98_OLDER) {
    /* Secondary context activation is an R99-only procedure: Fail when in pre-R99! */
    (void)TRACE_ERROR("R99 procedure rejected while active in pre-R99 network!");
    cause.ctrl_value     = CAUSE_is_from_sm;
    cause.value.sm_cause = (U16)CAUSE_SM_R99_PROCEDURE_REJECTED_IN_R97;
    send_smreg_pdp_activate_sec_rej(prim->nsapi, &cause);
    return;
  }

  if (sm_get_context_data_from_nsapi(prim->pri_nsapi) == NULL) {
    (void)TRACE_ERROR("sm_disp_smreg_pdp_activate_req: Primary context referenced in primitive does not exist!");
    cause.ctrl_value     = CAUSE_is_from_nwsm;
    cause.value.sm_cause = (U16)CAUSE_NWSM_UNKNOWN_LINKED_TI;
    send_smreg_pdp_activate_sec_rej(prim->nsapi, &cause);
    return;
  }

  /* Allocate new context data structure */
  context = sm_disp_allocate_context(prim->nsapi);

  if (context == NULL) {
    (void)TRACE_ERROR("Unable to allocate data structure for new context!");
    return;
  }

  sm_set_secondary(context);
  /* Set SM_CONTEXT_FLAG_STARTED_DURING_SUSPEND flag according to suspend status */
  sm_set_started_during_suspend(context);

  sm_assign_context_data_to_nsapi(context, prim->nsapi);

  context = sm_get_context_data_from_nsapi(prim->nsapi);

  sm_context_control(context, SM_P_SMREG_PDP_ACTIVATE_SEC_REQ, prim);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_smreg_pdp_deactivate_req
+------------------------------------------------------------------------------
| Description : Dispatch SMREG_PDP_DEACTIVATE_REQ
|
| Parameters  : prim        - received primitive
+------------------------------------------------------------------------------
*/
void sm_disp_smreg_pdp_activate_rej_res(T_SMREG_PDP_ACTIVATE_REJ_RES *prim)
{
  struct T_SM_CONTEXT_DATA *context;
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_smreg_pdp_activate_rej_res");
#endif

  /* Context was MT activated, context data already exists for the TI. */
  context                = sm_extract_mt_context_data(prim->ti);

  if (context == NULL) {
    (void)TRACE_ERROR("Unable to find data structure allocated by MT activation request!");
    return;
  }

  sm_context_control(context, SM_P_SMREG_PDP_ACTIVATE_REJ_RES, prim);

  /* Free context data */
  sm_free_context_data(context);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_smreg_pdp_deactivate_req
+------------------------------------------------------------------------------
| Description : Dispatch SMREG_PDP_DEACTIVATE_REQ
|
| Parameters  : prim        - received primitive
+------------------------------------------------------------------------------
*/
void sm_disp_smreg_pdp_deactivate_req(T_SMREG_PDP_DEACTIVATE_REQ *prim)
{
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_smreg_pdp_deactivate_req");
#endif

  /* Forward to Sequencer */
  sm_sequencer(SM_P_SMREG_PDP_DEACTIVATE_REQ, prim);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_smreg_pdp_modify_req
+------------------------------------------------------------------------------
| Description : Dispatch SMREG_PDP_MODIFY_REQ
|
| Parameters  : prim        - received primitive
+------------------------------------------------------------------------------
*/
void sm_disp_smreg_pdp_modify_req(T_SMREG_PDP_MODIFY_REQ *prim)
{
  struct T_SM_CONTEXT_DATA *context;
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_smreg_pdp_modify_req");
#endif

  context = sm_get_context_data_from_nsapi(prim->nsapi);

  if (context == NULL) {
    T_CAUSE_ps_cause          cause;

    (void)TRACE_ERROR("Non-existing context!");

    cause.ctrl_value     = CAUSE_is_from_sm;
    cause.value.sm_cause = (U16)CAUSE_SM_INVALID_NSAPI;
    send_smreg_pdp_modify_rej(prim->nsapi, &cause);
  } else if (sm_get_current_nw_release() == PS_SGSN_98_OLDER) {
    /* MO Modify is an R99-only procedure: Fail when in pre-R99! */
    T_CAUSE_ps_cause     cause;

    (void)TRACE_ERROR("R99 procedure rejected while active in pre-R99 network!");
    cause.ctrl_value     = CAUSE_is_from_sm;
    cause.value.sm_cause = (U16)CAUSE_SM_R99_PROCEDURE_REJECTED_IN_R97;
    send_smreg_pdp_modify_rej(context->nsapi, &cause);
  } else { /* context != NULL */
    /* Set SM_CONTEXT_FLAG_STARTED_DURING_SUSPEND flag according to suspend status */
    sm_set_started_during_suspend(context);

    /* Forward to Context Control */
    sm_context_control(context, SM_P_SMREG_PDP_MODIFY_REQ, prim);
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_sm_activate_res
+------------------------------------------------------------------------------
| Description : Dispatch SM_ACTIVATE_RES
|
| Parameters  : prim        - received primitive
+------------------------------------------------------------------------------
*/
void sm_disp_sm_activate_res(T_SM_ACTIVATE_RES *prim)
{
  struct T_SM_CONTEXT_DATA *context;
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_sm_activate_res");
#endif

  context = sm_get_context_data_from_nsapi(prim->nsapi);

  if (context == NULL) {
    (void)TRACE_ERROR("Non-existing context!");
    return;
  }

  /* Forward to User Plane Control */
  sm_user_plane_control(context, SM_P_SM_ACTIVATE_RES, prim);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_sm_deactivate_res
+------------------------------------------------------------------------------
| Description : Dispatch SM_DEACTIVATE_RES
|
| Parameters  : prim        - received primitive
+------------------------------------------------------------------------------
*/
void sm_disp_sm_deactivate_res(T_SM_DEACTIVATE_RES *prim)
{
  int                       nsapi;
  struct T_SM_CONTEXT_DATA *context;
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_sm_deactivate_res");
#endif

  for (nsapi = (int)NAS_NSAPI_5; nsapi < NAS_SIZE_NSAPI; nsapi++) {
    if (sm_is_nsapi_in_nsapi_set(nsapi, prim->nsapi_set)) {
      context = sm_get_context_data_from_nsapi(nsapi);

      /* Ignore non-existing contexts */
      if (context == NULL) {
	continue;
      }

      /* Forward to User Plane Control */
      sm_user_plane_control(context, SM_P_SM_DEACTIVATE_RES, prim);

      /* If SM_DEACTIVATE_RES completed deactivation, free context data */
      if (sm_is_context_pending_deallocation(context)) {
	sm_free_context_data_by_nsapi(context->nsapi);
      }
    }
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_sm_modify_res
+------------------------------------------------------------------------------
| Description : Dispatch SM_MODIFY_RES
|
| Parameters  : prim        - received primitive
+------------------------------------------------------------------------------
*/
void sm_disp_sm_modify_res(T_SM_MODIFY_RES *prim)
{
  struct T_SM_CONTEXT_DATA *context;
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_sm_modify_res");
#endif

  context = sm_get_context_data_from_nsapi(prim->nsapi);

  if (context == NULL) {
    (void)TRACE_ERROR("Non-existing context!");
    return;
  }

  /* Forward to User Plane Control */
  sm_user_plane_control(context, SM_P_SM_MODIFY_RES, prim);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_sm_status_req
+------------------------------------------------------------------------------
| Description : Dispatch SM_STATUS_REQ
|
| Parameters  : prim        - received primitive
+------------------------------------------------------------------------------
*/
void sm_disp_sm_status_req(T_SM_STATUS_REQ *prim)
{
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_sm_status_req");
#endif

  /* Forward to Sequencer */
  sm_sequencer(SM_P_SM_STATUS_REQ, prim);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_mmpm_attach_ind
+------------------------------------------------------------------------------
| Description : Dispatch MMPM_ATTACH_IND
|
| Parameters  : prim        - received primitive
+------------------------------------------------------------------------------
*/
void sm_disp_mmpm_attach_ind(T_MMPM_ATTACH_IND *prim)
{
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_mmpm_attach_ind");
#endif

  sm_data.sm_attached = TRUE;

  /* Forward to Sequencer */
  sm_sequencer(SM_P_MMPM_ATTACH_IND, prim);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_mmpm_detach_ind
+------------------------------------------------------------------------------
| Description : Dispatch MMPM_DETACH_IND
|
| Parameters  : prim        - received primitive
+------------------------------------------------------------------------------
*/
void sm_disp_mmpm_detach_ind(T_MMPM_DETACH_IND *prim)
{
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_mmpm_detach_ind");
#endif

  sm_data.sm_attached = FALSE;

  /* Forward to Sequencer */
  sm_sequencer(SM_P_MMPM_DETACH_IND, prim);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_mmpm_suspend_ind
+------------------------------------------------------------------------------
| Description : Dispatch MMPM_SUSPEND_IND
|
| Parameters  : mm_suspend_ind              - received primitive
+------------------------------------------------------------------------------
*/
void sm_disp_mmpm_suspend_ind(/*@unused@*/ T_MMPM_SUSPEND_IND *prim)
{
  int                       nsapi;
  struct T_SM_CONTEXT_DATA *context;
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_mmpm_suspend_ind");
#endif
  sm_data.sm_suspended = TRUE;
  sm_data.sm_suspend_cause = prim->ps_cause.value.mm_cause;

  for (nsapi = (int)NAS_NSAPI_5; nsapi < NAS_SIZE_NSAPI; nsapi++) {
    context = sm_get_context_data_from_nsapi(nsapi);
    if (context != NULL) {
      sm_network_control(context, SM_P_MMPM_SUSPEND_IND, NULL);
    }
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_mmpm_resume_ind
+------------------------------------------------------------------------------
| Description : Dispatch MMPM_RESUME_IND
|
| Parameters  : mm_resume_ind               - received primitive
+------------------------------------------------------------------------------
*/
void sm_disp_mmpm_resume_ind(/*@unused@*/ T_MMPM_RESUME_IND *prim)
{
  int                       nsapi;
  struct T_SM_CONTEXT_DATA *context;
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_mmpm_resume_ind");
#endif

  sm_data.sm_suspended = FALSE;
  sm_data.sm_suspend_cause = CAUSE_MM_SUCCESS;

  for (nsapi = (int)NAS_NSAPI_5; nsapi < NAS_SIZE_NSAPI; nsapi++) {
    context = sm_get_context_data_from_nsapi(nsapi);
    if (context != NULL) {
      sm_network_control(context, SM_P_MMPM_RESUME_IND, NULL);
    }
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_disp_pei_timeout
+------------------------------------------------------------------------------
| Description : Dispatch pei_timeout
|
| Parameters  : index  - system timer index (index into sm_context_array)
+------------------------------------------------------------------------------
*/
void sm_disp_pei_timeout(U16 index)
{
  int                       nsapi;
  struct T_SM_CONTEXT_DATA *context;
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_disp_pei_timeout");
#endif

  if (index > (U16)SM_MAX_NSAPI_OFFSET) {
    (void)TRACE_ERROR("Invalid timer index received!");
    return;
  }

  nsapi = sm_index_to_nsapi((U8)index);

  context = sm_get_context_data_from_nsapi(nsapi);

  if (context == NULL) {
    (void)TRACE_EVENT_P1("Warning!  Received timeout on non-existing NSAPI #%d; ignored...", nsapi);
    return;
  }

  if ((T_SM_TIMER_TYPE)context->active_timer == SM_TIMER_NONE) {
    (void)TRACE_EVENT_P1("Warning!  Received timeout on NSAPI #%d, which has no active timer; ignored...", nsapi);
    return;
  }

  if (context->timeouts == (U8)0) {
    (void)TRACE_EVENT_P1("Warning!  Received timeout on NSAPI #%d, which has no remaining timeouts; ignored...", nsapi);
    return;
  }

  /* Decrement remaining timeouts */
  context->timeouts -= (U8)1;

  /* Check remaining timeouts */
  if (context->timeouts > (U8)0) {
    T_SM_NETWORK_CONTROL_EVENT  event;
    /* More timeouts remaining - restart timer */
    sm_timer_restart(context);

    /* Inform Network Control of the timeout */
    switch (context->active_timer) {
    case SM_TIMER_T3380:   event = SM_T_T3380;  break;
    case SM_TIMER_T3381:   event = SM_T_T3381;  break;
    case SM_TIMER_T3390:   event = SM_T_T3390;  break;
    default:               return;
    }
    sm_network_control(context, event, NULL);
  } else {
    T_SM_NETWORK_CONTROL_EVENT  event;
    /* No timeouts remaining - Inform Network Control of the timer expiry */
    switch (context->active_timer) {
    case SM_TIMER_T3380:   event = SM_T_T3380_MAX;  break;
    case SM_TIMER_T3381:   event = SM_T_T3381_MAX;  break;
    case SM_TIMER_T3390:   event = SM_T_T3390_MAX;  break;
    default:               return;
    }
    sm_network_control(context, event, NULL);
  } /* if */ 

  /* Deallocate context if it was marked for deactivation due to T3390 max 
   * This change is separately taken from TI DK. Context data is cleaned up 
   * after deactivation due to max T3390 expiry. If this is not done the next
   * context activation on the same nsapi will fail.
   */
  if (sm_is_context_pending_deallocation(context)) {
    sm_free_context_data_by_nsapi(context->nsapi);
  }
}

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