view src/g23m-gprs/gmm/gmm_pei.c @ 480:41f2cc21bca9

hybrid fw: code change to support allowing GSM APDUs in AT+CSIM
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 19 Jun 2018 06:27:16 +0000
parents 219afcfc6250
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  GPRS (8441)
|  Modul   :  gmm_pei.c
+----------------------------------------------------------------------------- 
|  Copyright 2002 Texas Instruments Berlin, AG 
|                 All rights reserved. 
| 
|                 This file is confidential and a trade secret of Texas 
|                 Instruments Berlin, AG 
|                 The receipt of or possession of this file does not convey 
|                 any rights to reproduce or disclose its contents or to 
|                 manufacture, use, or sell anything it may describe, in 
|                 whole, or in part, without the specific written consent of 
|                 Texas Instruments Berlin, AG. 
+----------------------------------------------------------------------------- 
|  Purpose :  This module implements the process body interface
|             for the entity GPRS Mobility Management (GMM)
|             
|             Exported functions:
|             
|             pei_create    - Create the Protocol Stack Entity
|             pei_init      - Initialize Protocol Stack Entity
|             pei_primitive - Process Primitive
|             pei_timeout   - Process Timeout
|             pei_exit      - Close resources and terminate
|             pei_run       - Process Primitive
|             pei_config    - Dynamic Configuration
|             pei_monitor   - Monitoring of physical Parameters
+----------------------------------------------------------------------------- 
*/ 


#define GMM_PEI_C

#define ENTITY_GMM

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

#include <stddef.h>     /* to get definition of offsetof(), for MAK_FUNC_S */
#include <stdlib.h>     /* to get atoi for tokenizer in pei_init */
#include "typedefs.h"   /* to get Condat data types */
#include "vsi.h"        /* to get a lot of macros */
#include "macdef.h"
#include "gprs.h"
#include "gsm.h"        /* to get a lot of macros */
#include "cnf_gmm.h"    /* to get cnf-definitions */
#include "mon_gmm.h"    /* to get mon-definitions */
#include "prim.h"       /* to get the definitions of used SAP and directions */
#include "pei.h"        /* to get PEI interface */
#include "gmm.h"        /* to get the global entity definitions */
#include "gmm_f.h"      /* to get the debug print function */

#include "gmm_kernp.h"  /* to get primitive interface to KERN */
#include "gmm_txp.h"    /* to get primitive interface to TX */
#include "gmm_rxp.h"    /* to get primitive interface to RX */
#include "gmm_rdyp.h"   /* to get primitive interface to RDY */
#include "gmm_syncp.h"  /* to get primitive interface to SYNC */

#include "gmm_kernf.h"  /* to get functions from KERN */
#include "gmm_txf.h"    /* to get functions from TX */
#include "gmm_rxf.h"    /* to get functions from RX */
#include "gmm_rdyf.h"   /* to get functions from RDY */
#include "gmm_syncf.h"  /* to get functions from SYNC */


#include "ccdapi.h"     /* to get ccd stuff */
#include "tok.h"        /* to get tokenizer */
#include  <string.h>    /* to get memcpy */

#include "gmm_em.h"     /*to get definitions of the Engineering Mode*/
/*==== DEFINITIONS ==========================================================*/

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

/*==== GLOBAL VARS ==========================================================*/

/*==== LOCAL VARS ===========================================================*/

static  BOOL          first_access  = TRUE;
static  T_MONITOR     gmm_mon;

/*
 * Jumptables to primitive handler functions. One table per SAP.
 *
 * Use MAK_FUNC_0 for primitives which contains no SDU.
 * Use MAK_FUNC_S for primitives which contains a SDU.
 */

/*******************************************************
 * SAVE prim
 *******************************************************/

#define PEI_SIGNAL_NOT_SAVED      FALSE
#define PEI_SIGNAL_SAVED          TRUE
#define PEI_END_SAVETAB           0xFF

#define GMM_MAX_SIGNALS_SAVED      5     /* value adjusted to GMM requirements */

typedef struct SAVE_QUEUE
{
  void*              prim;
  T_VOID_FUNC        func;
  struct SAVE_QUEUE* next;
} T_SAVE_QUEUE;

void gmm_pei_delete_queue( T_SAVE_QUEUE** queue );

typedef struct
{
  USHORT  state;
  USHORT  signal[GMM_MAX_SIGNALS_SAVED];
} T_SAVE_TAB;

/*==== LOCAL PROTOTYPES =====================================================*/
LOCAL void gmm_pei_handle_prim( T_VOID_FUNC func, void* prim );
LOCAL BOOL gmm_pei_handle_save( void* prim, T_SAVE_QUEUE** queue,
                                     const T_SAVE_TAB* table, T_VOID_FUNC func);
LOCAL void gmm_pei_handle_queue( T_SAVE_QUEUE** queue,
                                      const T_SAVE_TAB* table);

/*==== VAR LOCAL ============================================================*/

LOCAL T_SAVE_QUEUE*     save_queue;     /* SAVE queue hangers */

LOCAL const T_SAVE_TAB save_tab[] = {

  { KERN_GMM_REG_INITIATED,      
                            {MMGMM_LUP_NEEDED_IND,
                             GMMREG_NET_REQ, 
                             GMMREG_PLMN_RES,
                             0, 0 }
  },

  { KERN_GMM_RAU_INITIATED,      
                            {MMGMM_LUP_NEEDED_IND,
                             GMMREG_DETACH_REQ,
                             GMMREG_NET_REQ, 
                             GMMREG_PLMN_RES,
                             0 }
  },

  {KERN_GMM_RAU_WAIT_FOR_NPDU_LIST ,
                           {GMMRR_CELL_IND, 
                            0, 0, 0, 0 }
  },
  { KERN_GMM_DEREG_SUSPENDING,
                            {GMMREG_NET_REQ, 
                             GMMREG_PLMN_RES,
                             GMMRR_CS_PAGE_IND,
                             MMGMM_CM_ESTABLISH_IND,
                             MMGMM_CM_EMERGENCY_IND     }
  },
  { KERN_GMM_REG_SUSPENDING,
                            {GMMREG_NET_REQ, 
                             GMMREG_PLMN_RES,
                             GMMRR_CS_PAGE_IND,
                             MMGMM_CM_ESTABLISH_IND,
                             MMGMM_CM_EMERGENCY_IND     }
  },
  { KERN_GMM_REG_RESUMING,
                            {GMMREG_DETACH_REQ, 
                             GMMRR_CS_PAGE_IND,
                             MMGMM_CM_ESTABLISH_IND,
                             MMGMM_CM_EMERGENCY_IND,
                             GMMREG_ATTACH_REQ }
  },
  { KERN_GMM_DEREG_RESUMING,
                            {GMMREG_DETACH_REQ, 
                             GMMRR_CS_PAGE_IND,
                             MMGMM_CM_ESTABLISH_IND,
                             MMGMM_CM_EMERGENCY_IND,
                             GMMREG_ATTACH_REQ}
  },
  { PEI_END_SAVETAB,
                           { 0, 0, 0, 0, 0 }
  }
};
/*******************************************************
 * End SAVE prim
 *******************************************************/


/*
 * Function is needed for grr_table[]. This declaration can be removed
 * as soon as this function is no more called (i.e. all primitives are
 * handled).
 */
LOCAL void primitive_not_supported (void *data);

