view src/g23m-gprs/sm/sm_network_control.c @ 508:61f878c011b0

pseudo-modem keepalive: poll interval reduced to 5 s on C1xx and 10 s for USB
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 25 Jun 2018 06:20:23 +0000
parents 219afcfc6250
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:    Network Control state machine implementation in the SM entity.
|             For design details, see:
|             8010.908 SM Detailed Specification
+---------------------------------------------------------------------------*/

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

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

#include "sm.h"

#include "sm_network_control.h"
#include "sm_context_control.h"

#include "sm_mm_output_handler.h"

#include "sm_qos.h"
#include "sm_tft.h"
#include "sm_timer_handler.h"

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

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

typedef void (*T_SM_NETWORK_CONTROL_TRANSITION_FUNC)(struct T_SM_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);

typedef struct {
#ifdef DEBUG
  T_SM_NETWORK_CONTROL_EVENT            event;
#endif /* DEBUG */
  T_SM_NETWORK_CONTROL_TRANSITION_FUNC  func;
} T_SM_NETWORK_CONTROL_TRANSITION;

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

static void state_event_error(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void ignored          (struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void message_incompatible_with_state(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void message_for_invalid_ti(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);

/* Handler functions for internal events */
static void handle_activate_primary(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_activate_secondary(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_request_activation_reject(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_modify_in_S4(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_deactivate_in_S0(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_deactivate_during_activation(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_deactivate_during_modification(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_deactivate_in_S4(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_deactivate_local(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);

/* Handler functions for incoming air interface messages */
static void handle_activate_pdp_context_accept(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_activate_pdp_context_reject(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_activate_secondary_pdp_context_accept(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_activate_secondary_pdp_context_reject(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_request_pdp_context_activation_in_S0(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_request_pdp_context_activation_in_S1(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_request_pdp_context_activation_in_S4(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_modify_pdp_context_request_in_S3(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_modify_pdp_context_request_in_S4(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_modify_pdp_context_request_in_S5(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_modify_pdp_context_request_in_S6(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_modify_pdp_context_accept_in_S3(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_modify_pdp_context_accept_in_S5(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_modify_pdp_context_accept_in_S6(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_modify_pdp_context_reject_in_S3(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_modify_pdp_context_reject_in_S5(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_modify_pdp_context_reject_in_S6(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_deactivate_pdp_context_request_while_active(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_deactivate_pdp_context_request_while_deactivating(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_deactivate_pdp_context_accept(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
/* Handler functions for timer timeouts */
static void handle_T3380(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_T3380_max  (struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_T3381      (struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_T3381_max_in_S3(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_T3381_max_in_S5(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_T3381_max_in_S6(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_T3390      (struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_T3390_max  (struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
/* Handler functions for incoming primitives */
static void handle_mmpm_suspend_ind(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);
static void handle_mmpm_resume_ind(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data);

/***********************************************************************
 * State/Transition Table
 */
static const T_SM_NETWORK_CONTROL_TRANSITION
transition[SM_NETWORK_CONTROL_NUMBER_OF_STATES][SM_NETWORK_CONTROL_NUMBER_OF_EVENTS] =
{
  {  /* S0: SM NETWORK DEACTIVATED */
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_ACCEPT,           message_for_invalid_ti),
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_REJECT,           message_for_invalid_ti),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_ACCEPT, message_for_invalid_ti),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_REJECT, message_for_invalid_ti),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_REQUEST,        state_event_error),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_ACCEPT,         state_event_error),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REQUEST,            message_for_invalid_ti),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_ACCEPT,             message_for_invalid_ti),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REJECT,             message_for_invalid_ti),
    M_TRANSITION(SM_M_REQUEST_PDP_CONTEXT_ACTIVATION,        handle_request_pdp_context_activation_in_S0),
    M_TRANSITION(SM_M_SM_STATUS,                             state_event_error),
    M_TRANSITION(SM_P_MMPM_RESUME_IND,                       ignored),
    M_TRANSITION(SM_P_MMPM_SUSPEND_IND,                      handle_mmpm_suspend_ind),
    M_TRANSITION(SM_T_T3380,                                 state_event_error),
    M_TRANSITION(SM_T_T3380_MAX,                             state_event_error),
    M_TRANSITION(SM_T_T3381,                                 state_event_error),
    M_TRANSITION(SM_T_T3381_MAX,                             state_event_error),
    M_TRANSITION(SM_T_T3390,                                 state_event_error),
    M_TRANSITION(SM_T_T3390_MAX,                             state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_PRIMARY,              handle_activate_primary),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_SECONDARY,            handle_activate_secondary),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE_LOCAL,              handle_deactivate_local),
    M_TRANSITION(SM_I_NETWORK_MODIFY,                        state_event_error),
    M_TRANSITION(SM_I_NETWORK_REQUEST_ACTIVATION_REJECT,     handle_request_activation_reject),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE,                    handle_deactivate_in_S0)
  },
  {  /* S1: SM NETWORK ACTIVATING PRIMARY */
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_ACCEPT,           handle_activate_pdp_context_accept),
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_REJECT,           handle_activate_pdp_context_reject),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_ACCEPT, message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_REJECT, message_incompatible_with_state),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_REQUEST,        handle_deactivate_pdp_context_request_while_active),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_ACCEPT,         message_incompatible_with_state),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REQUEST,            message_incompatible_with_state),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_ACCEPT,             message_incompatible_with_state),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REJECT,             message_incompatible_with_state),
    M_TRANSITION(SM_M_REQUEST_PDP_CONTEXT_ACTIVATION,        handle_request_pdp_context_activation_in_S1),
    M_TRANSITION(SM_M_SM_STATUS,                             state_event_error),
    M_TRANSITION(SM_P_MMPM_RESUME_IND,                       handle_mmpm_resume_ind),
    M_TRANSITION(SM_P_MMPM_SUSPEND_IND,                      handle_mmpm_suspend_ind),
    M_TRANSITION(SM_T_T3380,                                 handle_T3380),
    M_TRANSITION(SM_T_T3380_MAX,                             handle_T3380_max),
    M_TRANSITION(SM_T_T3381,                                 state_event_error),
    M_TRANSITION(SM_T_T3381_MAX,                             state_event_error),
    M_TRANSITION(SM_T_T3390,                                 state_event_error),
    M_TRANSITION(SM_T_T3390_MAX,                             state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_PRIMARY,              state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_SECONDARY,            state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE_LOCAL,              handle_deactivate_local),
    M_TRANSITION(SM_I_NETWORK_MODIFY,                        state_event_error),
    M_TRANSITION(SM_I_NETWORK_REQUEST_ACTIVATION_REJECT,     state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE,                    handle_deactivate_during_activation)
  },
  {  /* S2: SM NETWORK ACTIVATING SECONDARY */
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_ACCEPT,           message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_REJECT,           message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_ACCEPT, handle_activate_secondary_pdp_context_accept),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_REJECT, handle_activate_secondary_pdp_context_reject),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_REQUEST,        handle_deactivate_pdp_context_request_while_active),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_ACCEPT,         message_incompatible_with_state),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REQUEST,            message_incompatible_with_state),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_ACCEPT,             message_incompatible_with_state),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REJECT,             message_incompatible_with_state),
    M_TRANSITION(SM_M_REQUEST_PDP_CONTEXT_ACTIVATION,        message_incompatible_with_state),
    M_TRANSITION(SM_M_SM_STATUS,                             state_event_error),
    M_TRANSITION(SM_P_MMPM_RESUME_IND,                       handle_mmpm_resume_ind),
    M_TRANSITION(SM_P_MMPM_SUSPEND_IND,                      handle_mmpm_suspend_ind),
    M_TRANSITION(SM_T_T3380,                                 handle_T3380),
    M_TRANSITION(SM_T_T3380_MAX,                             handle_T3380_max),
    M_TRANSITION(SM_T_T3381,                                 state_event_error),
    M_TRANSITION(SM_T_T3381_MAX,                             state_event_error),
    M_TRANSITION(SM_T_T3390,                                 state_event_error),
    M_TRANSITION(SM_T_T3390_MAX,                             state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_PRIMARY,              state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_SECONDARY,            state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE_LOCAL,              handle_deactivate_local),
    M_TRANSITION(SM_I_NETWORK_MODIFY,                        state_event_error),
    M_TRANSITION(SM_I_NETWORK_REQUEST_ACTIVATION_REJECT,     state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE,                    handle_deactivate_during_activation)
  },
  {  /* S3: SM NETWORK ACTIVATING ADDING TFTS */
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_ACCEPT,           message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_REJECT,           message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_ACCEPT, message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_REJECT, message_incompatible_with_state),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_REQUEST,        handle_deactivate_pdp_context_request_while_active),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_ACCEPT,         message_incompatible_with_state),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REQUEST,            handle_modify_pdp_context_request_in_S3),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_ACCEPT,             handle_modify_pdp_context_accept_in_S3),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REJECT,             handle_modify_pdp_context_reject_in_S3),
    M_TRANSITION(SM_M_REQUEST_PDP_CONTEXT_ACTIVATION,        message_incompatible_with_state),
    M_TRANSITION(SM_M_SM_STATUS,                             state_event_error),
    M_TRANSITION(SM_P_MMPM_RESUME_IND,                       handle_mmpm_resume_ind),
    M_TRANSITION(SM_P_MMPM_SUSPEND_IND,                      handle_mmpm_suspend_ind),
    M_TRANSITION(SM_T_T3380,                                 state_event_error),
    M_TRANSITION(SM_T_T3380_MAX,                             state_event_error),
    M_TRANSITION(SM_T_T3381,                                 handle_T3381),
    M_TRANSITION(SM_T_T3381_MAX,                             handle_T3381_max_in_S3),
    M_TRANSITION(SM_T_T3390,                                 state_event_error),
    M_TRANSITION(SM_T_T3390_MAX,                             state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_PRIMARY,              state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_SECONDARY,            state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE_LOCAL,              handle_deactivate_local),
    M_TRANSITION(SM_I_NETWORK_MODIFY,                        state_event_error),
    M_TRANSITION(SM_I_NETWORK_REQUEST_ACTIVATION_REJECT,     state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE,                    handle_deactivate_during_modification)
  },
  {  /* S4: SM NETWORK ACTIVATED */
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_ACCEPT,           message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_REJECT,           message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_ACCEPT, message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_REJECT, message_incompatible_with_state),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_REQUEST,        handle_deactivate_pdp_context_request_while_active),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_ACCEPT,         message_incompatible_with_state),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REQUEST,            handle_modify_pdp_context_request_in_S4),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_ACCEPT,             message_incompatible_with_state),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REJECT,             message_incompatible_with_state),
    M_TRANSITION(SM_M_REQUEST_PDP_CONTEXT_ACTIVATION,        handle_request_pdp_context_activation_in_S4),
    M_TRANSITION(SM_M_SM_STATUS,                             state_event_error),
    M_TRANSITION(SM_P_MMPM_RESUME_IND,                       ignored),
    M_TRANSITION(SM_P_MMPM_SUSPEND_IND,                      handle_mmpm_suspend_ind),
    M_TRANSITION(SM_T_T3380,                                 state_event_error),
    M_TRANSITION(SM_T_T3380_MAX,                             state_event_error),
    M_TRANSITION(SM_T_T3381,                                 state_event_error),
    M_TRANSITION(SM_T_T3381_MAX,                             state_event_error),
    M_TRANSITION(SM_T_T3390,                                 state_event_error),
    M_TRANSITION(SM_T_T3390_MAX,                             state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_PRIMARY,              state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_SECONDARY,            state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE_LOCAL,              handle_deactivate_local),
    M_TRANSITION(SM_I_NETWORK_MODIFY,                        handle_modify_in_S4),
    M_TRANSITION(SM_I_NETWORK_REQUEST_ACTIVATION_REJECT,     state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE,                    handle_deactivate_in_S4)
  },
  {  /* S5: SM NETWORK MODIFYING */
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_ACCEPT,           message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_REJECT,           message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_ACCEPT, message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_REJECT, message_incompatible_with_state),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_REQUEST,        handle_deactivate_pdp_context_request_while_active),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_ACCEPT,         message_incompatible_with_state),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REQUEST,            handle_modify_pdp_context_request_in_S5),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_ACCEPT,             handle_modify_pdp_context_accept_in_S5),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REJECT,             handle_modify_pdp_context_reject_in_S5),
    M_TRANSITION(SM_M_REQUEST_PDP_CONTEXT_ACTIVATION,        message_incompatible_with_state),
    M_TRANSITION(SM_M_SM_STATUS,                             state_event_error),
    M_TRANSITION(SM_P_MMPM_RESUME_IND,                       handle_mmpm_resume_ind),
    M_TRANSITION(SM_P_MMPM_SUSPEND_IND,                      handle_mmpm_suspend_ind),
    M_TRANSITION(SM_T_T3380,                                 state_event_error),
    M_TRANSITION(SM_T_T3380_MAX,                             state_event_error),
    M_TRANSITION(SM_T_T3381,                                 handle_T3381),
    M_TRANSITION(SM_T_T3381_MAX,                             handle_T3381_max_in_S5),
    M_TRANSITION(SM_T_T3390,                                 state_event_error),
    M_TRANSITION(SM_T_T3390_MAX,                             state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_PRIMARY,              state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_SECONDARY,            state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE_LOCAL,              handle_deactivate_local),
    M_TRANSITION(SM_I_NETWORK_MODIFY,                        state_event_error),
    M_TRANSITION(SM_I_NETWORK_REQUEST_ACTIVATION_REJECT,     state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE,                    handle_deactivate_during_modification)
  },
  {  /* S6: SM NETWORK MODIFYING ADDITIONAL TFTS */
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_ACCEPT,           message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_REJECT,           message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_ACCEPT, message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_REJECT, message_incompatible_with_state),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_REQUEST,        handle_deactivate_pdp_context_request_while_active),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_ACCEPT,         message_incompatible_with_state),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REQUEST,            handle_modify_pdp_context_request_in_S6),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_ACCEPT,             handle_modify_pdp_context_accept_in_S6),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REJECT,             handle_modify_pdp_context_reject_in_S6),
    M_TRANSITION(SM_M_REQUEST_PDP_CONTEXT_ACTIVATION,        message_incompatible_with_state),
    M_TRANSITION(SM_M_SM_STATUS,                             state_event_error),
    M_TRANSITION(SM_P_MMPM_RESUME_IND,                       handle_mmpm_resume_ind),
    M_TRANSITION(SM_P_MMPM_SUSPEND_IND,                      handle_mmpm_suspend_ind),
    M_TRANSITION(SM_T_T3380,                                 state_event_error),
    M_TRANSITION(SM_T_T3380_MAX,                             state_event_error),
    M_TRANSITION(SM_T_T3381,                                 handle_T3381),
    M_TRANSITION(SM_T_T3381_MAX,                             handle_T3381_max_in_S6),
    M_TRANSITION(SM_T_T3390,                                 state_event_error),
    M_TRANSITION(SM_T_T3390_MAX,                             state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_PRIMARY,              state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_SECONDARY,            state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE_LOCAL,              handle_deactivate_local),
    M_TRANSITION(SM_I_NETWORK_MODIFY,                        state_event_error),
    M_TRANSITION(SM_I_NETWORK_REQUEST_ACTIVATION_REJECT,     state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE,                    handle_deactivate_during_modification)
  },
  {  /* S7: SM NETWORK DEACTIVATING */
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_ACCEPT,           message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_PDP_CONTEXT_REJECT,           message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_ACCEPT, message_incompatible_with_state),
    M_TRANSITION(SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_REJECT, message_incompatible_with_state),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_REQUEST,        handle_deactivate_pdp_context_request_while_deactivating),
    M_TRANSITION(SM_M_DEACTIVATE_PDP_CONTEXT_ACCEPT,         handle_deactivate_pdp_context_accept),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REQUEST,            message_incompatible_with_state),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_ACCEPT,             message_incompatible_with_state),
    M_TRANSITION(SM_M_MODIFY_PDP_CONTEXT_REJECT,             message_incompatible_with_state),
    M_TRANSITION(SM_M_REQUEST_PDP_CONTEXT_ACTIVATION,        message_incompatible_with_state),
    M_TRANSITION(SM_M_SM_STATUS,                             state_event_error),
    M_TRANSITION(SM_P_MMPM_RESUME_IND,                       handle_mmpm_resume_ind),
    M_TRANSITION(SM_P_MMPM_SUSPEND_IND,                      handle_mmpm_suspend_ind),
    M_TRANSITION(SM_T_T3380,                                 state_event_error),
    M_TRANSITION(SM_T_T3380_MAX,                             state_event_error),
    M_TRANSITION(SM_T_T3381,                                 state_event_error),
    M_TRANSITION(SM_T_T3381_MAX,                             state_event_error),
    M_TRANSITION(SM_T_T3390,                                 handle_T3390),
    M_TRANSITION(SM_T_T3390_MAX,                             handle_T3390_max),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_PRIMARY,              state_event_error),
    M_TRANSITION(SM_I_NETWORK_ACTIVATE_SECONDARY,            state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE_LOCAL,              handle_deactivate_local),
    M_TRANSITION(SM_I_NETWORK_MODIFY,                        state_event_error),
    M_TRANSITION(SM_I_NETWORK_REQUEST_ACTIVATION_REJECT,     state_event_error),
    M_TRANSITION(SM_I_NETWORK_DEACTIVATE,                    ignored)
  }
};

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

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_mark_context_active
+------------------------------------------------------------------------------
| Description : Mark context in network state ACTIVE
|
| Parameters  : nsapi              - context index
+------------------------------------------------------------------------------
*/
static void sm_nw_mark_context_active(int /*@alt U8@*/ nsapi)
{
  sm_data.sm_context_activation_status
    = sm_add_nsapi_to_nsapi_set(nsapi, sm_data.sm_context_activation_status);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_mark_context_inactive
+------------------------------------------------------------------------------
| Description : Mark context in network state INACTIVE
|
| Parameters  : nsapi              - context index
+------------------------------------------------------------------------------
*/
static void sm_nw_mark_context_inactive(int /*@alt U8@*/ nsapi)
{
  sm_data.sm_context_activation_status
    = sm_remove_nsapi_from_nsapi_set(nsapi, sm_data.sm_context_activation_status);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_mark_nsapi_set_inactive
+------------------------------------------------------------------------------
| Description : Mark a set of contexts in network state INACTIVE
|
| Parameters  : nsapi_set          - Set of NSAPIs to mark inactive
+------------------------------------------------------------------------------
*/
static void sm_nw_mark_nsapi_set_inactive(U16 nsapi_set)
{
  sm_data.sm_context_activation_status &= 0xffff ^ nsapi_set;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_get_next_free_ti
+------------------------------------------------------------------------------
| Description : Traverse sm_context_array and find the lowest unused TI.
|
| Parameters  : context             - context that needs TI
+------------------------------------------------------------------------------
*/
static U8 sm_nw_get_next_free_ti(struct T_SM_CONTEXT_DATA *context_to_get_ti)
{
  int nsapi;
  U16 ti_mask = (U16)0x07ff;

  /* Iterate through sm_context_array and find the lowest available TI */
  for (nsapi = (int)NAS_NSAPI_5; nsapi < NAS_SIZE_NSAPI; nsapi++)
  {
    struct T_SM_CONTEXT_DATA *context;

    context = sm_get_context_data_from_nsapi(nsapi);
    if (context != NULL && context != context_to_get_ti
        && (context->ti & (U8)SM_TI_FLAG) == (U8)0 )
    {
      ti_mask &= 0x7ff ^ (1 << context->ti);
    }
  }

  if (ti_mask != 0)
  {
    int index;
    for (index = 0;
         index < SM_MAX_NSAPI_OFFSET && (ti_mask & (1UL << (U16)index)) == 0;
         index++)
      {};
    return (U8)index;
  } else {
    /* No TIs available */
    return (U8)0;
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_initiate_deactivation
+------------------------------------------------------------------------------
| Description : General function for aborting a procedure and deactivating
|
| Parameters  : context          - context data
+------------------------------------------------------------------------------
*/
static void sm_nw_initiate_deactivation(struct T_SM_CONTEXT_DATA *context,
                                        T_CAUSE_ps_cause *ps_cause)
{
  /* Stop any active timer and start T3390 in stead */
  sm_timer_stop(context);
  sm_timer_start(context, SM_TIMER_T3390);

  /* Send message DEACTIVATE PDP CONTEXT REQUEST */
  send_msg_deactivate_pdp_context_request(context, ps_cause, FALSE);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_store_mt_modify_parameters
+------------------------------------------------------------------------------
| Description : Examines a T_D_MODIFY_PDP_CONTEXT_REQUEST message and stores
|               the parameters included.  Returns flags which indicate the
|               parameters that were updated.
|
| Parameters  : context          - context data
|               msg              - T_D_MODIFY_PDP_CONTEXT_REQUEST
+------------------------------------------------------------------------------
*/
static T_SM_UPDATE_FLAGS
sm_nw_store_mt_modify_parameters(struct T_SM_CONTEXT_DATA *context,
                                 T_D_MODIFY_PDP_CONTEXT_REQUEST *msg)
{
  T_SM_UPDATE_FLAGS  update_flags;
  sm_qos_assign_from_aim(&context->accepted_qos, &msg->qos);

  update_flags             = SM_UPDATE_QOS;

  /* Store GSM RAT parameters, if present */
  if (context->radio_prio != msg->radio_prio.radio_prio_val ||
      context->sapi       != msg->llc_sapi.sapi)
  {
    context->radio_prio    = msg->radio_prio.radio_prio_val;
    context->sapi          = msg->llc_sapi.sapi;
    update_flags          |= SM_UPDATE_SAPI_RADIO_PRIO_PFI;
  }

  /* Store PFI, if present */
  if (msg->v_pfi != (U8)FALSE && msg->pfi.pfi_val != context->pfi)
  {
    sm_set_pfi_included(context, TRUE);
    context->pfi           = msg->pfi.pfi_val;
    update_flags          |= SM_UPDATE_SAPI_RADIO_PRIO_PFI;
  }

  /* IP address "modified" (== assigned late)? Store, if so. */
  if (msg->v_address != (U8)FALSE)
  {
    sm_nw_store_negotiated_address(context, &msg->address, msg->v_address);
    update_flags          |= SM_UPDATE_ADDRESS;
  }

  return update_flags;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_store_modify_accept_parameters
+------------------------------------------------------------------------------
| Description : Examines a T_D_MODIFY_PDP_CONTEXT_ACCEPT message and stores
|               the parameters included.  Returns flags which indicate the
|               parameters that were updated.
|
| Parameters  : context          - context data
|               msg              - T_D_MODIFY_PDP_CONTEXT_REQUEST
+------------------------------------------------------------------------------
*/
static T_SM_UPDATE_FLAGS
sm_nw_store_modify_accept_parameters(struct T_SM_CONTEXT_DATA *context,
                                     T_D_MODIFY_PDP_CONTEXT_ACCEPT *msg)
{
  T_SM_UPDATE_FLAGS  update_flags = (T_SM_UPDATE_FLAGS)0;

  /* Store GSM RAT parameters, if present */
  if (msg->v_llc_sapi != (U8)FALSE)
  {
    context->sapi       = msg->llc_sapi.sapi;
    update_flags        = SM_UPDATE_SAPI_RADIO_PRIO_PFI;
  }

  if (msg->v_radio_prio != (U8)FALSE &&
      msg->radio_prio.radio_prio_val != context->radio_prio)
  {
    context->radio_prio = msg->radio_prio.radio_prio_val;
    update_flags        = SM_UPDATE_SAPI_RADIO_PRIO_PFI;
  }

  /* Store PFI, if present */
  if (msg->v_pfi != (U8)FALSE &&
      msg->pfi.pfi_val != context->pfi)
  {
    sm_set_pfi_included(context, TRUE);
    context->pfi         = msg->pfi.pfi_val;
    update_flags         = SM_UPDATE_SAPI_RADIO_PRIO_PFI;
  }

  return update_flags;
}

/*
+------------------------------------------------------------------------------
| Function    : state_event_error
+------------------------------------------------------------------------------
| Description : General function used to report state event errors.
|
| Parameters  : context          - Not used
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void state_event_error(/*@unused@*/ struct T_SM_CONTEXT_DATA *context, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_ERROR("SM Network Control: STATE EVENT ERROR!");
}

/*
+------------------------------------------------------------------------------
| Function    : ignored
+------------------------------------------------------------------------------
| Description : General function used for transitions that shall be ignored
|
| Parameters  : context          - Not used
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void ignored(/*@unused@*/ struct T_SM_CONTEXT_DATA *context, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("SM Network Control: Event ignored.");
}

/*
+------------------------------------------------------------------------------
| Function    : message_incompatible_with_state
+------------------------------------------------------------------------------
| Description : General function used for reporting illegal air interface
|               messages in the current state
|
| Parameters  : context          - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void message_incompatible_with_state(/*@unused@*/ struct T_SM_CONTEXT_DATA *context, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("message_incompatible_with_state");

  sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_MSG_TYPE_INCOMPATIBLE_WITH_STATE);
  send_msg_sm_status(context->ti, sm_get_nw_cause(context));
}

/*
+------------------------------------------------------------------------------
| Function    : message_for_invalid_ti
+------------------------------------------------------------------------------
| Description : General function used for replying to network messages
|               received for a context in state S0 (invalid TI)
|
| Parameters  : context          - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void message_for_invalid_ti(/*@unused@*/ struct T_SM_CONTEXT_DATA *context, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("message_for_invalid_ti");

  sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_INVALID_TI);
  send_msg_sm_status(context->ti, sm_get_nw_cause(context));
}

/*
+------------------------------------------------------------------------------
| Function    : handle_activate_primary
+------------------------------------------------------------------------------
| Description : Handle event SM_I_NETWORK_ACTIVATE_PRIMARY in S0
|
| Parameters  : context          - Context data
|               data             - SMREG_PDP_ACTIVATE_REQ *
+------------------------------------------------------------------------------
*/
static void handle_activate_primary(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_SMREG_PDP_ACTIVATE_REQ *prim = (T_SMREG_PDP_ACTIVATE_REQ *)data;

  (void)TRACE_FUNCTION("handle_activate_primary");

  if (prim != NULL)
  {
    memcpy(&context->comp_params, &prim->comp_params, sizeof(T_NAS_comp_params));

    sm_qos_copy_to_sm(&context->requested_qos, &prim->qos, prim->ctrl_qos);
    sm_qos_copy_to_sm(&context->minimum_qos, (T_PS_qos *)&prim->min_qos,
                      (T_PS_ctrl_qos)prim->ctrl_min_qos);

    sm_nw_store_requested_address(context, prim->pdp_type,
                                  prim->ctrl_ip_address, &prim->ip_address);

    /* Free APN (necessary if this is a network requested activation) */
    sm_nw_free_apn(context);

    /* Store APN for negotiation, if present */
    if (prim->apn.c_apn_buf > (U8)0)
    {
      sm_nw_allocate_and_copy_apn(context, prim->apn.c_apn_buf, prim->apn.apn_buf);
    }

    /* Store TFT for later addition, if present */
    TRACE_ASSERT(context->requested_tft.ptr_tft_pf == NULL);
    if (prim->v_tft != (U8)FALSE && prim->tft.c_tft_pf > (U8)0)
    {
      sm_nw_allocate_and_copy_requested_tft(context, &prim->tft);
    } else {
      context->requested_tft.c_tft_pf = (U8)0;
    }

    /* Store PCO for negotiation, if present */
    sm_nw_free_requested_pco(context);
    if (prim->sdu.l_buf > 0)
    {
      U16 pco_len = prim->sdu.l_buf >> 3;
      sm_nw_allocate_and_copy_requested_pco(context, pco_len,
                                            &prim->sdu.buf[(prim->sdu.o_buf >> 3)]);
    }

    /* Allocate TI for context unless this was a NW initiated activation */
    if ((context->ti & SM_TI_FLAG) == (U8)0)
    {
      context->ti = sm_nw_get_next_free_ti(context);
    }
  } else {
    /* No SMREG primitive: This is a re-activation.  Use current parameters. */ 
    /* The following function call can cause problems in reactivation cases 
     * where the first pdp context uses dynamic addressing. When the following
     * function is called the 'reactivated' context uses address issued by the 
     * network for the first pdp activation. This will result in static addressing
     * and may cause pdp activation reject from networks that doesn't support 
     * static addressing.
     */
    /*sm_nw_copy_negotiated_address_to_requested(context);*/
  }

  /* Mark context as active */
  sm_nw_mark_context_active(context->nsapi);

  /* Start timer T3380 for this NSAPI/context */
  sm_timer_start(context, SM_TIMER_T3380);

  /* Send ACTIVATE PDP CONTEXT REQUEST message */
  send_msg_activate_pdp_context_request(context);

  /* Go to state SM NETWORK ACTIVATING PRIMARY */
  context->network_control_state = SM_NETWORK_ACTIVATING_PRIMARY;
}

/*
+------------------------------------------------------------------------------
| Function    : handle_activate_secondary
+------------------------------------------------------------------------------
| Description : Handle event SM_I_NETWORK_ACTIVATE_SECONDARY in S0
|
| Parameters  : context          - Context data
|               data             - T_SMREG_PDP_ACTIVATE_SEC_REQ *
+------------------------------------------------------------------------------
*/
static void handle_activate_secondary(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_SMREG_PDP_ACTIVATE_SEC_REQ *prim = (T_SMREG_PDP_ACTIVATE_SEC_REQ *)data;

  (void)TRACE_FUNCTION("handle_activate_secondary");

  if (prim != NULL)
  {
    memcpy(&context->comp_params, &prim->comp_params, sizeof(T_NAS_comp_params));

    sm_qos_copy_to_sm(&context->requested_qos, &prim->qos, prim->ctrl_qos);
    sm_qos_copy_to_sm(&context->minimum_qos, (T_PS_qos *)&prim->min_qos,
                      (T_PS_ctrl_qos)prim->ctrl_min_qos);

    /* Store TFT for later addition, if present */
    sm_nw_free_requested_tft(context);
    if (prim->v_tft != (U8)FALSE && prim->tft.c_tft_pf > (U8)0)
    {
      sm_nw_allocate_and_copy_requested_tft(context, &prim->tft);
    } else {
      context->requested_tft.c_tft_pf = (U8)0;
    }
    /* Allocate TI for context */
    context->ti = sm_nw_get_next_free_ti(context);
  } else {
    /* No SMREG primitive: This is a re-activation.  Use current parameters. */
  }

  /* Mark context as active */
  sm_nw_mark_context_active(context->nsapi);

  /* Start timer T3380 for this NSAPI/context */
  sm_timer_start(context, SM_TIMER_T3380);

  /* Send ACTIVATE SECONDARY PDP CONTEXT REQUEST message */
  send_msg_activate_secondary_pdp_context_request(context);

  /* Go to state SM NETWORK ACTIVATING SECONDARY */
  context->network_control_state = SM_NETWORK_ACTIVATING_SECONDARY;
}

/*
+------------------------------------------------------------------------------
| Function    : handle_request_activation_reject
+------------------------------------------------------------------------------
| Description : Handle event SM_I_NETWORK_REQUEST_ACTIVATION_REJECT in S0
|
| Parameters  : context          - Context data
|               data             - Not used (cause set in context data)
+------------------------------------------------------------------------------
*/
static void handle_request_activation_reject(struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/ void *data)
{
  (void)TRACE_FUNCTION("handle_request_activation_reject");

  /* Send REQUEST PDP CONTEXT ACTIVATION REJECT message */
  send_msg_request_pdp_context_activation_reject(context, sm_get_nw_cause(context));
}

/*
+------------------------------------------------------------------------------
| Function    : handle_modify_in_S4
+------------------------------------------------------------------------------
| Description : Handle event SM_I_NETWORK_MODIFY in S4
|
| Parameters  : context          - Context data
|               data             - T_SMREG_PDP_MODIFY_REQ *
+------------------------------------------------------------------------------
*/
static void handle_modify_in_S4(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_SMREG_PDP_MODIFY_REQ *prim = (T_SMREG_PDP_MODIFY_REQ *)data;
  BOOL                    start_modification = FALSE;

  (void)TRACE_FUNCTION("handle_modify_in_S4");

  /* If prim == NULL this is a context upgrade (RAB re-establishment) */
  if (prim != NULL)
  {
    if (prim->ctrl_qos != PS_is_qos_not_present)
    {
      sm_qos_copy_to_sm(&context->requested_qos, &prim->qos, prim->ctrl_qos);
      start_modification          = TRUE;
    }

    if (prim->ctrl_min_qos != PS_is_min_qos_not_present)
    {
      sm_qos_copy_to_sm(&context->minimum_qos, (T_PS_qos *)&prim->min_qos,
                        (T_PS_ctrl_qos)prim->ctrl_min_qos);
      if (!sm_qos_is_minimum_satisfied_by_sm(context, &context->accepted_qos))
      {
        start_modification        = TRUE;
      }
    }

    /* Store TFT for later addition, if present */
    if (prim->v_tft != (U8)FALSE)
    {
      if (prim->tft.c_tft_pf > (U8)0)
      {
        sm_nw_allocate_and_copy_requested_tft(context, &prim->tft);
      } else {
        context->requested_tft.c_tft_pf = (U8)0;
      }
      if (sm_tft_more_to_modify(context))
      {
        start_modification        = TRUE;
      }
    }
  } else {
    /* Prim == NULL: context upgrade (RAB re-establishment) */
    /* Start modification with originally requested parameters */
    start_modification            = TRUE;
  }

  if (start_modification)
  {
    /* Start timer T3381 for this NSAPI/context */
    sm_timer_start(context, SM_TIMER_T3381);

    /* Send MODIFY PDP CONTEXT REQUEST message */
    send_msg_modify_pdp_context_request(context);

    /* Go to state SM NETWORK MODIFYING */
    context->network_control_state = SM_NETWORK_MODIFYING;
  }
}

/*
+------------------------------------------------------------------------------
| Function    : handle_deactivate_in_S0
+------------------------------------------------------------------------------
| Description : Handle event SM_I_NETWORK_DEACTIVATE in S0
|
| Parameters  : context          - Context data
|               data             - rel_ind flag
+------------------------------------------------------------------------------
*/
static void handle_deactivate_in_S0(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("handle_deactivate_in_S0");

  /* Report success deactivation to Context Control (already inactive) */
  sm_context_control(context, SM_I_NETWORK_DEACTIVATE_COMPLETED, data);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_deactivate_during_activation
+------------------------------------------------------------------------------
| Description : Handle event SM_I_NETWORK_DEACTIVATE in S1 or S2
|
| Parameters  : context          - Context data
|               data             - Cause (T_CAUSE_ps_cause *)
+------------------------------------------------------------------------------
*/
static void handle_deactivate_during_activation(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("handle_deactivate_during_activation");

  TRACE_ASSERT(data != NULL);

  /* Go to state SM NETWORK DEACTIVATING */
  context->network_control_state = SM_NETWORK_DEACTIVATING;

  /* Stop T3380, and start deactivation */
  sm_nw_initiate_deactivation(context, (T_CAUSE_ps_cause *)data);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_deactivate_in_S4
+------------------------------------------------------------------------------
| Description : Handle event SM_I_NETWORK_DEACTIVATE in S4
|
| Parameters  : context          - Context data
|               data             - Cause (T_CAUSE_ps_cause *)
+------------------------------------------------------------------------------
*/
static void handle_deactivate_in_S4(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("handle_deactivate_in_S4");

  TRACE_ASSERT(data != NULL);

  /* Go to state SM NETWORK DEACTIVATING */
  context->network_control_state = SM_NETWORK_DEACTIVATING;

  /* Initiate deactivation; data contains cause */
  sm_nw_initiate_deactivation(context, (T_CAUSE_ps_cause *)data);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_deactivate_during_modification
+------------------------------------------------------------------------------
| Description : Handle event SM_I_NETWORK_DEACTIVATE in S3, S5, or S6
|
| Parameters  : context          - Context data
|               data             - Cause (T_CAUSE_ps_cause *)
+------------------------------------------------------------------------------
*/
static void handle_deactivate_during_modification(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("handle_deactivate_during_modification");

  TRACE_ASSERT(data != NULL);

  /* Go to state SM NETWORK DEACTIVATING */
  context->network_control_state = SM_NETWORK_DEACTIVATING;

  /* Initiate deactivation; data contains cause */
  sm_nw_initiate_deactivation(context, (T_CAUSE_ps_cause *)data);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_deactivate_local
+------------------------------------------------------------------------------
| Description : Handle SM_I_NETWORK_DEACTIVATE_LOCAL
|
| Parameters  : context          - context data
|               data             - unused
+------------------------------------------------------------------------------
*/
static void handle_deactivate_local(struct T_SM_CONTEXT_DATA *context, /*@unused@*/ /*@null@*/ void *data)
{
  /* Remove active TFT - this is necessary in case of reactivations */
  sm_nw_free_active_tft(context);

  /* Free stored coded message - if any */
  sm_free_coded_msg(context);

  /* Mark context as inactive */
  sm_nw_mark_context_inactive(context->nsapi);

  context->network_control_state = SM_NETWORK_DEACTIVATED;
}

/*
+------------------------------------------------------------------------------
| Function    : handle_activate_pdp_context_accept
+------------------------------------------------------------------------------
| Description : Handle event SM_M_ACTIVATE_PDP_CONTEXT_ACCEPT in S1
|
| Parameters  : context          - Context data
|               data             - T_ACTIVATE_PDP_CONTEXT_ACCEPT *
+------------------------------------------------------------------------------
*/
static void handle_activate_pdp_context_accept(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_ACTIVATE_PDP_CONTEXT_ACCEPT *msg = (T_ACTIVATE_PDP_CONTEXT_ACCEPT *)data;
  T_SM_UPDATE_FLAGS     update_flags = (T_SM_UPDATE_FLAGS)0; 
  BOOL  is_address_changed = FALSE;

  (void)TRACE_FUNCTION("handle_activate_pdp_context_accept");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Stop timer T3380 */
  sm_timer_stop(context);

  if (!sm_is_llc_sapi_valid(msg->llc_sapi.sapi, context->ti))
  {
    return;
  }
   
  is_address_changed = sm_is_address_changed_with_reactivation(context, 
                                               &msg->address, msg->v_address);
  /* Check whether negotiated QoS satisfies minimum QoS */
  if ( sm_qos_is_minimum_satisfied_by_aim(context, &msg->qos) && 
                                         !(is_address_changed) )
  {
    if (context->accepted_qos.ctrl_qos != PS_is_qos_not_present)
    {
      update_flags |= SM_UPDATE_QOS;
    }

    /* QoS >= minimum QoS: Store negotiated parameters */
    sm_qos_assign_from_aim(&context->accepted_qos, &msg->qos);

    /* Store GSM RAT parameters */
    context->radio_prio        = msg->radio_prio.radio_prio_val;
    context->sapi              = msg->llc_sapi.sapi;

    /* Store PFI, if present */
    if (msg->v_pfi != (U8)FALSE)
    {
      sm_set_pfi_included(context, TRUE);
      context->pfi             = msg->pfi.pfi_val;
    } else {
      sm_set_pfi_included(context, FALSE);
    }

    /* Store negotiated IP address, if any */
    sm_nw_store_negotiated_address(context, &msg->address, msg->v_address);

    /* Store negotiated PCO, if any */
    if (msg->v_pco != (U8)FALSE && msg->pco.c_pco_value > (U8)0)
    {
      sm_nw_allocate_and_copy_negotiated_pco(context, msg->pco.c_pco_value,
                                             msg->pco.pco_value);
    } else {
      context->negotiated_pco     = NULL;
    }

    /* Check whether to add TFT */
    if (sm_tft_more_to_modify(context))
    {
      /* Start T3381 */
      sm_timer_start(context, SM_TIMER_T3381);
      /* Send MODIFY PDP CONTEXT REQUEST with remaining TFTs */
      send_msg_modify_pdp_context_request(context);
      /* Go to state SM NETWORK ACTIVATING ADDING TFTS */
      context->network_control_state = SM_NETWORK_ACTIVATING_ADDING_TFTS;
    } else {
      /* No TFT: go to state SM NETWORK ACTIVATED, and inform Context Control */
      context->network_control_state = SM_NETWORK_ACTIVATED;

      sm_context_control(context, SM_I_NETWORK_ACTIVATE_COMPLETED,
                         (void *)update_flags);
    }
  } else {  /* if (sm_qos_is_minimum_satisfied_by_aim()) */
    /* Minimum QoS not satisfied - Start deactivation, T3390 */
    sm_timer_start(context, SM_TIMER_T3390);

    /* Send DEACTIVATE PDP CONTEXT REQUEST message */
    if (is_address_changed) {
      sm_set_nw_cause(context, CAUSE_is_from_nwsm, 
                               (U16)CAUSE_NWSM_REGULAR_DEACTIVATION);
      sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_REGULAR_DEACTIVATION);
    }
    else {
      sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
      sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
    }
    send_msg_deactivate_pdp_context_request(context, sm_get_nw_cause(context), FALSE);

    /* Go to state SM NETWORK DEACTIVATING */
    context->network_control_state = SM_NETWORK_DEACTIVATING;

    /* Report failed activation to Context Control (with network deactivation) */
     
    sm_context_control(context, SM_I_NETWORK_ACTIVATE_REJECTED, (void *)TRUE);
  } /* if */
}

/*
+------------------------------------------------------------------------------
| Function    : handle_activate_pdp_context_reject
+------------------------------------------------------------------------------
| Description : Handle event SM_M_ACTIVATE_PDP_CONTEXT_REJECT in S1
|
| Parameters  : context          - Context data
|               data             - T_ACTIVATE_PDP_CONTEXT_REJECT *
+------------------------------------------------------------------------------
*/
static void handle_activate_pdp_context_reject(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_ACTIVATE_PDP_CONTEXT_REJECT *msg = (T_ACTIVATE_PDP_CONTEXT_REJECT *)data;
  (void)TRACE_FUNCTION("handle_activate_pdp_context_reject");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Store erroneous PCO, if any */
  if (msg->v_pco != (U8)FALSE && msg->pco.c_pco_value > (U8)0)
  {
    sm_nw_allocate_and_copy_negotiated_pco(context, msg->pco.c_pco_value,
                                           msg->pco.pco_value);
  } else {
    context->negotiated_pco     = NULL;
  }

  /* Stop timer T3380 */
  sm_timer_stop(context);

  /* Go to state SM NETWORK DEACTIVATED */
  context->network_control_state = SM_NETWORK_DEACTIVATED;

  /* Mark context as inactive */
  sm_nw_mark_context_inactive(context->nsapi);

  /* Build cause structure */
  sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)msg->sm_cause.sm_cause_val);

  /* Re-synchronise MMs PDP context status */
  send_mmpm_pdp_context_status_req();

  /* Report failed activation to Context Control (no network deactivation) */
  sm_context_control(context, SM_I_NETWORK_ACTIVATE_REJECTED, (void *)FALSE);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_activate_secondary_pdp_context_accept
+------------------------------------------------------------------------------
| Description : Handle event SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_ACCEPT
|
| Parameters  : context          - Context data
|               data             - T_ACTIVATE_SECONDARY_PDP_CONTEXT_ACCEPT *
+------------------------------------------------------------------------------
*/
static void handle_activate_secondary_pdp_context_accept(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_ACTIVATE_SECONDARY_PDP_CONTEXT_ACCEPT *msg = (T_ACTIVATE_SECONDARY_PDP_CONTEXT_ACCEPT *)data;

  (void)TRACE_FUNCTION("handle_activate_secondary_pdp_context_accept");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;
	  
  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Stop timer T3380 */
  sm_timer_stop(context);

  if (!sm_is_llc_sapi_valid(msg->llc_sapi.sapi, context->ti))
  {
    return;
  }

  /* Check whether negotiated QoS satisfies minimum QoS */
  if (sm_qos_is_minimum_satisfied_by_aim(context, &msg->qos))
  {
    /* QoS >= minimum QoS: Store negotiated parameters */
    sm_qos_assign_from_aim(&context->accepted_qos, &msg->qos);

    /* Store GSM RAT parameters */
    context->radio_prio        = msg->radio_prio.radio_prio_val;
    context->sapi              = msg->llc_sapi.sapi;

    /* Store PFI, if present */
    if (msg->v_pfi != (U8)FALSE)
    {
      sm_set_pfi_included(context, TRUE);
      context->pfi             = msg->pfi.pfi_val;
    } else {
      sm_set_pfi_included(context, FALSE);
    }

    /* Check whether to add TFT */
    if (sm_tft_more_to_modify(context))
    {
      /* Start T3381 */
      sm_timer_start(context, SM_TIMER_T3381);
      /* Send MODIFY PDP CONTEXT REQUEST with remaining TFTs */
      send_msg_modify_pdp_context_request(context);
      /* Go to state SM NETWORK ACTIVATING ADDING TFTS */
      context->network_control_state = SM_NETWORK_ACTIVATING_ADDING_TFTS;
    } else {
      /* No TFT: go to state SM NETWORK ACTIVATED, and inform Context Control */
      context->network_control_state = SM_NETWORK_ACTIVATED;

      sm_context_control(context, SM_I_NETWORK_ACTIVATE_COMPLETED, NULL);
    }
  } else {  /* if (sm_qos_is_minimum_satisfied_by_aim()) */
    /* Minimum QoS not satisfied - go to state SM NETWORK DEACTIVATING */
    context->network_control_state = SM_NETWORK_DEACTIVATING;

    /* Start deactivation, T3390 */
    sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
    sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

    /* Report failed activation to Context Control (with network deactivation) */
    sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
    sm_context_control(context, SM_I_NETWORK_ACTIVATE_REJECTED, (void *)TRUE);
  } /* if */
}

/*
+------------------------------------------------------------------------------
| Function    : handle_activate_secondary_pdp_context_reject
+------------------------------------------------------------------------------
| Description : Handle event SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_REJECT
|
| Parameters  : context          - Context data
|               data             - T_ACTIVATE_SECONDARY_PDP_CONTEXT_REJECT *
+------------------------------------------------------------------------------
*/
static void handle_activate_secondary_pdp_context_reject(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_ACTIVATE_SECONDARY_PDP_CONTEXT_REJECT *msg = (T_ACTIVATE_SECONDARY_PDP_CONTEXT_REJECT *)data;
  (void)TRACE_FUNCTION("handle_activate_secondary_pdp_context_reject");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Stop timer T3380 */
  sm_timer_stop(context);

  /* Go to state SM NETWORK DEACTIVATED */
  context->network_control_state = SM_NETWORK_DEACTIVATED;

  /* Mark context as inactive */
  sm_nw_mark_context_inactive(context->nsapi);

  /* Build cause structure */
  sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)msg->sm_cause.sm_cause_val);

  /* Re-synchronise MMs PDP context status */
  send_mmpm_pdp_context_status_req();

  /* Report failed activation to Context Control (no network deactivation) */
  sm_context_control(context, SM_I_NETWORK_ACTIVATE_REJECTED, (void *)FALSE);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_request_pdp_context_activation_in_S0
+------------------------------------------------------------------------------
| Description : Handle event SM_M_REQUEST_PDP_CONTEXT_ACTIVATION in S0
|
| Parameters  : context          - Context data
|               data             - T_REQUEST_PDP_CONTEXT_ACTIVATION *
+------------------------------------------------------------------------------
*/
static void handle_request_pdp_context_activation_in_S0(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_REQUEST_PDP_CONTEXT_ACTIVATION *msg = (T_REQUEST_PDP_CONTEXT_ACTIVATION *)data;

  (void)TRACE_FUNCTION("handle_request_pdp_context_activation_in_S0");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  context->pdp_type         = msg->address.pdp_type_no;

  sm_nw_store_negotiated_address(context, &msg->address, (U8)TRUE);

  if (msg->v_apn != (U8)FALSE)
  {
    sm_nw_allocate_and_copy_apn(context, msg->apn.c_apn_value, msg->apn.apn_value);
  } else {
    context->apn            = NULL;
  }

  /* Inform Context Control of activation request */
  sm_context_control(context, SM_I_NETWORK_REQUEST_ACTIVATION, msg);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_request_pdp_context_activation_in_S1
+------------------------------------------------------------------------------
| Description : Handle event SM_M_REQUEST_PDP_CONTEXT_ACTIVATION in S1
|
| Parameters  : context          - Context data
|               data             - T_REQUEST_PDP_CONTEXT_ACTIVATION *
+------------------------------------------------------------------------------
*/
static void handle_request_pdp_context_activation_in_S1(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_REQUEST_PDP_CONTEXT_ACTIVATION *msg = (T_REQUEST_PDP_CONTEXT_ACTIVATION *)data;
  (void)TRACE_FUNCTION("handle_request_pdp_context_activation_in_S1");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  /*lint !e613 (Warning -- Possible use of null pointer) */
  if (sm_nw_is_address_and_apn_equal(context, &context->requested_address,
                                     &msg->address, msg->v_apn, &msg->apn))
  {
    /* Do nothing */
  } else {
    /* Reject incoming context activation */
    sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_INSUFFICIENT_RESOURCES);

    send_msg_request_pdp_context_activation_reject(context,
                                                   sm_get_nw_cause(context));
  } /* if */
}

/*
+------------------------------------------------------------------------------
| Function    : handle_request_pdp_context_activation_in_S4
+------------------------------------------------------------------------------
| Description : Handle event SM_M_REQUEST_PDP_CONTEXT_ACTIVATION in S4
|
| Parameters  : context          - Context data
|               data             - T_REQUEST_PDP_CONTEXT_ACTIVATION *
+------------------------------------------------------------------------------
*/
static void handle_request_pdp_context_activation_in_S4(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_REQUEST_PDP_CONTEXT_ACTIVATION *msg = (T_REQUEST_PDP_CONTEXT_ACTIVATION *)data;
  (void)TRACE_FUNCTION("handle_request_pdp_context_activation_in_S4");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  if (sm_nw_is_address_and_apn_equal(context, &context->negotiated_address,
                                     &msg->address, msg->v_apn, &msg->apn))
  {
    /* Go to state SM NETWORK ACTIVATING PRIMARY */
    context->network_control_state = SM_NETWORK_ACTIVATING_PRIMARY;

    /* Inform Context Control of the activation override
     * NOTE!  Normally other state machines are informed last, but in this
     * case we need to update sm_data.sm_context_activation_status _before_
     * sending ACTIVATE PDP CONTEXT REQUEST through MM. */
    sm_context_control(context, SM_I_NETWORK_REQUEST_ACTIVATION_OVERRIDE, NULL);

    /* Context activation override - start context activation procedure */
    sm_timer_start(context, SM_TIMER_T3380);

    /* This is akin to a context reactivation: Use currently negotiated IP address */
    sm_nw_copy_negotiated_address_to_requested(context);

    send_msg_activate_pdp_context_request(context);
  } else {
    /* Reject incoming context activation */
    sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_INSUFFICIENT_RESOURCES);
    send_msg_request_pdp_context_activation_reject(context, sm_get_nw_cause(context));
  } /* if */
}

/*
+------------------------------------------------------------------------------
| Function    : handle_modify_pdp_context_request_in_S3
+------------------------------------------------------------------------------
| Description : Handle event SM_M_MODIFY_PDP_CONTEXT_REQUEST in S3
|
| Parameters  : context          - Context data
|               data             - T_MODIFY_PDP_CONTEXT_REQUEST * (unused)
+------------------------------------------------------------------------------
*/
static void handle_modify_pdp_context_request_in_S3(struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/void *data)
{
  (void)TRACE_FUNCTION("handle_modify_pdp_context_request_in_S3");

  /* Free coded message */
  sm_free_coded_msg(context);

  /* Stop T3381, start T3390, and send DEACTIVATE PDP CONTEXT REQUEST message */
  sm_set_nw_cause(context, CAUSE_is_from_nwsm,
                  (U16)CAUSE_NWSM_MSG_INCOMPATIBLE_WITH_STATE);
  sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

  /* Go to state SM NETWORK DEACTIVATING */
  context->network_control_state = SM_NETWORK_DEACTIVATING;

  /* Inform Context Control of the failed activation (with network deactivation) */
  sm_set_aci_cause(context, CAUSE_is_from_nwsm,
                   (U16)CAUSE_NWSM_MSG_INCOMPATIBLE_WITH_STATE);
  sm_context_control(context, SM_I_NETWORK_ACTIVATE_REJECTED, (void *)TRUE);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_modify_pdp_context_request_in_S4
+------------------------------------------------------------------------------
| Description : Handle event SM_M_MODIFY_PDP_CONTEXT_REQUEST in S4
|
| Parameters  : context          - Context data
|               data             - T_D_MODIFY_PDP_CONTEXT_REQUEST *
+------------------------------------------------------------------------------
*/
static void handle_modify_pdp_context_request_in_S4(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_D_MODIFY_PDP_CONTEXT_REQUEST *msg = (T_D_MODIFY_PDP_CONTEXT_REQUEST *)data;
  T_SM_UPDATE_FLAGS      update_flags;

  (void)TRACE_FUNCTION("handle_modify_pdp_context_request_in_S4");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  if (!sm_is_llc_sapi_valid(msg->llc_sapi.sapi, context->ti))
  {
    return;
  }

  if (sm_qos_is_minimum_satisfied_by_aim(context, &msg->qos))
  {
    /* QoS >= minimum QoS: Store negotiated parameters */
    update_flags = sm_nw_store_mt_modify_parameters(context, msg);

    /* Go to state SM NETWORK ACTIVATED */
    context->network_control_state = SM_NETWORK_ACTIVATED;

    /* Reply to network: MODIFY PDP CONTEXT ACCEPT */
    send_msg_modify_pdp_context_accept(context);

    /* Report successful NW initiated context modification */
    sm_context_control(context, SM_I_NETWORK_REQUEST_MODIFY,
                       (void *)update_flags);
  } else {
    /* Minimum QoS not satisfied - go to state SM NETWORK DEACTIVATING */
    context->network_control_state = SM_NETWORK_DEACTIVATING;

    /* Start deactivation, T3390 */
    sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
    sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

    /* Report failed activation to Context Control */
    sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
    sm_context_control(context, SM_I_NETWORK_REQUEST_MODIFY_FAILED, NULL);
  } /* if (sm_qos_is_minimum_satisfied_by_aim()) */
}

/*
+------------------------------------------------------------------------------
| Function    : handle_modify_pdp_context_request_in_S5
+------------------------------------------------------------------------------
| Description : Handle event SM_M_MODIFY_PDP_CONTEXT_REQUEST in S5
|
| Parameters  : context          - Context data
|               data             - T_D_MODIFY_PDP_CONTEXT_REQUEST *
+------------------------------------------------------------------------------
*/
static void handle_modify_pdp_context_request_in_S5(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_D_MODIFY_PDP_CONTEXT_REQUEST *msg = (T_D_MODIFY_PDP_CONTEXT_REQUEST *)data;
  T_SM_UPDATE_FLAGS      update_flags;

  (void)TRACE_FUNCTION("handle_modify_pdp_context_request_in_S5");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  /* Free coded message */
  sm_free_coded_msg(context);

  /* Reject currently active UE initiated modification */
  sm_set_aci_cause(context, CAUSE_is_from_sm, (U16)CAUSE_SM_MODIFY_COLLISION);
  sm_context_control(context, SM_I_NETWORK_MODIFY_REJECTED, (void *)FALSE);

  if (!sm_is_llc_sapi_valid(msg->llc_sapi.sapi, context->ti))
  {
    return;
  }

  if (sm_qos_is_minimum_satisfied_by_aim(context, &msg->qos))
  {
    /* QoS >= minimum QoS: Store negotiated parameters */
    update_flags = sm_nw_store_mt_modify_parameters(context, msg);

    /* Go to state SM NETWORK ACTIVATED */
    context->network_control_state = SM_NETWORK_ACTIVATED;

    /* Reply to network: MODIFY PDP CONTEXT ACCEPT */
    send_msg_modify_pdp_context_accept(context);

    /* Report successful NW initiated context modification */
    sm_context_control(context, SM_I_NETWORK_REQUEST_MODIFY,
                       (void *)update_flags);
  } else {
    /* Minimum QoS not satisfied - go to state SM NETWORK DEACTIVATING */
    context->network_control_state = SM_NETWORK_DEACTIVATING;

    /* Start deactivation, T3390 */
    sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
    sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

    /* Report failed activation to Context Control */
    sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
    sm_context_control(context, SM_I_NETWORK_REQUEST_MODIFY_FAILED, NULL);
  } /* if (sm_qos_is_minimum_satisfied_by_aim()) */
}

/*
+------------------------------------------------------------------------------
| Function    : handle_modify_pdp_context_request_in_S6
+------------------------------------------------------------------------------
| Description : Handle event SM_M_MODIFY_PDP_CONTEXT_REQUEST in S6
|
| Parameters  : context          - Context data
|               data             - T_MODIFY_PDP_CONTEXT_REQUEST * (unused)
+------------------------------------------------------------------------------
*/
static void handle_modify_pdp_context_request_in_S6(struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/ void *data)
{
  (void)TRACE_FUNCTION("handle_modify_pdp_context_request_in_S6");

  /* Free coded message */
  sm_free_coded_msg(context);

  /* Reject currently active UE initiated modification */
  sm_set_aci_cause(context, CAUSE_is_from_sm, (U16)CAUSE_SM_MODIFY_COLLISION);
  sm_context_control(context, SM_I_NETWORK_MODIFY_REJECTED, (void *)FALSE);

  /* Go to state SM NETWORK DEACTIVATING */
  context->network_control_state = SM_NETWORK_DEACTIVATING;

  /* Stop T3381, start T3390, and send DEACTIVATE PDP CONTEXT REQUEST message */
  sm_set_nw_cause(context, CAUSE_is_from_nwsm,
                  (U16)CAUSE_NWSM_MSG_INCOMPATIBLE_WITH_STATE);
  sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

  /* Inform Context Control of the failed modification */
  sm_set_aci_cause(context, CAUSE_is_from_nwsm,
                   (U16)CAUSE_NWSM_MSG_INCOMPATIBLE_WITH_STATE);
  sm_context_control(context, SM_I_NETWORK_REQUEST_MODIFY_FAILED, NULL);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_modify_pdp_context_accept_in_S3
+------------------------------------------------------------------------------
| Description : Handle event SM_M_MODIFY_PDP_CONTEXT_ACCEPT in S3
|
| Parameters  : context          - Context data
|               data             - T_D_MODIFY_PDP_CONTEXT_ACCEPT *
+------------------------------------------------------------------------------
*/
static void handle_modify_pdp_context_accept_in_S3(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_D_MODIFY_PDP_CONTEXT_ACCEPT *msg = (T_D_MODIFY_PDP_CONTEXT_ACCEPT *)data;
  T_SM_UPDATE_FLAGS     update_flags;
  (void)TRACE_FUNCTION("handle_modify_pdp_context_accept_in_S3");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Stop timer T3381 */
  sm_timer_stop(context);

  /* Store GSM RAT parameters, if present */
  update_flags = sm_nw_store_modify_accept_parameters(context, msg);

  if (msg->v_qos != (U8)FALSE)
  {
    update_flags       |= SM_UPDATE_QOS;
    /* We requested no new QoS, but received one nontheless. */
    if (sm_qos_is_minimum_satisfied_by_aim(context, &msg->qos))
    {
      /* QoS >= minimum QoS: Store negotiated parameters */
      sm_qos_assign_from_aim(&context->accepted_qos, &msg->qos);
    } else {
      /* Minimum QoS no longer satisfied: Abort activation */
      sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
      sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

      context->network_control_state = SM_NETWORK_DEACTIVATING;

      sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
      /* Report failed activation to Context Control (with network deactivation) */
      sm_context_control(context, SM_I_NETWORK_ACTIVATE_REJECTED, (void *)TRUE);
      return;
    } /* if (sm_qos_is_minimum_satisfied_by_aim) */
  }

  if (sm_tft_more_to_modify(context))
  {
    /* Start T3381 */
    sm_timer_start(context, SM_TIMER_T3381);
    /* Send MODIFY PDP CONTEXT REQUEST with remaining TFTs */
    send_msg_modify_pdp_context_request(context);
  } else {
    /* No more TFTs to add: go to state SM NETWORK ACTIVATED, and inform Context Control */
    context->network_control_state = SM_NETWORK_ACTIVATED;

    sm_context_control(context, SM_I_NETWORK_ACTIVATE_COMPLETED,
                       (void *)update_flags);
  }
}

/*
+------------------------------------------------------------------------------
| Function    : handle_modify_pdp_context_accept_in_S5
+------------------------------------------------------------------------------
| Description : Handle event SM_M_MODIFY_PDP_CONTEXT_ACCEPT in S5
|
| Parameters  : context          - Context data
|               data             - T_D_MODIFY_PDP_CONTEXT_ACCEPT *
+------------------------------------------------------------------------------
*/
static void handle_modify_pdp_context_accept_in_S5(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_D_MODIFY_PDP_CONTEXT_ACCEPT *msg = (T_D_MODIFY_PDP_CONTEXT_ACCEPT *)data;
  T_SM_UPDATE_FLAGS     update_flags = (T_SM_UPDATE_FLAGS)0;
  (void)TRACE_FUNCTION("handle_modify_pdp_context_accept_in_S5");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Stop timer T3381 */
  sm_timer_stop(context);

  /* Store GSM RAT parameters, if present */
  update_flags = sm_nw_store_modify_accept_parameters(context, msg);

  if (msg->v_qos != (U8)FALSE)
  {
    /* QoS updated */
    if (sm_qos_is_minimum_satisfied_by_aim(context, &msg->qos))
    {
      /* QoS >= minimum QoS: Store negotiated parameters */
      sm_qos_assign_from_aim(&context->accepted_qos, &msg->qos);
      update_flags     |= SM_UPDATE_QOS;
    } else {
      /* Minimum QoS no longer satisfied: Deactivate */
      sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
      sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

      context->network_control_state = SM_NETWORK_DEACTIVATING;

      sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
      sm_context_control(context, SM_I_NETWORK_MODIFY_REJECTED, (void *)FALSE);
      return;
    } /* if (sm_qos_is_minimum_satisfied_by_aim) */
  } else {
    /* Check that minimum QoS is still satisfied by current QoS */
    if (!sm_qos_is_minimum_satisfied_by_sm(context, &context->accepted_qos))
    {
      /* Minimum QoS no longer satisfied: Deactivate */
      sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
      sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

      context->network_control_state = SM_NETWORK_DEACTIVATING;

      sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
      sm_context_control(context, SM_I_NETWORK_MODIFY_REJECTED, (void *)TRUE);

      return;
    }
  }

  if (sm_tft_more_to_modify(context))
  {
    /* Start T3381 */
    sm_timer_start(context, SM_TIMER_T3381);
    /* Send MODIFY PDP CONTEXT REQUEST with more TFTs */
    send_msg_modify_pdp_context_request(context);

    context->network_control_state = SM_NETWORK_MODIFYING_ADDITIONAL_TFTS;
  } else {
    /* No more TFTs to add: Modification completed. */
    /* Go to state SM NETWORK ACTIVATED, and inform Context Control */
    context->network_control_state = SM_NETWORK_ACTIVATED;

    sm_context_control(context, SM_I_NETWORK_MODIFY_COMPLETED,
                       (void *)update_flags);
  }
}

/*
+------------------------------------------------------------------------------
| Function    : handle_modify_pdp_context_accept_in_S6
+------------------------------------------------------------------------------
| Description : Handle event SM_M_MODIFY_PDP_CONTEXT_ACCEPT in S6
|
| Parameters  : context          - Context data
|               data             - T_D_MODIFY_PDP_CONTEXT_ACCEPT *
+------------------------------------------------------------------------------
*/
static void handle_modify_pdp_context_accept_in_S6(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_D_MODIFY_PDP_CONTEXT_ACCEPT *msg = (T_D_MODIFY_PDP_CONTEXT_ACCEPT *)data;
  T_SM_UPDATE_FLAGS     update_flags = (T_SM_UPDATE_FLAGS)0;
  (void)TRACE_FUNCTION("handle_modify_pdp_context_accept_in_S6");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Stop timer T3381 */
  sm_timer_stop(context);

  /* Store GSM RAT parameters, if present */
  update_flags = sm_nw_store_modify_accept_parameters(context, msg);

  if (msg->v_qos != (U8)FALSE)
  {
    /* We requested no new QoS, but received one nontheless. */
    if (sm_qos_is_minimum_satisfied_by_aim(context, &msg->qos))
    {
      /* QoS >= minimum QoS: Store negotiated parameters */
      sm_qos_assign_from_aim(&context->accepted_qos, &msg->qos);
      update_flags     |= SM_UPDATE_QOS;
    } else {
      /* Minimum QoS no longer satisfied: Deactivate */
      sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
      sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

      context->network_control_state = SM_NETWORK_DEACTIVATING;

      sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_QOS_NOT_ACCEPTED);
      sm_context_control(context, SM_I_NETWORK_MODIFY_REJECTED, (void *)TRUE);

      return;
    } /* if (sm_qos_is_minimum_satisfied_by_aim) */
  }

  if (sm_tft_more_to_modify(context))
  {
    /* Start T3381 */
    sm_timer_start(context, SM_TIMER_T3381);
    /* Send MODIFY PDP CONTEXT REQUEST with remaining TFTs */
    send_msg_modify_pdp_context_request(context);
  } else {
    /* No more TFTs to add: Modification completed. */
    /* Go to state SM NETWORK ACTIVATED, and inform Context Control */
    context->network_control_state = SM_NETWORK_ACTIVATED;

    sm_context_control(context, SM_I_NETWORK_MODIFY_COMPLETED,
                       (void *)update_flags);
  }
}

/*
+------------------------------------------------------------------------------
| Function    : handle_modify_pdp_context_reject_in_S3
+------------------------------------------------------------------------------
| Description : Handle event SM_M_MODIFY_PDP_CONTEXT_REJECT in S3
|
| Parameters  : context          - Context data
|               data             - T_MODIFY_PDP_CONTEXT_REJECT *
+------------------------------------------------------------------------------
*/
static void handle_modify_pdp_context_reject_in_S3(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_MODIFY_PDP_CONTEXT_REJECT *msg = (T_MODIFY_PDP_CONTEXT_REJECT *)data;
  (void)TRACE_FUNCTION("handle_modify_pdp_context_reject_in_S3");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Go to state SM NETWORK DEACTIVATING */
  context->network_control_state = SM_NETWORK_DEACTIVATING;

  /* Save cause value for ACI */
  sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)msg->sm_cause.sm_cause_val);

  /* Stop T3381, start T3390, and send DEACTIVATE PDP CONTEXT REQUEST message */
  sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_REGULAR_DEACTIVATION);
  sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

  /* Inform Context Control of the failed activation (with network deactivation) */
  sm_context_control(context, SM_I_NETWORK_ACTIVATE_REJECTED, (void *)TRUE);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_modify_pdp_context_reject_in_S5