static const T_FUNC gmmreg_table[] =
{
  MAK_FUNC_0(kern_gmmreg_attach_req,        GMMREG_ATTACH_REQ),
  MAK_FUNC_0(kern_gmmreg_detach_req,        GMMREG_DETACH_REQ),
  MAK_FUNC_0(kern_gmmreg_net_req,           GMMREG_NET_REQ),
  MAK_FUNC_0(kern_gmmreg_plmn_res,          GMMREG_PLMN_RES),
  MAK_FUNC_0(kern_gmmreg_plmn_mode_req,     GMMREG_PLMN_MODE_REQ),
  MAK_FUNC_0(kern_gmmreg_config_req,        GMMREG_CONFIG_REQ),
};

#ifdef FF_EM_MODE
static const T_FUNC em_ul_table[] =
{
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x00 */
  /*EM_SC_GPRS_INFO_REQ cannot be sent directly from ACI to GRR, because no SAP is defined.
  So it have to be passed via GMM.*/
  MAK_FUNC_0(em_gmm_sc_gprs_info_req,       EM_SC_GPRS_INFO_REQ     ), /* 0x01 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x02 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x03 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x04 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x05 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x06 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x07 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x08 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x09 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x0A */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x0B */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x0C */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x0D */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x0E */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x0F */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x10 */
  MAK_FUNC_0(em_gmm_pco_trace_req   ,       EM_PCO_TRACE_REQ   ), /* 0x11*/ /*PCO output*/
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x12 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x13 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x14 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x15 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x16 */
  MAK_FUNC_0(em_gmm_info_req,                EM_GMM_INFO_REQ   ), /* 0x17 */
  /*EM_GRLC_INFO_REQ cannot be sent directly from ACI to GRLC, so it is passed via GMM*/
  MAK_FUNC_0(em_gmm_grlc_info_req,          EM_GRLC_INFO_REQ        ),  /* 0x18 */
  MAK_FUNC_N(primitive_not_supported,       0                       ), /* 0x19 */
  MAK_FUNC_0(em_gmm_grr_event_req,          EM_GRR_EVENT_REQ        ), /* 0x1A */
  MAK_FUNC_0(em_gmm_event_req,              EM_GMM_EVENT_REQ        ), /* 0x1B */
  MAK_FUNC_0(em_gmm_grlc_event_req,         EM_GRLC_EVENT_REQ       ), /* 0x1C */
  MAK_FUNC_0(em_gmm_throughput_info_req,    EM_THROUGHPUT_INFO_REQ  ) /* 0x1D */
};

static const T_FUNC em_dl_table[] =
{
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x00 */
/*EM_SC_GPRS_INFO_CNF cannot be sent directly from GRR to ACI, so it is passed via GMM*/
  MAK_FUNC_0(em_gmm_sc_gprs_info_cnf,       EM_SC_GPRS_INFO_CNF      ), /* 0x01 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x02 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x03 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x04 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x05 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x06 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x07 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x08 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x09 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x0A */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x0B */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x0C */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x0D */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x0E */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x0F */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x10 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x11 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x12 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x13 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x14 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x15 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x16 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* 0x17 */
/*EM_GRLC_INFO_CNF cannot be sent directly from ACI to GRLC, so it is passed via GMM*/
  MAK_FUNC_0(em_gmm_grlc_info_cnf,          EM_GRLC_INFO_CNF         ), /* 0x18 */
  MAK_FUNC_N(primitive_not_supported,       0                        ), /* 0x19 */
  MAK_FUNC_N(primitive_not_supported,       0                        ), /* 0x1A */
  MAK_FUNC_N(primitive_not_supported,       0                        ), /* 0x1B */
  MAK_FUNC_N(primitive_not_supported,       0                        ), /* 0x1C */
  MAK_FUNC_0(em_gmm_throughput_info_cnf,    EM_THROUGHPUT_INFO_CNF   ) /* 0x1D */
};
#endif /* FF_EM_MODE */  


static const T_FUNC gmmrr_table[] =
{
  MAK_FUNC_0(sync_gmmrr_cell_ind,           GMMRR_CELL_IND),
  MAK_FUNC_N(primitive_not_supported,       0                  ),
  MAK_FUNC_0(kern_gmmrr_page_ind,           GMMRR_PAGE_IND),
  MAK_FUNC_0(kern_gmmrr_cs_page_ind,        GMMRR_CS_PAGE_IND),
  MAK_FUNC_0(kern_gmmrr_suspend_cnf,        GMMRR_SUSPEND_CNF),
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* TCS 2.1 */
  MAK_FUNC_N(primitive_not_supported,       0                  ),/* TCS 2.1 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* TCS 2.1 */
  MAK_FUNC_0(kern_gmmrr_cr_ind,             GMMRR_CR_IND),
};


static const T_FUNC cgrlc_table[] = /* TCS 2.1 */
{ /* TCS 2.1 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* TCS 2.1 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* TCS 2.1 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* TCS 2.1 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* TCS 2.1 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* TCS 2.1 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* TCS 2.1 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* TCS 2.1 */
  MAK_FUNC_N(primitive_not_supported,       0                  ), /* TCS 2.1 */
  MAK_FUNC_0(kern_cgrlc_status_ind,         CGRLC_STATUS_IND ), /* TCS 2.1 */
  MAK_FUNC_0(kern_cgrlc_test_mode_cnf,      CGRLC_TEST_MODE_CNF ), /* TCS 2.1 */
  MAK_FUNC_0(rdy_cgrlc_trigger_ind,         CGRLC_TRIGGER_IND ), /* TCS 2.1 */
  MAK_FUNC_0(rdy_cgrlc_standby_state_ind,   CGRLC_STANDBY_STATE_IND ), /* TCS 2.1 */
  MAK_FUNC_0(rdy_cgrlc_ready_state_ind,     CGRLC_READY_STATE_IND ), /* TCS 2.1 */
}; /* TCS 2.1 */


#ifndef GMM_TCS4
static const T_FUNC gmmsm_table[] =
{
  MAK_FUNC_0(kern_gmmsm_establish_req,      GMMSM_ESTABLISH_REQ),
  MAK_FUNC_S(tx_gmmsm_unitdata_req,         GMMSM_UNITDATA_REQ),
  MAK_FUNC_0(kern_gmmsm_sequence_res,       GMMSM_SEQUENCE_RES),
};
#else   
static const T_FUNC mmpm_table[] =
{
#ifdef REL99
  MAK_FUNC_0(kern_gmmsm_pdp_status_req,    MMPM_PDP_CONTEXT_STATUS_REQ),
#else
  MAK_FUNC_0(primitive_not_supported,      MMPM_PDP_CONTEXT_STATUS_REQ),
#endif
  MAK_FUNC_N(primitive_not_supported,      0),
  MAK_FUNC_N(primitive_not_supported,      0),
  MAK_FUNC_0(kern_gmmsm_sequence_res,      MMPM_SEQUENCE_RES),
  MAK_FUNC_S(tx_gmmsm_unitdata_req,        MMPM_UNITDATA_REQ),
};

#endif /* #ifndef GMM_TCS4 */

static const T_FUNC gmmsms_table[] =
{
  MAK_FUNC_0(kern_gmmsms_reg_state_req,     GMMSMS_REG_STATE_REQ)
};

LOCAL const T_FUNC sim_table[] = {
  MAK_FUNC_0 (primitive_not_supported      , SIM_READ_CNF           ), /* 0x00 */
  MAK_FUNC_0 (primitive_not_supported      , SIM_UPDATE_CNF         ),
  MAK_FUNC_0 (primitive_not_supported      , SIM_READ_RECORD_CNF    ),
  MAK_FUNC_N (primitive_not_supported      , 0                      ),
  MAK_FUNC_0 (primitive_not_supported      , SIM_UPDATE_RECORD_CNF  ),
  MAK_FUNC_N (primitive_not_supported      , 0                      ),
  MAK_FUNC_N (primitive_not_supported      , 0                      ),
  MAK_FUNC_N (primitive_not_supported      , 0                      ),
  MAK_FUNC_0 (primitive_not_supported      , SIM_INCREMENT_CNF      ),
  MAK_FUNC_0 (primitive_not_supported      , SIM_VERIFY_PIN_CNF     ),
  MAK_FUNC_0 (primitive_not_supported      , SIM_CHANGE_PIN_CNF     ),
  MAK_FUNC_0 (primitive_not_supported      , SIM_DISABLE_PIN_CNF    ),
  MAK_FUNC_0 (primitive_not_supported      , SIM_ENABLE_PIN_CNF     ),
  MAK_FUNC_0 (primitive_not_supported      , SIM_UNBLOCK_CNF        ),
  MAK_FUNC_0 (kern_sim_authentication_cnf       , SIM_AUTHENTICATION_CNF ),
  MAK_FUNC_0 (primitive_not_supported      , SIM_MMI_INSERT_IND     ),
  MAK_FUNC_0 (primitive_not_supported      , SIM_MM_INSERT_IND   ),  
  MAK_FUNC_0 (kern_sim_remove_ind    , SIM_REMOVE_IND         ),
  MAK_FUNC_0 (primitive_not_supported      , SIM_SYNC_CNF           ),
  MAK_FUNC_0 (primitive_not_supported      , SIM_ACTIVATE_CNF       ),
  MAK_FUNC_0 (primitive_not_supported      , SIM_SMS_INSERT_IND     ), /* 0x14 */
  MAK_FUNC_0 (primitive_not_supported      , SIM_TOOLKIT_IND        ), /* 0x15 */
  MAK_FUNC_0 (primitive_not_supported      , SIM_TOOLKIT_CNF        ), /* 0x16 */
  MAK_FUNC_0 (primitive_not_supported      , SIM_ACTIVATE_IND       ), /* 0x17 */
  MAK_FUNC_0 (primitive_not_supported      , SIM_MM_INFO_IND        ), /* 0x18 GMM GlumPs*/
  MAK_FUNC_0 (primitive_not_supported      , SIM_ACCESS_CNF         ), /* 0x19 */
  MAK_FUNC_0 (primitive_not_supported   , SIM_FILE_UPDATE_IND    ),  /* 0x1a */
  MAK_FUNC_0 (kern_sim_gmm_insert_ind  , SIM_GMM_INSERT_IND   ),  /* 0x1b */
};

static const T_FUNC ll_table[] =
{
  MAK_FUNC_0(primitive_not_supported,       LL_RESET_IND),
  MAK_FUNC_S(primitive_not_supported,       LL_ESTABLISH_CNF),
  MAK_FUNC_S(primitive_not_supported,       LL_ESTABLISH_IND),
  MAK_FUNC_0(primitive_not_supported,       LL_RELEASE_CNF),
  MAK_FUNC_0(primitive_not_supported,       LL_RELEASE_IND),
  MAK_FUNC_S(primitive_not_supported,       LL_XID_CNF),
  MAK_FUNC_S(primitive_not_supported,       LL_XID_IND),
  MAK_FUNC_0(primitive_not_supported,       LL_READY_IND),
  MAK_FUNC_0(primitive_not_supported,       LL_UNITREADY_IND),
  MAK_FUNC_0(primitive_not_supported,       LL_DATA_CNF),
  MAK_FUNC_S(primitive_not_supported,       LL_DATA_IND),
  MAK_FUNC_S(rx_ll_unitdata_ind,            LL_UNITDATA_IND)
};

static const T_FUNC llgmm_table[] =
{
  MAK_FUNC_0(kern_llgmm_status_ind,         LLGMM_STATUS_IND),
  MAK_FUNC_0(kern_llgmm_tlli_ind,         LLGMM_TLLI_IND)
};

static const T_FUNC mmgmm_table[] =
{
  MAK_FUNC_0(sync_mmgmm_reg_cnf,            MMGMM_REG_CNF),
  MAK_FUNC_0(sync_mmgmm_reg_rej,            MMGMM_REG_REJ),
  MAK_FUNC_0(sync_mmgmm_nreg_ind,           MMGMM_NREG_IND),
  MAK_FUNC_0(kern_mmgmm_nreg_cnf,           MMGMM_NREG_CNF),
  MAK_FUNC_0(kern_mmgmm_plmn_ind,           MMGMM_PLMN_IND),
  MAK_FUNC_0(kern_mmgmm_auth_rej_ind,       MMGMM_AUTH_REJ_IND),
  MAK_FUNC_0(kern_mmgmm_cm_establish_ind,   MMGMM_CM_ESTABLISH_IND),
  MAK_FUNC_0(kern_mmgmm_cm_release_ind,     MMGMM_CM_RELEASE_IND),
  MAK_FUNC_0(sync_mmgmm_activate_ind,       MMGMM_ACTIVATE_IND),
  MAK_FUNC_0(kern_mmgmm_t3212_val_ind,      MMGMM_T3212_VAL_IND),
  MAK_FUNC_0(kern_mmgmm_info_ind,           MMGMM_INFO_IND),
  MAK_FUNC_0(kern_mmgmm_cm_emergency_ind,   MMGMM_CM_EMERGENCY_IND),
  MAK_FUNC_0(kern_mmgmm_lup_accept_ind,     MMGMM_LUP_ACCEPT_IND),
  MAK_FUNC_0(kern_mmgmm_lup_needed_ind,     MMGMM_LUP_NEEDED_IND),
  MAK_FUNC_0(kern_mmgmm_ciphering_ind,      MMGMM_CIPHERING_IND),
  MAK_FUNC_0(kern_mmgmm_tmsi_ind,           MMGMM_TMSI_IND),
  MAK_FUNC_0(kern_mmgmm_ahplmn_ind,         MMGMM_AHPLMN_IND)
};


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

/*
+------------------------------------------------------------------------------
|  Function    : primitive_not_supported
+------------------------------------------------------------------------------
|  Description  :  This function handles unsupported primitives.
|
|  Parameters  :  -
|
|  Return      :  -
|
+------------------------------------------------------------------------------
*/
LOCAL void primitive_not_supported (void *data)
{
  TRACE_FUNCTION ("primitive_not_supported");

  PFREE (data);
}


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