+------------------------------------------------------------------------------
| Description : Handle event SM_M_MODIFY_PDP_CONTEXT_REJECT in S5
|
| Parameters  : context          - Context data
|               data             - T_MODIFY_PDP_CONTEXT_REJECT *
+------------------------------------------------------------------------------
*/
static void handle_modify_pdp_context_reject_in_S5(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_MODIFY_PDP_CONTEXT_REJECT *msg = (T_MODIFY_PDP_CONTEXT_REJECT *)data;
  (void)TRACE_FUNCTION("handle_modify_pdp_context_reject_in_S5");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Go to state SM NETWORK DEACTIVATING */
  context->network_control_state = SM_NETWORK_DEACTIVATING;

  /* Save cause value for ACI */
  sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)msg->sm_cause.sm_cause_val);

  /* Stop T3381, start T3390, and send DEACTIVATE PDP CONTEXT REQUEST message */
  sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_REGULAR_DEACTIVATION);
  sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

  /* Inform Context Control of the failed modification */
  sm_context_control(context, SM_I_NETWORK_MODIFY_REJECTED, (void *)TRUE);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_modify_pdp_context_reject_in_S6
+------------------------------------------------------------------------------
| Description : Handle event SM_M_MODIFY_PDP_CONTEXT_REJECT in S6
|
| Parameters  : context          - Context data
|               data             - T_MODIFY_PDP_CONTEXT_REJECT *
+------------------------------------------------------------------------------
*/
static void handle_modify_pdp_context_reject_in_S6(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_MODIFY_PDP_CONTEXT_REJECT *msg = (T_MODIFY_PDP_CONTEXT_REJECT *)data;
  (void)TRACE_FUNCTION("handle_modify_pdp_context_reject_in_S6");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Go to state SM NETWORK DEACTIVATING */
  context->network_control_state = SM_NETWORK_DEACTIVATING;

  /* Save cause value for ACI */
  sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)msg->sm_cause.sm_cause_val);

  /* Stop T3381, start T3390, and send DEACTIVATE PDP CONTEXT REQUEST message */
  sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_REGULAR_DEACTIVATION);
  sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

  /* Inform Context Control of the failed modification */
  sm_context_control(context, SM_I_NETWORK_MODIFY_REJECTED, (void *)TRUE);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_deactivate_pdp_context_request_while_active