/*
+------------------------------------------------------------------------------
|  Function    : pei_primitive
+------------------------------------------------------------------------------
|  Description  :  This function is called by the frame when a primitive is
|                received and needs to be processed.
|
|                             |
|                          GMMREG
|                       |     |     |     |
|                     GMMSM   |   GMMSM GMMAA             UPLINK
|                       |     |     |     |
|                   +---v-----v-----v-----v----+
|                   |                          |
|         MMGMM ---->           GMM            |
|                   |                          |
|                   +---^--------^--------^----+
|                       |        |        |
|                       |        |      LLGMM            DOWNLINK
|                       |      GMMRR      |
|                       |        |
|                     SIM
|                       |
|
|
|  Parameters  :  prim      - Pointer to the received primitive
|
|  Return      :  PEI_OK    - function succeeded
|               PEI_ERROR - function failed
|
+------------------------------------------------------------------------------
*/
LOCAL SHORT pei_primitive (void * primptr)
{
  TRACE_FUNCTION ("pei_primitive");
#ifdef TRACE_FUNC
#ifdef IDENTATION
  gmm_data->deep=0;
#endif
#endif

  if (primptr NEQ NULL)
  {
    T_PRIM *prim  = (T_PRIM *)primptr;
    ULONG           opc = prim->custom.opc;
    USHORT           n;
    const T_FUNC    *table;

    /*
     * This must be called for Partition Pool supervision. Will be replaced
     * by another macro some time.
     */
    VSI_PPM_REC (&prim->custom, __FILE__, __LINE__);

    GMM_TRACE_GMM_DATA(GMM_DEBUG_PRINT_MASK_STATE);
    PTRACE_IN (opc);

    switch (SAP_NR(opc))
    {
      case GMMREG_UL:
        table = gmmreg_table;
        n = TAB_SIZE (gmmreg_table);
        break;
      case GMMRR_DL:
        table = gmmrr_table;
        n = TAB_SIZE (gmmrr_table);
        break;      
      case SAP_NR(CGRLC_DL):  /* TCS 2.1 */
        table = cgrlc_table;  /* TCS 2.1 */
        n = TAB_SIZE (cgrlc_table); /* TCS 2.1 */
        break; /* TCS 2.1 */
#ifndef GMM_TCS4
      case GMMSM_UL:
        table = gmmsm_table;
        n = TAB_SIZE (gmmsm_table);
        break;
#else
      case SAP_NR(MMPM_UL):
        table = mmpm_table;
        n = TAB_SIZE (mmpm_table);
        break;
#endif
      case GMMSMS_UL:
        table = gmmsms_table;
        n = TAB_SIZE (gmmsms_table);
        break;
      case SAP_NR(SIM_UL):/*lint !e778 (Info -- Constant expression evaluates to 0 in operation '&') */
        table = sim_table;
        n = TAB_SIZE (sim_table);
        break;
      case LL_DL:
        table = ll_table;
        n = TAB_SIZE (ll_table);
        break;
      case LLGMM_DL:
        table = llgmm_table;
        n = TAB_SIZE (llgmm_table);
        break;
      case MMGMM_DL:
        table = mmgmm_table;
        n = TAB_SIZE (mmgmm_table);
        break;
#ifdef FF_EM_MODE
      case EM_Ul:
        table = em_ul_table;
        n = TAB_SIZE (em_ul_table);
        break;
      case EM_Dl:
        table = em_dl_table;
        n = TAB_SIZE (em_dl_table);
        break;
#endif /* FF_EM_MODE */
      default:
        TRACE_ERROR("pei_primitive. Unknown SAP");
        table = NULL;
        n = 0;
        break;
    }

    if (table != NULL)
    {
      if (PRIM_NR(opc) < n)
      {
        table += PRIM_NR(opc);
#ifdef PALLOC_TRANSITION
        P_SDU(prim) = table->soff ? (T_sdu*) (((char*)&prim->data) + table->soff) : 0;
#ifndef NO_COPY_ROUTING
        P_LEN(prim) = table->size + sizeof (T_PRIM_HEADER);
#endif /* NO_COPY_ROUTING */
#endif /* PALLOC_TRANSITION */

        /*******************************************************
         * SAVE prim
         *******************************************************/

        if( gmm_pei_handle_save( prim, &save_queue, save_tab, table->func )
          ==  PEI_SIGNAL_NOT_SAVED )
        {
          UBYTE old_kern_state = gmm_data->kern.state;
          /*******************************************************
           * SAVE prim
           *******************************************************/

          JUMP (table->func) (P2D(prim));
          
          /*******************************************************
           * SAVE prim
           *******************************************************/
          if( gmm_data->kern.state != old_kern_state )
          {
            gmm_pei_handle_queue(&save_queue, save_tab);
          }
        } 
        else
        {
          TRACE_2_INFO ("S:%2d SAVE of Primitive 0x%x", gmm_data->kern.state, opc );
        }



        /*******************************************************
         * End SAVE prim
         *******************************************************/
        
      }
      else
      {
        primitive_not_supported (P2D(prim));
      }
      return PEI_OK;
    }

    /*
     * primitive is not a GSM primitive - forward it to the environment
     */
    if (opc & SYS_MASK)
      vsi_c_primitive (VSI_CALLER prim);
    else
    {
      PFREE (P2D(prim));
      return PEI_ERROR;
    }
  }
  return PEI_OK;
}


/*
+------------------------------------------------------------------------------
|  Function    : pei_init
+------------------------------------------------------------------------------
|  Description  : This function is called by the frame. It is used to initialise
|               the entitiy.
|
|  Parameters  :  handle            - task handle
|
|  Return      :  PEI_OK            - entity initialised
|               PEI_ERROR         - entity not (yet) initialised
|
+------------------------------------------------------------------------------
*/
LOCAL SHORT pei_init (T_HANDLE handle)
{
  TRACE_FUNCTION ("pei_init");

  /*
   * Initialize task handle
   */
  GMM_handle = handle;

  /*
   * Open communication channels
   */
  if (hCommSMS < VSI_OK)
  {
    if ((hCommSMS = vsi_c_open (VSI_CALLER SMS_NAME)) < VSI_OK)
      return PEI_ERROR;
  }
  if (hCommSM < VSI_OK)
  {
    if ((hCommSM = vsi_c_open (VSI_CALLER SM_NAME)) < VSI_OK)
      return PEI_ERROR;
  }
  if (hCommGRLC < VSI_OK) /* TCS 2.1 */
  { /* TCS 2.1 */
    if ((hCommGRLC = vsi_c_open (VSI_CALLER GRLC_NAME)) < VSI_OK) /* TCS 2.1 */
      return PEI_ERROR; /* TCS 2.1 */
  } /* TCS 2.1 */

  if (hCommGRR < VSI_OK)
  {
    if ((hCommGRR = vsi_c_open (VSI_CALLER GRR_NAME)) < VSI_OK)
      return PEI_ERROR;
  }
  if (hCommLLC < VSI_OK)
  {
    if ((hCommLLC = vsi_c_open (VSI_CALLER LLC_NAME)) < VSI_OK)
      return PEI_ERROR;
  }
  if (hCommSIM < VSI_OK)
  {
    if ((hCommSIM = vsi_c_open (VSI_CALLER SIM_NAME)) < VSI_OK)
      return PEI_ERROR;
  }
  if (hCommMM < VSI_OK)
  {
    if ((hCommMM = vsi_c_open (VSI_CALLER MM_NAME)) < VSI_OK)
      return PEI_ERROR;
  }
  if (hCommMMI < VSI_OK)
  {
    if ((hCommMMI = vsi_c_open (VSI_CALLER ACI_NAME)) < VSI_OK) /* TCS 2.1 */
      return PEI_ERROR;
  }
  if (hCommGMM < VSI_OK)
  {
    if ((hCommGMM = vsi_c_open (VSI_CALLER GMM_NAME)) < VSI_OK)
      return PEI_ERROR;
  }
#ifdef GMM_TCS4
  if (hCommUPM < VSI_OK)
  {
    if ((hCommUPM = vsi_c_open (VSI_CALLER UPM_NAME)) < VSI_OK)
      return PEI_ERROR;
  }
#endif


  /*
   * Initialize global pointer llc_data. This is required to access all
   * entity data.
   */
  gmm_data = &gmm_data_base;

  /*
   * Initialite ccd
   */
  ccd_init ();

#ifdef FF_EM_MODE
  em_init_gmm_event_trace();
#endif /* FF_EM_MODE */


  /*
   * Initialize entity data (call init function of every service)
   */

  kern_init();
  rxgmm_init();
  txgmm_init();
  rdy_init();
  sync_gmm_init();

  GMM_TRACE_GMM_DATA(GMM_DEBUG_PRINT_MASK_FULL);

  return (PEI_OK);
}

/*
+------------------------------------------------------------------------------
|  Function    : pei_timeout
+------------------------------------------------------------------------------
|  Description  : This function is called by the frame when a timer has expired.
|
|  Parameters  :  index             - timer index
|
|  Return      :  PEI_OK            - timeout processed
|               PEI_ERROR         - timeout not processed
|
+------------------------------------------------------------------------------
*/
LOCAL SHORT pei_timeout (USHORT index)
{
  UBYTE      old_kern_state;
  TRACE_FUNCTION ("pei_timeout");

  old_kern_state = gmm_data->kern.state;
  /*
   * Process timeout
   */
  switch (index)
  {
    case kern_T3302:
      /*
       * T3302 expired.
       */
      kern_t3302 ();
      break;
    case kern_T3310:
      /*
       * T3310 expired.
       */
      kern_t3310 ();
      break;
    case kern_T3311:
      /*
       * T3311 expired.
       */
      kern_t3311 ();
      break;
    case kern_T3321:
      /*
       * T3321 expired.
       */
      kern_t3321 ();
      break;
    case rdy_T3312:
      /*
       * T3312 expired.
       */
      kern_t3312 ();
      break;
    case kern_TPOWER_OFF:
      kern_tpower_off();
      break;
    case kern_TLOCAL_DETACH:
      kern_tlocal_detach();
      break;
    case sync_TSYNC:
      sync_tsync();
      break;
    default:
      TRACE_ERROR("Unknown Timeout");
      return PEI_ERROR;
  }

  if( gmm_data->kern.state != old_kern_state )
  {
    gmm_pei_handle_queue(  &save_queue, save_tab);
  }
  return PEI_OK;
}

/*
+------------------------------------------------------------------------------
|  Function    : pei_signal
+------------------------------------------------------------------------------
|  Description  : This function is called by the frame when a signal has been
|               received.
|
|  Parameters  :  opc               - signal operation code
|               *data             - pointer to primitive
|
|  Return      :  PEI_OK            - signal processed
|               PEI_ERROR         - signal not processed
|
+------------------------------------------------------------------------------
*/
LOCAL SHORT pei_signal (ULONG opc, void *data)
{
  TRACE_FUNCTION ("pei_signal");

  /*
   * Process signal
   */
  switch (opc)
  {
    default:
      TRACE_ERROR("Unknown Signal OPC");
      break;
  }/*lint !e764 (Info -- switch statement does not have a case) */

  return PEI_OK;
}

/*
+------------------------------------------------------------------------------
|  Function    : pei_exit
+------------------------------------------------------------------------------
|  Description  : This function is called by the frame when the entity is
|               terminated. All open resources are freed.
|
|  Parameters  :  -
|
|  Return      :  PEI_OK            - exit sucessful
|               PEI_ERROR         - exit not sueccessful
|
+------------------------------------------------------------------------------
*/
LOCAL SHORT pei_exit (void)
{
  TRACE_FUNCTION ("pei_exit");

  /*
   * Close communication channels
   */
  vsi_c_close (VSI_CALLER hCommSMS);
  hCommSMS = VSI_ERROR;

  vsi_c_close (VSI_CALLER hCommSM);
  hCommSM = VSI_ERROR;

  vsi_c_close (VSI_CALLER hCommGRLC); /* TCS 2.1 */
  hCommGRLC = VSI_ERROR; /* TCS 2.1 */

  vsi_c_close (VSI_CALLER hCommGRR);
  hCommGRR = VSI_ERROR;

  vsi_c_close (VSI_CALLER hCommLLC);
  hCommLLC = VSI_ERROR;

  vsi_c_close (VSI_CALLER hCommSIM);
  hCommSIM = VSI_ERROR;

  vsi_c_close (VSI_CALLER hCommMM);
  hCommMM = VSI_ERROR;

  vsi_c_close (VSI_CALLER hCommMMI);
  hCommMMI = VSI_ERROR;

  vsi_c_close (VSI_CALLER hCommGMM);
  hCommGMM = VSI_ERROR;

  /*
   * delete queues
   */
  gmm_pei_delete_queue(&save_queue);
  
  /*
   * close ccd
   */
  ccd_exit ();

  return PEI_OK;
}

/*
+------------------------------------------------------------------------------
|  Function    : pei_run
+------------------------------------------------------------------------------
|  Description  : This function is called by the frame when entering the main
|               loop. This fucntion is only required in the active variant.
|
|               This function is not used.
|
|  Parameters  :  handle            - Communication handle
|
|  Return      :  PEI_OK            - sucessful
|               PEI_ERROR         - not successful
|
+------------------------------------------------------------------------------
*/
LOCAL SHORT pei_run (T_HANDLE TaskHandle, T_HANDLE ComHandle )
{
  return PEI_OK;
}


/*
+------------------------------------------------------------------------------
|  Function    : gmm_tok_key
+------------------------------------------------------------------------------
|  Description  : This function is used by pei_config in windows test
|                 environment for string tokenizing for CHECK STATE command, e.g.
|                 COMMAND("GMM CONFIG CHECK_STATE=<REG_NORMAL_SERVICE>");
|
|
|  Parameters  :  
|
|  Return      :  
|               
|
+------------------------------------------------------------------------------
*/
#ifndef _TARGET_
typedef struct KW_STATE_DATA
{
   char   keyword[60];
   SHORT  code;
} KW_STATE_DATA;

LOCAL SHORT gmm_tok_key (KW_STATE_DATA * keytab, char * keyword)
{
  /*
   * Empty string terminates
   */
  while (keytab->keyword[0])
  {
    if (strcmp (keytab->keyword, keyword ) == 0)
      return (keytab->code);
    keytab++;
  }

  return (TOK_NOT_FOUND);
}
#endif