+------------------------------------------------------------------------------
| Description : Handle event SM_M_DEACTIVATE_PDP_CONTEXT_REQUEST in S1 - S6
|
| Parameters  : context          - Context data
|               data             - T_DEACTIVATE_PDP_CONTEXT_REQUEST *
+------------------------------------------------------------------------------
*/
static void handle_deactivate_pdp_context_request_while_active(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  BOOL tear_down;
  T_DEACTIVATE_PDP_CONTEXT_REQUEST *msg = (T_DEACTIVATE_PDP_CONTEXT_REQUEST *)data;
  (void)TRACE_FUNCTION("handle_deactivate_pdp_context_request_while_active");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  /* Stop any active timers */
  sm_timer_stop(context);

  /* Free stored coded message - if any */
  sm_free_coded_msg(context);

  if (msg->v_tear_down != (U8)FALSE && msg->tear_down.tear_down_flag == (U8)1)
  {
    tear_down = TRUE;
    /* Mark linked contexts as inactive */
    sm_nw_mark_nsapi_set_inactive(sm_linked_nsapis(context->ti));
  } else {
    tear_down = FALSE;
  };

  /* Mark context as inactive */
  sm_nw_mark_context_inactive(context->nsapi);

  /* Save cause for ACI */
  sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)msg->sm_cause.sm_cause_val);

  /* Send DEACTIVATE PDP CONTEXT ACCEPT message */
  send_msg_deactivate_pdp_context_accept(context);

  /* Go to state SM NETWORK DEACTIVATED */
  context->network_control_state = SM_NETWORK_DEACTIVATED;

  /* Report deactivation to Context Control */
  sm_context_control(context, SM_I_NETWORK_REQUEST_DEACTIVATE, (void *)tear_down);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_deactivate_pdp_context_request_while_deactivating