/*
+------------------------------------------------------------------------------
|  Function    : pei_config
+------------------------------------------------------------------------------
|  Description  : This function is called by the frame when a primitive is
|               received indicating dynamic configuration.
|
|               This function is not used in this entity.
|
|  Parameters  :  handle            - Communication handle
|
|  Return      :  PEI_OK            - sucessful
|               PEI_ERROR         - not successful
|
+------------------------------------------------------------------------------
*/
LOCAL SHORT pei_config (char *inString)
{
  TRACE_FUNCTION ("pei_config");
  TRACE_FUNCTION (inString);

#ifndef NCONFIG
   /*
   * Parse next keyword and number of variables
   */
    if(!strcmp(inString,"PERIODIC_LAU"))
    {
      PALLOC (mmgmm_lup_needed_ind, MMGMM_LUP_NEEDED_IND);
      mmgmm_lup_needed_ind->reason = MMGMM_T3212; /* TCS 2.1 */
      TRACE_EVENT(  "Info: Periodic LAU requested by MM");
      PSEND (hCommGMM, mmgmm_lup_needed_ind);
    }
    else if(!strcmp(inString,"PERIODIC_RAU"))
    {
      kern_t3312();
    }
    else if(!strcmp(inString,"REATTACH"))
    {
      PALLOC (gmmrr_page_ind,  GMMRR_PAGE_IND);
        gmmrr_page_ind->page_id=GMMRR_IMSI;
      PSEND (hCommGMM, gmmrr_page_ind);
    }
    else if(!strcmp(inString,"CELL"))
    {
      PALLOC (gmmrr_cell_ind,  GMMRR_CELL_IND);
      gmmrr_cell_ind->cell_info.service_state=GMMRR_SERVICE_FULL;
      gmmrr_cell_ind->cell_info.cell_env.rai.lac=0x2506;
      gmmrr_cell_ind->cell_info.cell_env.rai.rac=0x71;
      gmmrr_cell_ind->cell_info.net_mode=gmm_data->config.nmo;
      PSEND (hCommGMM, gmmrr_cell_ind);
    }
    else if(!strcmp(inString,"NMO_I"))
    {
      gmm_data->config.nmo = GMMRR_NET_MODE_I;
    }
    else if(!strcmp(inString,"NMO_II"))
    {
      gmm_data->config.nmo = GMMRR_NET_MODE_II;
    }
    else if(!strcmp(inString,"NMO_III"))
    {
      gmm_data->config.nmo = GMMRR_NET_MODE_III;
    }
    else if(!strcmp(inString,"GMM_INFO"))
    {
      PALLOC (gmmreg_info_ind,  GMMREG_INFO_IND);
      PSEND (hCommMMI, gmmreg_info_ind);
    }

    else if(!strcmp(inString,"RESET_SIM"))
    {
      gmm_data->sim_gprs_invalid = TRUE;
      kern_sim_del_locigprs ();
      kern_sim_gmm_update();
      kern_mm_auth_rej();
      {
        PALLOC (sim_update_req, SIM_UPDATE_REQ);

        sim_update_req->source         = SRC_GMM;
        /* req_id is not filled since response is not handled */

        sim_update_req->v_path_info    = FALSE;

        sim_update_req->datafield      = SIM_FPLMN;
        sim_update_req->length         = 12;
        memset (sim_update_req->trans_data,0xff,12);
        sim_update_req->offset         = 0;

        PSEND (hCommSIM, sim_update_req);
      }
      {
        PALLOC (sim_update_req, SIM_UPDATE_REQ);

        sim_update_req->source         = SRC_GMM;

        /* req_id is not filled since response is not handled */        
        sim_update_req->v_path_info    = FALSE;

        sim_update_req->datafield      = SIM_LOCI;
        sim_update_req->length         = 11;
        memset (sim_update_req->trans_data,0xff,8);
        sim_update_req->trans_data[8]=0xfe;
        sim_update_req->trans_data[9]=0x0;
        sim_update_req->trans_data[10]=GU2_NOT_UPDATED;
        sim_update_req->offset         = 0;

        PSEND (hCommSIM, sim_update_req);
      }
    }
    else if(!strcmp(inString,"ANITE"))
    {
      gmm_data->anite = TRUE;
    }
    else if(!strcmp(inString,"CIPHER_OFF"))
    {
      gmm_data->config.cipher_on =   0x00;
      TRACE_EVENT ("ciphering switched OFF");
    }
    else if(!strcmp(inString,"CIPHER_ON"))
    {
      gmm_data->config.cipher_on |= 0x01;
    }
    else if(!strcmp(inString,"PREUSE_OFF"))
    {
      gmm_data->config.preuse_off =    TRUE;
    }

#ifdef REL99
    else if(!strcmp(inString,"CL_SGSN_REL_98_OR_OLDER")) /* TCS 4.0 */
    { /* TCS 4.0 */
      /*gmm_data->config.sgsnr_flag =    R_98NW; */
      cl_nwrl_set_sgsn_release(PS_SGSN_98_OLDER); /*CL function*/ /* TCS 4.0 */
    } /* TCS 4.0 */
    else if(!strcmp(inString,"CL_SGSN_REL_99_ONWARDS")) /* TCS 4.0 */
    { /* TCS 4.0 */
      /* gmm_data->config.sgsnr_flag =    R_99NW; */
      cl_nwrl_set_sgsn_release(PS_SGSN_99_ONWARDS); /*CL function*/ /* TCS 4.0 */
    } /* TCS 4.0 */
    else if (!strcmp(inString,"CELL_NOTIFY_ON")) /* TCS 4.0 */
    { /* TCS 4.0 */
      gmm_data->config.cell_notification = FIRST_CELL_NOTIFY; /* TCS 4.0 */
    } /* TCS 4.0 */
    else if (!strcmp(inString, "CELL_NOTIFY_OFF")) /* TCS 4.0 */
    { /* TCS 4.0 */
      gmm_data->config.cell_notification = NO_CELL_NOTIFY; /* TCS 4.0 */
    } /* TCS 4.0 */
#endif

#ifdef _SIMULATION_    
    else if(!strcmp(inString, "NEXT_TIMEOUT"))
    {
      T_TIME old_value = 0;
      T_TIME new_value = 0;
      USHORT timer;
      USHORT timeout = TIMER_MAX;
    
      /* Find next timer to timeout */    
      
      for(timer = 0; timer < TIMER_MAX; timer++)
      {
        if ( VSI_OK == vsi_t_status ( GMM_handle ,timer, &new_value ))
        {
          if (new_value >0 )
          {
            if((old_value==0)||
               (new_value < old_value))
            {
              old_value = new_value;
              timeout = timer;        
            }
          }
        }
      }

      
      /* Force timeout */
      if(TIMER_MAX != timeout )
      {
        TRACE_1_INFO("gmm_pei_config - forcing timeout:%d", timeout);
        
        vsi_t_stop ( GMM_handle, timeout);       

        for(timer = 0; timer < TIMER_MAX ; timer++)
        {
          if ( VSI_OK == vsi_t_status ( GMM_handle ,timer, &new_value ))
          {
            if (timer!=timeout )
            {
              if (new_value>0 && new_value-old_value >0 )
              {
                vsi_t_start ( GMM_handle , timer, new_value-old_value ); 
              }
            }
          }
        }

        pei_timeout(timeout);
      }
    }
#endif

#define GMM_CONFIG_DRX               1
#define GMM_CONFIG_GEA            2

#ifndef _TARGET_
#define GMM_CONFIG_CHECK_STATE       3
#endif

#define GMM_DRX               "DRX"
#define GMM_GEA               "GEA"

#ifndef _TARGET_
#define GMM_CHECK_STATE       "CHECK_STATE"

#define GMM_NULL_NO_IMSI                      "NULL_NO_IMSI"
#define GMM_NULL_IMSI                         "NULL_IMSI"
#define GMM_DEREG_INITIATED                   "DEREG_INITIATED"  
#define GMM_DEREG_ATTEMPTING_TO_ATTACH        "DEREG_ATTEMPTING_TO_ATTACH"
#define GMM_DEREG_NO_CELL_AVAILABLE           "DEREG_NO_CELL_AVAILABLE"
#define GMM_DEREG_LIMITED_SERVICE             "DEREG_LIMITED_SERVICE"
#define GMM_DEREG_NO_IMSI                     "DEREG_NO_IMSI"
#define GMM_DEREG_PLMN_SEARCH                 "DEREG_PLMN_SEARCH"
#define GMM_DEREG_SUSPENDED                   "DEREG_SUSPENDED"

#define GMM_REG_INITIATED                     "REG_INITIATED"

#define GMM_REG_NO_CELL_AVAILABLE             "REG_NO_CELL_AVAILABLE"
#define GMM_REG_LIMITED_SERVICE               "REG_LIMITED_SERVICE"
#define GMM_REG_ATTEMPTING_TO_UPDATE_MM       "REG_ATTEMPTING_TO_UPDATE_MM  "
#define GMM_REG_ATTEMPTING_TO_UPDATE          "REG_ATTEMPTING_TO_UPDATE"
#define GMM_REG_RESUMING                      "REG_RESUMING"
#define GMM_REG_SUSPENDED                     "REG_SUSPENDED"
#define GMM_REG_NORMAL_SERVICE                "REG_NORMAL_SERVICE"

#define GMM_RAU_INITIATED                     "RAU_INITIATED"

#define GMM_RAU_WAIT_FOR_NPDU_LIST            "RAU_WAIT_FOR_NPDU_LIST"

#define GMM_REG_IMSI_DETACH_INITIATED         "REG_IMSI_DETACH_INITIATED"

#define GMM_DEREG_SUSPENDING                  "DEREG_SUSPENDING"
#define GMM_DEREG_RESUMING                    "DEREG_RESUMING"

#define GMM_REG_SUSPENDING                    "REG_SUSPENDING"
#define GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ     "NULL_NO_IMSI_LIMITED_SERVICE_REQ"
#define GMM_NULL_IMSI_LIMITED_SERVICE_REQ     "NULL_IMSI_LIMITED_SERVICE_REQ"
#define GMM_REG_TEST_MODE                     "REG_TEST_MODE"
#define GMM_NULL_PLMN_SEARCH                  "NULL_PLMN_SEARCH"
#define GMM_REG_TEST_MODE_NO_IMSI             "REG_TEST_MODE_NO_IMSI "

#endif
    
    {   
      LOCAL KW_DATA kwtab[] = 
      {
        GMM_DRX, GMM_CONFIG_DRX,
        GMM_GEA, GMM_CONFIG_GEA,
#ifndef _TARGET_
        GMM_CHECK_STATE, GMM_CONFIG_CHECK_STATE,
#endif
        "", 0  
      };
#ifndef _TARGET_
      LOCAL KW_STATE_DATA kw_state_tab[] = 
      {
         GMM_NULL_NO_IMSI                      ,KERN_GMM_NULL_NO_IMSI,
         GMM_NULL_IMSI                         ,KERN_GMM_NULL_IMSI,
         GMM_DEREG_INITIATED                   ,KERN_GMM_DEREG_INITIATED,  
         GMM_DEREG_ATTEMPTING_TO_ATTACH        ,KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH,
         GMM_DEREG_NO_CELL_AVAILABLE           ,KERN_GMM_DEREG_NO_CELL_AVAILABLE,
         GMM_DEREG_LIMITED_SERVICE             ,KERN_GMM_DEREG_LIMITED_SERVICE,
         GMM_DEREG_NO_IMSI                     ,KERN_GMM_DEREG_NO_IMSI,
         GMM_DEREG_PLMN_SEARCH                 ,KERN_GMM_DEREG_PLMN_SEARCH,
         GMM_DEREG_SUSPENDED                   ,KERN_GMM_DEREG_SUSPENDED,

         GMM_REG_INITIATED                     ,KERN_GMM_REG_INITIATED,

         GMM_REG_NO_CELL_AVAILABLE             ,KERN_GMM_REG_NO_CELL_AVAILABLE,
         GMM_REG_LIMITED_SERVICE               ,KERN_GMM_REG_LIMITED_SERVICE,
         GMM_REG_ATTEMPTING_TO_UPDATE_MM       ,KERN_GMM_REG_ATTEMPTING_TO_UPDATE_MM  ,
         GMM_REG_ATTEMPTING_TO_UPDATE          ,KERN_GMM_REG_ATTEMPTING_TO_UPDATE,
         GMM_REG_RESUMING                      ,KERN_GMM_REG_RESUMING,
         GMM_REG_SUSPENDED                     ,KERN_GMM_REG_SUSPENDED,
         GMM_REG_NORMAL_SERVICE                ,KERN_GMM_REG_NORMAL_SERVICE,

         GMM_RAU_INITIATED                     ,KERN_GMM_RAU_INITIATED,

         GMM_RAU_WAIT_FOR_NPDU_LIST            ,KERN_GMM_RAU_WAIT_FOR_NPDU_LIST,

         GMM_REG_IMSI_DETACH_INITIATED         ,KERN_GMM_REG_IMSI_DETACH_INITIATED,

         GMM_DEREG_SUSPENDING                  ,KERN_GMM_DEREG_SUSPENDING,
         GMM_DEREG_RESUMING                    ,KERN_GMM_DEREG_RESUMING,
         GMM_REG_SUSPENDING                    ,KERN_GMM_REG_SUSPENDING,
         
         GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ     ,KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ,
         GMM_NULL_IMSI_LIMITED_SERVICE_REQ     ,KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ,
         GMM_REG_TEST_MODE                     ,KERN_GMM_REG_TEST_MODE,
         GMM_NULL_PLMN_SEARCH                  ,KERN_GMM_NULL_PLMN_SEARCH,
         GMM_REG_TEST_MODE_NO_IMSI             ,KERN_GMM_REG_TEST_MODE_NO_IMSI ,
        "", 0  
      };

#endif
      SHORT valno;
      char *keyw;
      char *val[10];
      
      tok_init (inString);

      while((valno = tok_next(&keyw,val)) NEQ TOK_EOCS)
      {
        switch ((tok_key((KW_DATA *)kwtab, keyw)))
        {
          case GMM_CONFIG_DRX:
            if (3==valno)
            {
              TRACE_EVENT ("use of DRX <split_pg_cycle_code,split_on_ccch,non_drx_timer>");
              gmm_data->drx_parameter.split_pg_cycle_code = atoi (val[0]);
              gmm_data->drx_parameter.split_on_ccch       = atoi (val[1]);
              gmm_data->drx_parameter.non_drx_timer       = atoi (val[2]);
            }
            else
            {
              TRACE_ERROR("[PEI_CONFIG]: use CONFIG DRX <1,2,3>");
            }
            break;
          case GMM_CONFIG_GEA:
            if (1==valno)
            {
              TRACE_EVENT ("GEA=<bit_field of wanted GEA in dec>");
              
              gmm_data->config.cipher_on |= atoi (val[0]);
              TRACE_1_INFO("GEA2=%d", (gmm_data->config.cipher_on & 0x02)>0);
              TRACE_1_INFO("GEA3=%d", (gmm_data->config.cipher_on & 0x04)>0);
              TRACE_1_INFO("GEA4=%d", (gmm_data->config.cipher_on & 0x08)>0);
              TRACE_1_INFO("GEA5=%d", (gmm_data->config.cipher_on & 0x10)>0);
              TRACE_1_INFO("GEA6=%d", (gmm_data->config.cipher_on & 0x20)>0);
              TRACE_1_INFO("GEA7=%d", (gmm_data->config.cipher_on & 0x40)>0);
            }
            else
            {
              TRACE_ERROR("[PEI_CONFIG]: use CONFIG GEA=<0-255>//255 means all GEA wanted");
            }
            break;
#ifndef _TARGET_
          case GMM_CONFIG_CHECK_STATE:
            if(1==valno)
            {
              if (gmm_tok_key ((KW_STATE_DATA *)kw_state_tab, val[0])!=GET_STATE(KERN))
              {
                PALLOC ( cgrlc_status_ind, CGRLC_STATUS_IND ); /* TCS 2.1 */
                PSEND ( hCommGMM, cgrlc_status_ind ); /* TCS 2.1 */
                TRACE_1_OUT_PARA(   "neq %s", val[0]);
                TRACE_ERROR("state wrong");
              }
              else
              {
                TRACE_1_INFO("state %s ok",val[0]);
              }
            }
            else
            {
              TRACE_ERROR("[PEI_CONFIG]: USE CONFIG CHECK_STATE <state>");
            }
            break;
#endif            
          default:
            break;
        }
      }
    }
#endif
    return PEI_OK;
}

/*
+------------------------------------------------------------------------------
|  Function    : pei_monitor
+------------------------------------------------------------------------------
|  Description  : This function is called by the frame in case sudden entity
|               specific data is requested (e.g. entity Version).
|
|  Parameters  :  out_monitor       - return the address of the data to be
|                                   monitoredCommunication handle
|
|  Return      :  PEI_OK            - sucessful (address in out_monitor is valid)
|               PEI_ERROR         - not successful
|
+------------------------------------------------------------------------------
*/
LOCAL SHORT pei_monitor (void ** out_monitor)
{
  TRACE_FUNCTION ("pei_monitor");

  /*
   * Version = "0.S" (S = Step).
   */
  gmm_mon.version = "GMM 0.1";
  *out_monitor = &gmm_mon;

  return PEI_OK;
}

/*
+------------------------------------------------------------------------------
|  Function    : pei_create
+------------------------------------------------------------------------------
|  Description  :  This function is called by the frame when the process is
|                created.
|
|  Parameters  :  out_name          - Pointer to the buffer in which to locate
|                                   the name of this entity
|
|  Return      :  PEI_OK            - entity created successfuly
|               PEI_ERROR         - entity could not be created
|
+------------------------------------------------------------------------------
*/
GLOBAL SHORT pei_create (T_PEI_INFO **info)
{
static T_PEI_INFO pei_info =
              {
               "GMM",         /* name */
               {              /* pei-table */
                 pei_init,
                 pei_exit,
                 pei_primitive,
                 pei_timeout,
                 pei_signal,
                 pei_run,
                 pei_config,
                 pei_monitor
               },
               2048,          /* stack size */
               25,            /* queue entries */
               190,           /* priority (1->low, 255->high) */
               TIMER_MAX,     /* number of timers */
               0x03|PRIM_NO_SUSPEND /* flags: bit 0   active(0) body/passive(1) */
              };              /*        bit 1   com by copy(0)/reference(1) */


  TRACE_FUNCTION ("pei_create");

  /*
   * Close Resources if open
   */
  if (first_access)
    first_access = FALSE;
  else
    pei_exit();

  /*
   * Export startup configuration data
   */
  *info = &pei_info;

  return (PEI_OK);
}