+------------------------------------------------------------------------------
| Description : Handle event SM_M_DEACTIVATE_PDP_CONTEXT_REQUEST in S7
|
| Parameters  : context          - Context data
|               data             - T_DEACTIVATE_PDP_CONTEXT_REQUEST *
+------------------------------------------------------------------------------
*/
static void handle_deactivate_pdp_context_request_while_deactivating(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data)
{
  T_DEACTIVATE_PDP_CONTEXT_REQUEST *msg = (T_DEACTIVATE_PDP_CONTEXT_REQUEST *)data;
  (void)TRACE_FUNCTION("handle_deactivate_pdp_context_request_while_deactivating");

  TRACE_ASSERT(msg != NULL);

  if (msg EQ NULL)
    return;

  /* Save cause for ACI */
  sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)msg->sm_cause.sm_cause_val);

  /* Send DEACTIVATE PDP CONTEXT ACCEPT message */
  send_msg_deactivate_pdp_context_accept(context);

  /* Report deactivation to Context Control iff tear_down == TRUE */
  if (msg->v_tear_down != (U8)FALSE && msg->tear_down.tear_down_flag == (U8)1)
  {
    sm_context_control(context, SM_I_NETWORK_REQUEST_DEACTIVATE, (void *)TRUE);
  }
}