/*
+------------------------------------------------------------------------------
| Function    : gmm_pei_handle_queue
+------------------------------------------------------------------------------
| Description : This function searches for the first stored primitive, which
|               must not be saved further in current state.
|
| Parameters  : state     - current state of the instance
|               queue     - PtrPtr to the hanger of the instance save queue
|               table     - Ptr to the state/signals-to-save table
|               inst_data - Ptr to instance data
+------------------------------------------------------------------------------
*/
LOCAL void gmm_pei_handle_queue( T_SAVE_QUEUE** queue,
                                      const T_SAVE_TAB* table)
{
  /* search for a T_SAVE_TAB entry which fits to current state */
  if( *queue )
    while( table->state != PEI_END_SAVETAB && table->state != gmm_data->kern.state )
      table++;

  while( *queue )
  {
    T_SAVE_QUEUE* current = *queue;
    ULONG  opc            = ((T_PRIM_HEADER*)current->prim)->opc;
    USHORT n              = 0;

    if( table->state != PEI_END_SAVETAB )
    {
      /* search for this signals in savelist of this state */
      while( n < GMM_MAX_SIGNALS_SAVED && table->signal[n] &&
             table->signal[n] != opc                       )
        n++;
    }

    if( table->signal[n] != opc )
    {
      TRACE_1_INFO ("Pimitive 0x%x send from SAVE queue",
                    ((T_PRIM_HEADER*)current->prim)->opc );
      /* this signal must not further be stored -> handle it now */
      /* first remove it from save queue, because of recursion!! */
      *queue = current->next;
      gmm_pei_handle_prim(current->func, current->prim );
      /* and free memory after last use */
      MFREE( current );

      /* recursion! handle at maximum one prim at once -> job done */
      return;
    }

    /* goto next queued signal */
    queue = &((*queue)->next);
  }
}
/*
+------------------------------------------------------------------------------
| Function    : gmm_pei_delete_queue
+------------------------------------------------------------------------------
| Description : This function removes all stored primitives from the queue and
|               frees the memory.
|
| Parameters  : queue    - PtrPtr to the hanger of the instance save queue
+------------------------------------------------------------------------------
*/
GLOBAL void gmm_pei_delete_queue( T_SAVE_QUEUE** queue )
{
  while( *queue )
  {
    T_SAVE_QUEUE* current = *queue;


    TRACE_1_INFO( "Pimitive 0x%x deleted from SAVE queue",
                                         ((T_PRIM_HEADER*)current->prim)->opc );

    *queue = current->next;
    PFREE( P2D(current->prim) );
    MFREE( current );
  }
}
/*
+------------------------------------------------------------------------------
| Function    : gmm_pei_handle_prim
+------------------------------------------------------------------------------
| Description : This function calls the handle function of the signal
|
| Parameters  : func       - Function, which should handle the signal
|               inst_data  - Ptr to instance data
|               *prim      - Ptr to primitive
+------------------------------------------------------------------------------
*/
LOCAL void gmm_pei_handle_prim( T_VOID_FUNC func, void* prim )
{
  JUMP(func)( P2D(prim));

  gmm_pei_handle_queue(   &save_queue, save_tab);
}
/*
+------------------------------------------------------------------------------
| Function    : gmm_pei_handle_save
+------------------------------------------------------------------------------
| Description : This function saves the prim pointer to the save queue, if
|               this is necessary in current state.
|
| Parameters  : *prim    - Ptr to primitive
|               state    - Current state of the instance
|               queue    - PtrPtr to the hanger of the instance save queue
|               table    - Ptr to the state/signals-to-save table
|               func     - Function, which should handle the signal
|
| Returns     : PEI_SIGNAL_SAVED      - if signal is stored to save queue
|               PEI_SIGNAL_NOT_SAVED  - else
+------------------------------------------------------------------------------
*/
LOCAL BOOL gmm_pei_handle_save( void* prim, T_SAVE_QUEUE** queue,
                                     const T_SAVE_TAB* table, T_VOID_FUNC func  )
{
  ULONG opc = ((T_PRIM_HEADER*)prim)->opc;

  while( table->state != PEI_END_SAVETAB )
  {
    if( table->state == gmm_data->kern.state )
    {
      UBYTE n = 0;

      /* check for signals to save */
      while( n < GMM_MAX_SIGNALS_SAVED && table->signal[n] )
      {
        if( table->signal[n] == opc )
        {
          /* store signal to end of save queue */
          while( *queue )
            queue = &((*queue)->next);

          MALLOC( *queue, sizeof(T_SAVE_QUEUE) );

          if( *queue )
          {
            (*queue)->prim = prim;
            (*queue)->func = func;
            (*queue)->next = NULL;
          }
          else
          {
            TRACE_ERROR( "Out of memory in mm_pei_handle_save()" );
            return PEI_SIGNAL_NOT_SAVED;
          }

          return PEI_SIGNAL_SAVED;
        }

        /* goto next signal */
        n++;
      }

      break;
    }

    /* gote next entry */
    table++;
  }

  return PEI_SIGNAL_NOT_SAVED;
}

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