/*
+------------------------------------------------------------------------------
| Function    : handle_deactivate_pdp_context_accept
+------------------------------------------------------------------------------
| Description : Handle event SM_M_DEACTIVATE_PDP_CONTEXT_ACCEPT in S7
|
| Parameters  : context          - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void handle_deactivate_pdp_context_accept(struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/ void *data)
{
  (void)TRACE_FUNCTION("handle_deactivate_pdp_context_accept");

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Stop T3390 */
  sm_timer_stop(context);

  /* Go to state SM NETWORK DEACTIVATED */
  context->network_control_state = SM_NETWORK_DEACTIVATED;

  /* Mark context as inactive */
  sm_nw_mark_context_inactive(context->nsapi);

  /* Report deactivate complete to Context Control */
  sm_context_control(context, SM_I_NETWORK_DEACTIVATE_COMPLETED, NULL);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_T3380
+------------------------------------------------------------------------------
| Description : Handle event SM_T_T3380
|
| Parameters  : context          - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void handle_T3380(struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/void *data)
{
  (void)TRACE_FUNCTION("handle_T3380");

  /* If SM is not suspended, resend ACTIVATE (SECONDARY) PDP CONTEXT REQUEST */
  resend_msg(context);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_T3380_max
+------------------------------------------------------------------------------
| Description : Handle event SM_T_T3380_MAX
|
| Parameters  : context          - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void handle_T3380_max(struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/void *data)
{
  (void)TRACE_FUNCTION("handle_T3380_max");

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Go to state SM NETWORK DEACTIVATED */
  context->network_control_state = SM_NETWORK_DEACTIVATED;

  /* Inform Context Control of the failed activation (no network deactivation) */
  sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_NETWORK_FAILURE);
  sm_context_control(context, SM_I_NETWORK_ACTIVATE_REJECTED, (void *)FALSE);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_T3381
+------------------------------------------------------------------------------
| Description : Handle event SM_T_T3381
|
| Parameters  : context          - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void handle_T3381(struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/void *data)
{
  (void)TRACE_FUNCTION("handle_T3381");

  /* If SM is not suspended, resend MODIFY PDP CONTEXT REQUEST */
  resend_msg(context);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_T3381_max_in_S3
+------------------------------------------------------------------------------
| Description : Handle event SM_T_T3381_MAX in S3
|
| Parameters  : context          - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void handle_T3381_max_in_S3(struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/void *data)
{
  (void)TRACE_FUNCTION("handle_T3381_max_in_S3");

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Go to state SM NETWORK DEACTIVATING */
  context->network_control_state = SM_NETWORK_DEACTIVATING;

  /* Initiate deactivation */
  sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_REGULAR_DEACTIVATION);
  sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

  /* Inform Context Control of the failed activation */
  sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_NETWORK_FAILURE);
  sm_context_control(context, SM_I_NETWORK_ACTIVATE_REJECTED, (void *)TRUE);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_T3381_max_in_S5
+------------------------------------------------------------------------------
| Description : Handle event SM_T_T3381_MAX in S5
|
| Parameters  : context          - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void handle_T3381_max_in_S5(struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/void *data)
{
  (void)TRACE_FUNCTION("handle_T3381_max_in_S5");

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Modify procedure has failed, but the context remains active. */
  /* Go to state SM NETWORK ACTIVATED */
  context->network_control_state = SM_NETWORK_ACTIVATED;

  /* Inform Context Control of the failed activation */
  sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_NETWORK_FAILURE);
  sm_context_control(context, SM_I_NETWORK_MODIFY_REJECTED, (void *)FALSE);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_T3381_max_in_S6
+------------------------------------------------------------------------------
| Description : Handle event SM_T_T3381_MAX in S6
|
| Parameters  : context          - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void handle_T3381_max_in_S6(struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/void *data)
{
  (void)TRACE_FUNCTION("handle_T3381_max_in_S6");

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Go to state SM NETWORK DEACTIVATING */
  context->network_control_state = SM_NETWORK_DEACTIVATING;

  /* Initiate deactivation */
  sm_set_nw_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_REGULAR_DEACTIVATION);
  sm_nw_initiate_deactivation(context, sm_get_nw_cause(context));

  /* Inform Context Control of the failed activation */
  sm_set_aci_cause(context, CAUSE_is_from_nwsm, (U16)CAUSE_NWSM_NETWORK_FAILURE);
  sm_context_control(context, SM_I_NETWORK_MODIFY_REJECTED, (void *)TRUE);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_T3390
+------------------------------------------------------------------------------
| Description : Handle event SM_T_T3390
|
| Parameters  : context          - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void handle_T3390(struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/void *data)
{
  (void)TRACE_FUNCTION("handle_T3390");

  /* If SM is not suspended, resend DEACTIVATE PDP CONTEXT REQUEST */
  resend_msg(context);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_T3390_max
+------------------------------------------------------------------------------
| Description : Handle event SM_T_T3390_MAX
|
| Parameters  : context          - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void handle_T3390_max(struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/void *data)
{
  (void)TRACE_FUNCTION("handle_T3390_max");

  /* Free stored coded message */
  sm_free_coded_msg(context);

  /* Go to state SM NETWORK DEACTIVATED */
  context->network_control_state = SM_NETWORK_DEACTIVATED;

  /* Context is considered deactivated.  Inform Context Control. */
  sm_context_control(context, SM_I_NETWORK_DEACTIVATE_COMPLETED, NULL);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_mmpm_suspend_ind
+------------------------------------------------------------------------------
| Description : Handle incoming MMPM_SUSPEND_IND primitive
|
| Parameters  : context         - Context data
|               data            - Unused
+------------------------------------------------------------------------------
*/
static void handle_mmpm_suspend_ind(/*@unused@*/struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/ void *data)
{
  (void)TRACE_FUNCTION("handle_mmpm_suspend_ind");
}

/*
+------------------------------------------------------------------------------
| Function    : handle_mmpm_resume_ind
+------------------------------------------------------------------------------
| Description : Handle incoming MMPM_RESUME_IND primitive
|
| Parameters  : context         - Context data
|               data            - Unused
+------------------------------------------------------------------------------
*/
static void handle_mmpm_resume_ind(struct T_SM_CONTEXT_DATA *context, /*@null@*/ /*@unused@*/ void *data)
{
  (void)TRACE_FUNCTION("handle_mmpm_resume_ind");

  if (sm_is_started_during_suspend(context))
  {
    resend_msg(context);
    sm_clear_started_during_suspend(context);
  }
}

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

/*
+------------------------------------------------------------------------------
| Function    : sm_network_control_init
+------------------------------------------------------------------------------
| Description : Network Control state machine initialization function

| Parameters  : context  - Context data
+------------------------------------------------------------------------------
*/
void sm_network_control_init(struct T_SM_CONTEXT_DATA *context)
{
  (void)TRACE_FUNCTION("sm_network_control_init");

  context->network_control_state = SM_NETWORK_DEACTIVATED;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_network_control_exit
+------------------------------------------------------------------------------
| Description : Network Control state machine exit function

| Parameters  : context  - Context data
+------------------------------------------------------------------------------
*/
void sm_network_control_exit(struct T_SM_CONTEXT_DATA *context)
{
  (void)TRACE_FUNCTION("sm_network_control_exit");

  context->network_control_state = SM_NETWORK_DEACTIVATED;

  /* Free any memory allocated to this context (fields managed by Network Control) */
  sm_free_coded_msg(context);
  sm_nw_free_apn(context);
  sm_nw_free_requested_tft(context);
  sm_nw_free_active_tft(context);
  sm_nw_free_requested_pco(context);
  sm_nw_free_negotiated_pco(context);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_network_control_state
+------------------------------------------------------------------------------
| Description : Returns a read-only string with the name of the active state.

| Parameters  : context  - Context data
+------------------------------------------------------------------------------
*/
#ifdef DEBUG
/*@observer@*/const char *
sm_network_control_state(struct T_SM_CONTEXT_DATA *context)
{
  /*@observer@*/
  static const char *state_name[SM_NETWORK_CONTROL_NUMBER_OF_STATES] = {
    "S0_SM_NETWORK_DEACTIVATED",
    "S1_SM_NETWORK_ACTIVATING_PRIMARY",
    "S2_SM_NETWORK_ACTIVATING_SECONDARY",
    "S3_SM_NETWORK_ACTIVATING_ADDING_TFTS",
    "S4_SM_NETWORK_ACTIVATED",
    "S5_SM_NETWORK_MODIFYING",
    "S6_SM_NETWORK_MODIFYING_ADDITIONAL_TFTS",
    "S7_SM_NETWORK_DEACTIVATING"
  };

  TRACE_ASSERT(context->network_control_state < SM_NETWORK_CONTROL_NUMBER_OF_STATES);

  return state_name[(U16)context->network_control_state];
}
#endif
/*
+------------------------------------------------------------------------------
| Function    : sm_network_control
+------------------------------------------------------------------------------
| Description : User Plane Control state machine
|
| Parameters  : context          - Context data
|               event            - Internal event (see sm_network_control.h)
|               data             - Event dependent parameter
+------------------------------------------------------------------------------
*/
void sm_network_control(struct T_SM_CONTEXT_DATA *context,
                        T_SM_NETWORK_CONTROL_EVENT event,
                        /*@null@*/ void *data)
{
#ifdef DEBUG
  const char *old_state_name, *new_state_name;
  T_SM_NETWORK_CONTROL_STATE old_state;
  /*@observer@*/
  static const char *event_name[SM_NETWORK_CONTROL_NUMBER_OF_EVENTS] = {
    "SM_M_ACTIVATE_PDP_CONTEXT_ACCEPT",
    "SM_M_ACTIVATE_PDP_CONTEXT_REJECT",
    "SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_ACCEPT",
    "SM_M_ACTIVATE_SECONDARY_PDP_CONTEXT_REJECT",
    "SM_M_DEACTIVATE_PDP_CONTEXT_REQUEST",
    "SM_M_DEACTIVATE_PDP_CONTEXT_ACCEPT",
    "SM_M_MODIFY_PDP_CONTEXT_REQUEST",
    "SM_M_MODIFY_PDP_CONTEXT_ACCEPT",
    "SM_M_MODIFY_PDP_CONTEXT_REJECT",
    "SM_M_REQUEST_PDP_CONTEXT_ACTIVATION",
    "SM_M_SM_STATUS",
    "SM_P_MMPM_RESUME_IND",
    "SM_P_MMPM_SUSPEND_IND",
    "SM_T_T3380",
    "SM_T_T3380_MAX",
    "SM_T_T3381",
    "SM_T_T3381_MAX",
    "SM_T_T3390",
    "SM_T_T3390_MAX",
    "SM_I_NETWORK_ACTIVATE_PRIMARY",
    "SM_I_NETWORK_ACTIVATE_SECONDARY",
    "SM_I_NETWORK_DEACTIVATE_LOCAL",
    "SM_I_NETWORK_MODIFY",
    "SM_I_NETWORK_REQUEST_ACTIVATION_REJECT",
    "SM_I_NETWORK_DEACTIVATE"
  };

  TRACE_ASSERT(event < SM_NETWORK_CONTROL_NUMBER_OF_EVENTS);

  old_state = context->network_control_state;
  old_state_name = sm_network_control_state(context);

  if (transition[(U16)old_state][(U16)event].event != event)
  {
    (void)TRACE_ERROR("Event table error in sm_network_control!");
  }
#endif /* DEBUG */

  transition[(U16)context->network_control_state][(U16)event].func(context, data);

#ifdef DEBUG
  new_state_name = sm_network_control_state(context);

  (void)TRACE_EVENT_P4("SM NETWORK #%d: %s => %s to %s", context->nsapi,
                       event_name[(U16)event], old_state_name, new_state_name);
#endif /* DEBUG */
}

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