FreeCalypso > hg > fc-tourmaline
view src/g23m-aci/aci/cmh_mmf.c @ 303:f76436d19a7a default tip
!GPRS config: fix long-standing AT+COPS chance hanging bug
There has been a long-standing bug in FreeCalypso going back years:
sometimes in the AT command bring-up sequence of an ACI-only MS,
the AT+COPS command would produce only a power scan followed by
cessation of protocol stack activity (only L1 ADC traces), instead
of the expected network search sequence. This behaviour was seen
in different FC firmware versions going back to Citrine, and seemed
to follow some law of chance, not reliably repeatable.
This bug has been tracked down and found to be specific to !GPRS
configuration, stemming from our TCS2/TCS3 hybrid and reconstruction
of !GPRS support that was bitrotten in TCS3.2/LoCosto version.
ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3
version and had to be pulled from TCS2 - but as it turns out,
there is a new field in the MMR_REG_REQ primitive that needs to be
set correctly, and that psa_mms.c module is the place where this
initialization needed to be added.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 08 Jun 2023 08:23:37 +0000 |
parents | fa8dc04885d8 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : GSM-PS (6147) | Modul : CMH_MMF +----------------------------------------------------------------------------- | 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 defines the functions used by the command | handler for mobility management. +----------------------------------------------------------------------------- */ #ifndef CMH_MMF_C #define CMH_MMF_C #endif #include "aci_all.h" /*==== INCLUDES ===================================================*/ #include "aci_cmh.h" #include "ati_cmd.h" #include "aci_cmd.h" #include "aci_mem.h" #include "pcm.h" #ifdef FAX_AND_DATA #include "aci_fd.h" #endif /* of #ifdef FAX_AND_DATA */ #include "aci.h" #include "psa.h" #include "psa_cc.h" #include "psa_mm.h" #include "psa_sim.h" #include "psa_sat.h" #include "psa_util.h" #include "cmh.h" #ifdef TI_PS_OP_OPN_TAB_ROMBASED #include "plmn_decoder.h" #include "rom_tables.h" #endif #ifdef DTI #include "dti.h" /* functionality of the dti library */ #include "dti_conn_mng.h" /* #include "dti_cntrl_mng.h" */ #endif #ifdef GPRS #include "gaci.h" #include "gaci_cmh.h" #include "psa_gmm.h" #include "cmh_gmm.h" #endif /* GPRS */ #include "cmh_mm.h" #include "cmh_sim.h" #ifndef _SIMULATION_ #include "ffs/ffs.h" #include "ffs_coat.h" #endif /* !_SIMULATION_ */ #ifdef FF_CPHS #include "cphs.h" #endif /* FF_CPHS */ /*==== CONSTANTS ==================================================*/ /* Countries, for which the ECC should be ignored, i.e. done as normal call */ /* contains MCC and ECC, last element should be always NULL*/ GLOBAL const T_ECCIgnoreRec ECCIgnoreTable[] = { { 0x260, ALL_MNC, "999" }, /* Poland */ { 0x454, 0x04F, "112" }, /* "HK ORANGE" */ { 0x454, 0x10F, "112" }, /* "HK New World" */ { -1, -1, NULL } /* End mark */ }; #define ONS_EXT_DCS 0x80 /*==== TYPES ======================================================*/ /*==== EXPORT =====================================================*/ /*==== VARIABLES ==================================================*/ EXTERN T_ACI_CUSCFG_PARAMS cuscfgParams; LOCAL T_OPER_ENTRY ONSDesc; GLOBAL T_ONS_READ_STATE ONSReadStatus = ONS_READ_NOT_DONE; /* This is required because FFS is not available in the Simulation Mode */ #ifdef _SIMULATION_ T_FFSPLMNIMSI RAMPlmnIMSI = {0}; #endif #if defined GPRS AND defined (DTI) EXTERN T_GMM_SHRD_PRM gmmShrdPrm; #endif /* Implements Measure#32: Row 119, 980, 987, 1037 */ const char * const format_03x02x_str ="%03X%02X"; /* Implements Measure#32: Row 118, 986, 1036 */ const char * const format_03x03x_str = "%03X%03X"; /* Implements Measure#32: Row 969, 1027, 1239 & 1240 */ const char * const num_112_str = "112"; const char * const num_911_str = "911"; /* Implements Measure#32: Row 110 & 981 */ const char * const ef_plmn_id = EF_PLMN_ID; #ifndef _SIMULATION_ /* Implements Measure#32: Row 120 & 121 */ LOCAL const char * const gsm_cops_path=MM_FFS_OPER_DIR; LOCAL const char * const gsm_cops_operimsi_path=MM_FFS_OPER_FILE; #endif /*==== FUNCTIONS ==================================================*/ LOCAL void cmhMM_cvtPnnOpName( UBYTE pnn, UBYTE source_len, UBYTE ext_dcs, CHAR *source, CHAR *oper); LOCAL void cmhMM_decodePnnOpName ( UBYTE oper_len, UBYTE *source_len, UBYTE dcs, CHAR *op_name); LOCAL void cmhMM_decodePnnChs( CHAR *op_name, UBYTE source_len, UBYTE dcs, char *Name ); LOCAL BOOL cmhMM_cvtPLMNINT2BCD ( T_ACI_NRG_FRMT oprFrmt, CHAR *opr); /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhMM_wild_compare | +-------------------------------------------------------------------+ PURPOSE : */ LOCAL BOOL cmhMM_wild_compare( int sim, int bcch ) { if ((bcch & 0x00F) NEQ (sim & 0x00F) AND (sim & 0x00F) != 0x00D) return FALSE; if ((bcch & 0x0F0) NEQ (sim & 0x0F0) AND (sim & 0x0F0) != 0x0D0) return FALSE; if ((bcch & 0xF00) NEQ (sim & 0xF00) AND (sim & 0xF00) != 0xD00) return FALSE; return TRUE; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhSIM_plmn_equal_sim_wc| +-------------------------------------------------------------------+ PURPOSE : */ LOCAL BOOL cmhSIM_plmn_equal_sim_wc (int bcch_mcc, int bcch_mnc, int sim_mcc, int sim_mnc) { /*TRACE_FUNCTION ("cmhSIM_plmn_equal_sim()");*/ /* Check MCC */ if (!cmhMM_wild_compare(sim_mcc, bcch_mcc)) return FALSE; /* Check first 2 MNC digits */ if (!cmhMM_wild_compare(sim_mnc & 0xff0, bcch_mnc & 0xff0)) return FALSE; /* Check for full match */ if (cmhMM_wild_compare(sim_mnc & 0xf, bcch_mnc & 0xf)) return TRUE; /* The 3rd digit of the MNC differs */ if ((bcch_mcc >= 0x310) AND (bcch_mcc <= 0x316)) { /* * The MCC is in the range 310..316, this means North America. * The zero suffix rule applies. */ return ((((sim_mnc & 0xf) EQ 0xf) AND ((bcch_mnc & 0xf) EQ 0x0)) OR (((sim_mnc & 0xf) EQ 0x0) AND ((bcch_mnc & 0xf) EQ 0xf))); } return ((bcch_mnc & 0xf) EQ 0xf); } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhMM_FindPLMN | +-------------------------------------------------------------------+ PURPOSE : scan the list of operators to find the PLMN representation. NOTE: This function looks as if it could be simplified and shortened. However, it is expected that it works. */ GLOBAL BOOL cmhMM_FindPLMN( T_OPER_ENTRY * plmnDesc, SHORT mcc, SHORT mnc, U16 lac, BOOL nw_search ) { int i; /* holds list idx */ EF_PLMN plmn; /* holds PLMN identifier */ SHORT sim_mcc; /* Integer representation MCC */ SHORT sim_mnc; /* Integer representation MNC */ USHORT maxRec; /* holds maximum records */ USHORT recNr; /* holds record number */ UBYTE retVal; /* holds return value */ UBYTE ver; /* holds version */ #ifdef TI_PS_OP_OPN_TAB_ROMBASED /* Changes for ROM data */ const UBYTE *plmn_comp_entry; /* get a local pointer holder */ T_OPER_ENTRY oper; #endif /* *------------------------------------------------------------------- * search list of PNN records if SIM is EONS enabled *------------------------------------------------------------------- */ TRACE_FUNCTION ("cmhMM_FindPLMN()"); TRACE_EVENT_P3 ("mcc: %x, mnc %x, lac: %x", mcc, mnc, lac); /* Initial conditions for Data Coding Scheme and PLMN name source */ memset (plmnDesc, 0, sizeof (T_OPER_ENTRY)); /* plmnDesc.dcs = 0; */ plmnDesc->pnn = Read_ROM_TABLE; if(psaSIM_ChkSIMSrvSup(SRV_PNN)) { if (!nw_search) /* this is not for network search list */ { if(psaSIM_ChkSIMSrvSup(SRV_OPL) OR cmhSIM_plmn_is_hplmn (mcc, mnc)) { if (mmShrdPrm.PNNLst.plmn.v_plmn EQ VLD_PLMN) { plmnDesc->mcc = mcc; plmnDesc->mnc = mnc; plmnDesc->pnn = Read_EONS; plmnDesc->long_len = mmShrdPrm.PNNLst.long_len; plmnDesc->long_ext_dcs = mmShrdPrm.PNNLst.long_ext_dcs; plmnDesc->shrt_len = mmShrdPrm.PNNLst.shrt_len; plmnDesc->shrt_ext_dcs = mmShrdPrm.PNNLst.shrt_ext_dcs; if(mmShrdPrm.PNNLst.long_len) { memcpy (plmnDesc->longName, mmShrdPrm.PNNLst.long_name, MINIMUM(mmShrdPrm.PNNLst.long_len, MAX_LONG_OPER_LEN - 1)); } if(mmShrdPrm.PNNLst.shrt_len > 0) { memcpy (plmnDesc->shrtName, mmShrdPrm.PNNLst.shrt_name, MINIMUM(mmShrdPrm.PNNLst.shrt_len, MAX_SHRT_OPER_LEN - 1)); } return TRUE; } else { U16 current_lac = lac; if (current_lac EQ NOT_PRESENT_16BIT) current_lac = mmShrdPrm.lac; for (i=0; i<simShrdPrm.opl_list.num_rcd; i++) { int pnn_rec_number = simShrdPrm.opl_list.opl_rcd[i].pnn_rec_num; SHORT sim_mcc, sim_mnc; cmhSIM_getMncMccFrmPLMNsel (simShrdPrm.opl_list.opl_rcd[i].plmn, &sim_mcc, &sim_mnc); if (pnn_rec_number EQ 0xFF) continue; /* empty record, continue with next one */ if(cmhSIM_plmn_equal_sim_wc( mcc, mnc, sim_mcc, sim_mnc) AND ( (simShrdPrm.opl_list.opl_rcd[i].lac1 EQ 0x0000 AND simShrdPrm.opl_list.opl_rcd[i].lac2 EQ 0xFFFE) OR (simShrdPrm.opl_list.opl_rcd[i].lac1 <= current_lac AND simShrdPrm.opl_list.opl_rcd[i].lac2 >= current_lac) ) ) { if (pnn_rec_number EQ 0) break; /* 31.102: 4.2.59 EFOPL (Operator PLMN List): A value of '00' indicates that the name is to be taken from other sources, see TS 22.101 [24] */ pnn_rec_number--; /* adjust to zero based array */ if (simShrdPrm.pnn_list.pnn_rcd[pnn_rec_number].v_plmn) { plmnDesc->mcc = mcc; plmnDesc->mnc = mnc; plmnDesc->pnn = Read_EONS; plmnDesc->long_len = MINIMUM (simShrdPrm.pnn_list.pnn_rcd[pnn_rec_number].long_len, MAX_LONG_OPER_LEN - 1); memcpy (plmnDesc->longName, simShrdPrm.pnn_list.pnn_rcd[pnn_rec_number].long_name, plmnDesc->long_len); plmnDesc->long_ext_dcs = simShrdPrm.pnn_list.pnn_rcd[pnn_rec_number].long_ext_dcs; plmnDesc->shrt_len = MINIMUM (simShrdPrm.pnn_list.pnn_rcd[pnn_rec_number].shrt_len, MAX_SHRT_OPER_LEN - 1); memcpy (plmnDesc->shrtName, simShrdPrm.pnn_list.pnn_rcd[pnn_rec_number].shrt_name, plmnDesc->shrt_len); plmnDesc->shrt_ext_dcs = simShrdPrm.pnn_list.pnn_rcd[pnn_rec_number].shrt_ext_dcs; return TRUE; } } } } } } else /* the procedure is used for building the PLMN selection list */ { T_pnn_name *current; /* points to PNN element currently compared */ current = (T_pnn_name *)mmShrdPrm.PNNLst.next; while (current != NULL) { SHORT sim_mcc, sim_mnc; cmhMM_CnvrtPLMN2INT (current->plmn.mcc, current->plmn.mnc, &sim_mcc, &sim_mnc); if (cmhSIM_plmn_equal_sim (mcc, mnc, sim_mcc, sim_mnc) AND (current->lac EQ lac)) { if(current->plmn.v_plmn EQ VLD_PLMN) { plmnDesc->mcc = mcc; plmnDesc->mnc = mnc; plmnDesc->pnn = Read_EONS; plmnDesc->long_len = MINIMUM (current->long_len, MAX_LONG_OPER_LEN - 1); plmnDesc->long_ext_dcs = current->long_ext_dcs; plmnDesc->shrt_len = MINIMUM (current->shrt_len, MAX_SHRT_OPER_LEN - 1); plmnDesc->shrt_ext_dcs = current->shrt_ext_dcs; if (current->long_len) { memcpy (plmnDesc->longName, current->long_name, plmnDesc->long_len); } if (current->shrt_len) { memcpy (plmnDesc->shrtName, current->shrt_name, plmnDesc->shrt_len); } return TRUE; } } else current = (T_pnn_name *)current->next; } } } if((ONSReadStatus EQ ONS_READ_OVER) AND cmhSIM_plmn_is_hplmn (mcc, mnc)) { *plmnDesc = ONSDesc; /* Struct assignment */ plmnDesc->mcc = mcc; plmnDesc->mnc = mnc; plmnDesc->pnn = Read_CPHS; return TRUE; } /* *------------------------------------------------------------------- * search list of operators ( PCM table ) *------------------------------------------------------------------- */ recNr = 1; do { /* Implements Measure#32: Row 110 */ retVal= pcm_ReadRecord( (UBYTE *) ef_plmn_id, recNr, SIZE_EF_PLMN, (UBYTE *)&plmn, &ver, &maxRec ); if( retVal EQ PCM_INVALID_SIZE OR retVal EQ PCM_INVALID_RECORD ) break; sim_mcc = (plmn.mcc[0] << 8) + plmn.mcc[1]; sim_mnc = (plmn.mnc[0] << 8) + plmn.mnc[1]; if (cmhSIM_plmn_equal_sim (mcc, mnc, sim_mcc, sim_mnc)) { cmhMM_CnvrtTrmPCMOpNam( plmnDesc, &plmn ); plmnDesc->mcc = sim_mcc; plmnDesc->mnc = sim_mnc; return TRUE; } recNr++; } while( recNr <= maxRec ); /* *------------------------------------------------------------------- * search list of operators ( fixed table ) *------------------------------------------------------------------- */ #ifdef TI_PS_OP_OPN_TAB_ROMBASED /* Changes for ROM data */ plmn_comp_entry = ptr_plmn_compressed; while (cmhMM_decodePlmn (&oper, plmn_comp_entry) EQ 0) { /* Get first compressed PLMN entry */ sim_mcc = oper.mcc; sim_mnc = oper.mnc; if (cmhSIM_plmn_equal_sim (mcc, mnc, sim_mcc, sim_mnc)) { strncpy (plmnDesc->longName, oper.longName, MAX_LONG_OPER_LEN - 1); strncpy (plmnDesc->shrtName, oper.shrtName, MAX_SHRT_OPER_LEN - 1); plmnDesc->mcc = oper.mcc; plmnDesc->mnc = oper.mnc; return TRUE; } /* Next compressed PLMN entry */ plmn_comp_entry += cmhMM_PlmnEntryLength (plmn_comp_entry); } #else for( i = 0; operListFixed[i].mcc NEQ -1 AND operListFixed[i].mnc NEQ -1; i++ ) { sim_mcc = operListFixed[i].mcc; sim_mnc = operListFixed[i].mnc; if (cmhSIM_plmn_equal_sim (mcc, mnc, sim_mcc, sim_mnc)) { strncpy (plmnDesc->longName, operListFixed[i].longName, MAX_LONG_OPER_LEN - 1); strncpy (plmnDesc->shrtName, operListFixed[i].shrtName, MAX_SHRT_OPER_LEN - 1); plmnDesc->mcc = operListFixed[i].mcc; plmnDesc->mnc = operListFixed[i].mnc; return TRUE; } } #endif /* *------------------------------------------------------------------- * only mnc and mcc description available *------------------------------------------------------------------- */ plmnDesc->mcc = mcc; plmnDesc->mnc = mnc; /* * The competitor has here a more sophisticated algorithm: * If they know the country code, they don't display the * MCC in numerical representation, but an abbreviation * for the country. We are satisfied displaying the MCC * and saving the ROM space for the country table. */ if ( ( mnc & 0xF) NEQ 0xf ) /* is 3rd digit mnc? */ { sprintf (plmnDesc->longName, "%03x %03x", mcc, mnc); } else { /* only 2-digit-MNC */ mnc = (mnc & 0x0FF0) >> 4; sprintf (plmnDesc->longName, "%03x %02x", mcc, mnc); } strcpy (plmnDesc->shrtName, plmnDesc->longName); return TRUE; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhMM_isBandAllowed | +-------------------------------------------------------------------+ PURPOSE : Check if band combination is part of bands allowed by manufacturer. To be used by AT%BAND. Per convention: if AllowedBands = 0, all bands are allowed. band 0 is never allowed (that is not a combination !!) */ GLOBAL BOOL cmhMM_isBandAllowed( UBYTE band, UBYTE AllowedBands ) { if( AllowedBands EQ 0x00 ) { /* no manufacturer constraint */ return(TRUE); } if( band EQ 0x00) { return(FALSE); } if( (band & AllowedBands) EQ band ) { return( TRUE ); } else return( FALSE ); } /* +---------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhMM_writeSetBand | +---------------------------------------------------------------------+ PURPOSE : */ #define SIZE_OF_RFCAP (16*sizeof(UBYTE)) GLOBAL BOOL cmhMM_writeSetBand( UBYTE setband ) { #ifndef _SIMULATION_ T_FFS_RET ret_ffs; UBYTE RFCap[SIZE_OF_RFCAP]; /* RFCap has 16 bytes */ /* Implements Measure#32: Row 114 */ ret_ffs = FFS_fread(gsm_com_rfcap_path, RFCap, SIZE_OF_RFCAP); if(ret_ffs < 0) /* error */ { TRACE_EVENT_P1("RFCap: cannot read FFS: error n: %d", ret_ffs); return(FALSE); } /* write user bands into FFS */ RFCap[0] = setband; /* Implements Measure#32: Row 114 */ ret_ffs = FFS_fwrite(gsm_com_rfcap_path, RFCap, SIZE_OF_RFCAP); if( ret_ffs NEQ EFFS_OK ) { TRACE_EVENT_P1("Cannot write value on RFCap, error n: %d", ret_ffs); return(FALSE); } TRACE_EVENT("cmhMM_writeSetBand: data writing in FFS successful"); #endif /* _SIMULATION_ */ return( TRUE ); } /* +---------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhMM_getBandSettings | +---------------------------------------------------------------------+ PURPOSE : */ GLOBAL BOOL cmhMM_getBandSettings( UBYTE *SetBands, UBYTE *AllowedBands ) { UBYTE intern_set_bands = 0x00, /* initialized to NOT SET */ intern_allowed_bands = 0x00; /* avoid several checks against NULL */ BOOL ret = FALSE; #ifndef _SIMULATION_ UBYTE RFCap[SIZE_OF_RFCAP]; /* RFCap has 16 bytes */ T_FFS_RET ret_ffs; TRACE_FUNCTION("cmhMM_getBandSettings()"); /* Implements Measure#32: Row 114 */ ret_ffs = FFS_fread(gsm_com_rfcap_path, RFCap, SIZE_OF_RFCAP); if(ret_ffs < 0) /* error */ { TRACE_EVENT_P1("cmhMM_getBandSettings: RFCap: cannot read FFS: error n: %d", ret_ffs); } else { TRACE_EVENT("cmhMM_getBandSettings: data reading from FFS successful"); intern_set_bands = RFCap[0]; intern_allowed_bands = RFCap[1]; ret = TRUE; } #endif /* #ifndef _SIMULATION_ */ if( SetBands NEQ NULL ) { *SetBands = intern_set_bands; TRACE_EVENT_P1("User defined Band bitfield: %d", *SetBands); } if( AllowedBands NEQ NULL ) { *AllowedBands = intern_allowed_bands; TRACE_EVENT_P1("Manufacturer defined Band bitfield: %d", *AllowedBands); } return (ret); } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhMM_FindNumeric | +-------------------------------------------------------------------+ PURPOSE : Convert operator representation from string into numeric. NOTE: The cmhMM_FindNumeric() function is not part of the public declared interface to ACI. However some guys from the MFW team are using this function in mfw_nma.c, declaring the function prototype in the nfw_nma.c file locally. Be careful with changes. */ GLOBAL BOOL cmhMM_FindNumeric( T_OPER_ENTRY * plmnDesc, const CHAR *numStr ) { USHORT idx; BOOL ready; TRACE_FUNCTION ("cmhMM_FindNumeric()"); plmnDesc->mcc = 0; plmnDesc->mnc = 0; ready = FALSE; /* * Convert string representation into internal represention */ for (idx = 0; idx < SIZE_MCC + SIZE_MNC; idx++) { if (idx < SIZE_MCC) { /* * Converting MCC */ if (!ready AND numStr[idx] >= '0' AND numStr[idx] <= '9') { plmnDesc->mcc = (plmnDesc->mcc << 4) + numStr[idx] - '0'; } else { ready = TRUE; } } else { /* * Converting MNC */ if (!ready AND numStr[idx] >= '0' AND numStr[idx] <= '9') { plmnDesc->mnc = (plmnDesc->mnc << 4) + numStr[idx] - '0'; } else { ready = TRUE; if ((plmnDesc->mnc & 0x00F) NEQ 0xF) plmnDesc->mnc = (plmnDesc->mnc << 4) + 0xF; } } } /* *------------------------------------------------------------------- * search list of operators *------------------------------------------------------------------- */ (void)cmhMM_FindPLMN (plmnDesc, plmnDesc->mcc, plmnDesc->mnc, NOT_PRESENT_16BIT, FALSE); /* decode 7 Bit default GSM for MFW */ if (plmnDesc->pnn EQ Read_EONS) { /* Implements Measure 70 */ cmhMM_decodePnnOpName( MAX_LONG_OPER_LEN, &(plmnDesc->long_len), plmnDesc->long_ext_dcs, plmnDesc->longName ); /* Implements Measure 70 */ cmhMM_decodePnnOpName( MAX_SHRT_OPER_LEN, &(plmnDesc->shrt_len), plmnDesc->shrt_ext_dcs, plmnDesc->shrtName ); } return TRUE; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhMM_FindName | +-------------------------------------------------------------------+ PURPOSE : scan the list of operators to find the short or long name representation. NOTE: The cmhMM_FindName() function is not part of the public declared interface to ACI. However some guys from the MFW team are using this function in mfw_nma.c, declaring the function prototype in the nfw_nma.c file locally. Be careful with changes. */ GLOBAL BOOL cmhMM_FindName( T_OPER_ENTRY * plmnDesc, const CHAR *string, T_ACI_CPOL_FRMT format ) { EF_PLMN plmn; /* holds PLMN identifier */ USHORT maxRec; /* holds maximum records */ USHORT recNr; /* holds record number */ UBYTE retVal; /* holds return value */ UBYTE ver; /* holds version */ char longName[(MAX_ALPHA_OPER_LEN*8+6)/7]; char shrtName[(MAX_ALPHA_OPER_LEN*8+6)/7]; #ifdef TI_PS_OP_OPN_TAB_ROMBASED /* Changes for ROM data */ const UBYTE *plmn_comp_entry; /* get a local pointer holder */ T_OPER_ENTRY oper; #else /* TI_PS_OP_OPN_TAB_ROMBASED */ USHORT idx; /* holds list idx */ #endif /* TI_PS_OP_OPN_TAB_ROMBASED */ /* Initial conditions for Data Coding Scheme and PLMN name source */ memset (plmnDesc, 0, sizeof (T_OPER_ENTRY)); plmnDesc->pnn = Read_ROM_TABLE; /* *------------------------------------------------------------------- * search list of PNN records if SIM is EONS enabled *------------------------------------------------------------------- */ if(psaSIM_ChkSIMSrvSup(SRV_PNN) AND psaSIM_ChkSIMSrvSup(SRV_OPL)) { T_pnn_name *current; /* points to PNN element currently compared */ /* The current will be taken from PNNLst only if the pnn_rec_num is valid. Otherwise start with next pointer. */ if (mmShrdPrm.PNNLst.pnn_rec_num NEQ 0) { current = &mmShrdPrm.PNNLst; } else { current = (T_pnn_name *)mmShrdPrm.PNNLst.next; } while (current NEQ NULL) { longName[0]=shrtName[0]='\0'; if (current->long_len) { switch (current->long_ext_dcs>>4 & 0x07) { case 0x00: utl_cvtPnn7To8((UBYTE *)current->long_name, current->long_len, current->long_ext_dcs, (UBYTE *)longName); break; case 0x01: TRACE_ERROR ("ERROR: Unhandled UCS2"); break; default: TRACE_ERROR ("ERROR: Unknown DSC"); break; } } if (current->shrt_len) { switch (current->shrt_ext_dcs>>4 & 0x07) { case 0x00: utl_cvtPnn7To8((UBYTE *)current->shrt_name, current->shrt_len, current->shrt_ext_dcs, (UBYTE *)shrtName); break; case 0x01: TRACE_ERROR ("ERROR: Unhandled UCS2"); break; default: TRACE_ERROR ("ERROR: Unknown DSC"); break; } } /* To avoid the endless loop we need to check v_plmn along with the name checking. */ if(((format EQ CPOL_FRMT_Long) AND (strncmp (string, (char *)longName, strlen(string)) EQ 0)) OR ((format EQ CPOL_FRMT_Short) AND (strncmp (string,(char *)shrtName, strlen(string)) EQ 0)) AND (current->plmn.v_plmn EQ VLD_PLMN)) { plmnDesc->pnn = Read_EONS; /* decode Name since MFW expects 8-Bit string */ strncpy (plmnDesc->longName, longName, MAX_LONG_OPER_LEN - 1); plmnDesc->longName[MAX_LONG_OPER_LEN - 1] = '\0'; plmnDesc->long_len = strlen (plmnDesc->longName); strncpy (plmnDesc->shrtName, shrtName, MAX_SHRT_OPER_LEN - 1); plmnDesc->shrtName[MAX_SHRT_OPER_LEN -1] = '\0'; plmnDesc->shrt_len = strlen (plmnDesc->shrtName); cmhMM_CnvrtPLMN2INT( current->plmn.mcc, current->plmn.mnc, &plmnDesc->mcc, &plmnDesc->mnc ); return TRUE; } else { current = (T_pnn_name *)current->next; } } } if((ONSReadStatus EQ ONS_READ_OVER) AND (strcmp (string, (char *)ONSDesc.longName) EQ 0)) { *plmnDesc = ONSDesc; /* Struct assignment */ plmnDesc->mcc = ONSDesc.mcc; plmnDesc->mnc = ONSDesc.mnc; plmnDesc->pnn = Read_CPHS; return TRUE; } /* *------------------------------------------------------------------- * search list of operators ( PCM table ) *------------------------------------------------------------------- */ recNr = 1; do { /* Implements Measure#32: Row 110 */ retVal= pcm_ReadRecord( (UBYTE *) ef_plmn_id, recNr, SIZE_EF_PLMN, (UBYTE *)&plmn, &ver, &maxRec ); if( retVal EQ PCM_INVALID_SIZE OR retVal EQ PCM_INVALID_RECORD ) break; cmhMM_CnvrtTrmPCMOpNam( plmnDesc, &plmn ); if ((format EQ CPOL_FRMT_Short AND strcmp(plmnDesc->shrtName, string) EQ 0) OR (format EQ CPOL_FRMT_Long AND strcmp(plmnDesc->longName, string) EQ 0)) { plmnDesc->mcc = (plmn.mcc[0] << 8) + plmn.mcc[1]; plmnDesc->mnc = (plmn.mnc[0] << 8) + plmn.mnc[1]; return TRUE; } recNr++; } while( recNr <= maxRec ); /* *------------------------------------------------------------------- * search list of operators ( fixed table ) *------------------------------------------------------------------- */ #ifdef TI_PS_OP_OPN_TAB_ROMBASED /* Changes for ROM data */ plmn_comp_entry = ptr_plmn_compressed; while (cmhMM_decodePlmn (&oper, plmn_comp_entry) EQ 0) { if ((format EQ CPOL_FRMT_Short AND strcmp((char*)oper.shrtName, string) EQ 0) OR (format EQ CPOL_FRMT_Long AND strcmp((char*)oper.longName, string) EQ 0)) { memset (plmnDesc, 0, sizeof (T_OPER_ENTRY)); strncpy (plmnDesc->longName, oper.longName, MAX_LONG_OPER_LEN - 1); strncpy (plmnDesc->shrtName, oper.shrtName, MAX_SHRT_OPER_LEN - 1); plmnDesc->mcc = oper.mcc; plmnDesc->mnc = oper.mnc; return TRUE; } /* Next compressed PLMN entry */ plmn_comp_entry += cmhMM_PlmnEntryLength (plmn_comp_entry); } #else for( idx = 0; operListFixed[idx].shrtName NEQ NULL; idx++ ) { if ((format EQ CPOL_FRMT_Short AND strcmp((char*)operListFixed[idx].shrtName, string) EQ 0) OR (format EQ CPOL_FRMT_Long AND strcmp((char*)operListFixed[idx].longName, string) EQ 0)) { memset (plmnDesc, 0, sizeof (T_OPER_ENTRY)); strncpy (plmnDesc->longName, operListFixed[idx].longName, MAX_LONG_OPER_LEN - 1); strncpy (plmnDesc->shrtName, operListFixed[idx].shrtName, MAX_SHRT_OPER_LEN - 1); plmnDesc->mcc = operListFixed[idx].mcc; plmnDesc->mnc = operListFixed[idx].mnc; return TRUE; } } #endif return FALSE; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhMM_CnvrtPLMN2INT | +-------------------------------------------------------------------+ PURPOSE : convert the BCD PLMN notation for mcc and mnc into integer values. */ GLOBAL void cmhMM_CnvrtPLMN2INT( const UBYTE * BCDmcc, const UBYTE * BCDmnc, SHORT * mccBuf, SHORT * mncBuf ) { SHORT idx; /* * Convert MCC */ *mccBuf = 0; for (idx = 0; idx < SIZE_MCC; idx++) { *mccBuf = (*mccBuf << 4) + BCDmcc[idx]; } /* * Convert MNC */ *mncBuf = 0; for (idx = 0; idx < SIZE_MNC; idx++) { *mncBuf = (*mncBuf << 4) + BCDmnc[idx]; } } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhMM_CnvrtINT2PLMN | +-------------------------------------------------------------------+ PURPOSE : convert the integer PLMN notation for mcc and mnc into BCD representation. */ GLOBAL void cmhMM_CnvrtINT2PLMN( SHORT INTmcc, SHORT INTmnc, UBYTE * mccBuf, UBYTE * mncBuf ) { SHORT idx; SHORT shift; /* * Convert MCC */ shift = 0; for (idx = SIZE_MCC - 1; idx >= 0; idx--) { /*lint -e{702} */ mccBuf[idx] = (INTmcc >> shift) & 0xf; shift += 4; } /* * Convert MNC */ shift = 0; for (idx = SIZE_MNC - 1; idx >= 0; idx--) { /*lint -e{702} */ mncBuf[idx] = (INTmnc >> shift) & 0xf; shift += 4; } } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhMM_GetNregCREGStat | +-------------------------------------------------------------------+ PURPOSE : return CREG status for a not registered state. */ GLOBAL T_ACI_CREG_STAT cmhMM_GetNregCREGStat( void ) { switch( mmShrdPrm.regMode ) { case( MODE_AUTO ): #if defined GPRS AND defined (DTI) if ( cmhGMM_isClassCG() ) return(CREG_STAT_NoSearch); else #endif { /* Depending on the deregistration cause proper CREG state has been sent to the user */ switch(mmShrdPrm.deregCs) { case( NREG_LIMITED_SERVICE ): return(CREG_STAT_Denied); case( NREG_NO_SERVICE ): return(CREG_STAT_NoSearch); default: return(CREG_STAT_Unknown); } } case( MODE_MAN ): return(CREG_STAT_NoSearch); default: return(CREG_STAT_Unknown); } } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhMM_GetNregCMEStat | +-------------------------------------------------------------------+ PURPOSE : return CME error status for a not registered state. */ GLOBAL T_ACI_CME_ERR cmhMM_GetNregCMEStat( void ) { switch( mmShrdPrm.regStat ) { case( NO_VLD_RS ): case( RS_NO_SRV ): return( CME_ERR_NoServ ); case( RS_LMTD_SRV ): return( CME_ERR_LimServ ); default: return( CME_ERR_Unknown ); } } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhMM_GetOperLstLen | +-------------------------------------------------------------------+ PURPOSE : return CME error status for a not registered state. */ GLOBAL USHORT cmhMM_GetOperLstLen( void ) { #ifdef TI_PS_OP_OPN_TAB_ROMBASED return (OPERLIST_FIXED_LEN); #else return((sizeof(operListFixed)/sizeof(T_OPER_NTRY_FIXED))-1); #endif } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MM | | ROUTINE : cmhMM_CnvrtTrmPCMOpNam | +-------------------------------------------------------------------+ PURPOSE : Convert and terminate PCM long and short operator names. */ GLOBAL void cmhMM_CnvrtTrmPCMOpNam( T_OPER_ENTRY *plmnDesc, void *pPCMBuf ) { UBYTE len; EF_PLMN * pPlmn = (EF_PLMN *)pPCMBuf; /* convert and terminate long name */ for( len = 0; len < SIZE_EF_PLMN_LONG AND pPlmn->lngNam[len] NEQ 0xFF; len++ ) ; if (len > MAX_LONG_OPER_LEN - 1) len = MAX_LONG_OPER_LEN - 1; utl_cvtGsmIra( pPlmn->lngNam, len, (UBYTE *)plmnDesc->longName, len, CSCS_DIR_GsmToIra ); plmnDesc->longName[len] = '\0'; /* convert and terminate short name */ for( len = 0; len < SIZE_EF_PLMN_SHRT AND pPlmn->shrtNam[len] NEQ 0xFF; len++ ) ; if (len > MAX_SHRT_OPER_LEN - 1) len = MAX_SHRT_OPER_LEN - 1; utl_cvtGsmIra( pPlmn->shrtNam, len, (UBYTE *)plmnDesc->shrtName, len, CSCS_DIR_GsmToIra ); plmnDesc->shrtName[len] = '\0'; } /* +----------------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH | | ROUTINE : cmhMM_Ntfy_NtwRegistrationStatus | +----------------------------------------------------------------------------+ PURPOSE : report function */ #ifdef FF_CPHS LOCAL BOOL has_roaming_state_changed(T_CPHS_ROAMING_IND roaming_ind) { static T_CPHS_ROAMING_IND last_roam_notified = CPHS_ROAMING_STAT_NotPresent; T_CPHS_ROAMING_IND previous_roam; TRACE_EVENT_P2("has_roaming_state_changed() roam: %d, previous roam: %d", roaming_ind, last_roam_notified); previous_roam = last_roam_notified; /* update last_roam_notified */ last_roam_notified = roaming_ind; /* status has not changed at all */ if(roaming_ind EQ previous_roam) return(FALSE); /* Mobile is entering Roaming service: since roaming is different from last roaming */ if((roaming_ind EQ CPHS_INTERNATIONAL_ROAMING_ON) OR (roaming_ind EQ CPHS_NATIONAL_ROAMING_ON)) return(TRUE); /* Mobile is not in Roaming service: Check whether this has already been told to the user */ if((previous_roam EQ CPHS_INTERNATIONAL_ROAMING_ON) OR (previous_roam EQ CPHS_NATIONAL_ROAMING_ON)) return(TRUE); return(FALSE); } LOCAL void cmhMM_cphs_roaming(T_ACI_CREG_STAT creg) { SHORT mncCur, mccCur; /* Holds MNC and MCC of current PLMN */ SHORT sim_mcc; /* Holds the MCC of the HPLMN from the SIM */ SHORT sim_mnc; /* Holds the MNC of the HPLMN from the SIM */ T_CPHS_ROAMING_IND roaming_ind = CPHS_ROAMING_STAT_NotPresent; /* Decision on whether roaming within or outside the home country * made on the basis of the MCC of the selected PLMN. */ if (creg EQ CREG_STAT_Roam) { cmhMM_CnvrtPLMN2INT( mmShrdPrm.usedPLMN.mcc, mmShrdPrm.usedPLMN.mnc, &mccCur, &mncCur ); if(!cmhMM_GetActingHPLMN(&sim_mcc, &sim_mnc))/*Enhancement Acting HPLMN*/ { /* Extract the HPLMN identification out of the IMSI digits. */ cmhSIM_GetHomePLMN (&sim_mcc, &sim_mnc); } if (sim_mcc NEQ mccCur) { roaming_ind = CPHS_INTERNATIONAL_ROAMING_ON; } else { roaming_ind = CPHS_NATIONAL_ROAMING_ON; } } else if (creg EQ CREG_STAT_Reg) { roaming_ind = CPHS_ROAMING_OFF; } if(has_roaming_state_changed(roaming_ind)) { /* Roaming state has changed */ if (roaming_ind EQ CPHS_ROAMING_STAT_NotPresent) { roaming_ind = CPHS_ROAMING_OFF; } cphs_roaming_ind((UBYTE)roaming_ind); } } #endif /* FF_CPHS */ GLOBAL void cmhMM_Ntfy_NtwRegistrationStatus( T_ACI_CREG_STAT creg ) { SHORT src; T_ACI_P_CREG_GPRS_IND gprs_ind; U8 rt; TRACE_FUNCTION ("cmhMM_Ntfy_NtwRegistrationStatus()"); #ifdef FF_CPHS cmhMM_cphs_roaming(creg); #endif /* FF_CPHS */ #if defined (GPRS) AND defined (DTI) gprs_ind = gmmShrdPrm.gprs_indicator; rt = gmmShrdPrm.rt; #else gprs_ind = P_CREG_GPRS_Not_Supported; /* ACI-SPR-17218: use ACI type */ rt = 0; #endif /* notify GSM change in network status */ /* +CREG */ if( creg NEQ CREG_STAT_NotPresent ) { mmShrdPrm.creg_status = creg; for( src = 0; src < CMD_SRC_MAX; src++ ) { R_AT( RAT_CREG, (T_ACI_CMD_SRC)src )( creg, mmShrdPrm.lac, mmShrdPrm.cid ); R_AT( RAT_P_CREG, (T_ACI_CMD_SRC)src )( creg, mmShrdPrm.lac, mmShrdPrm.cid, gprs_ind ,rt); } } } /* +-------------------------------------------------------------------------------------+ | PROJECT : GSM-PS MODULE : CMH | | ROUTINE : cmhMM_OpCheckName | +-------------------------------------------------------------------------------------+ PURPOSE : Function for EONS support. Checks if the operator name should be read from EF_PNN upon registration or location update. */ GLOBAL BOOL cmhMM_OpCheckName() { SHORT mncCur, mccCur; /* holds converted mnc and mcc of current PLMN */ SHORT mncOpl, mccOpl; T_opl_field *ptrOpl; UBYTE i, pnn_rec_num=0; BOOL ret = TRUE; TRACE_FUNCTION ("cmhMM_OpCheckName()"); /* check if PNN is active and allocated on SIM */ if(psaSIM_ChkSIMSrvSup(SRV_PNN)) { /* check if OPL is active and allocated */ /* if OPL not activaten and T_mobile EONS is not enabled then the first record of PNN holds the operator name of the HPLMN */ if(!psaSIM_ChkSIMSrvSup(SRV_OPL) AND (cuscfgParams.T_MOBILE_Eons NEQ CUSCFG_MOD_Enable)) { /* only read PNN if not already present */ if(mmShrdPrm.PNNLst.plmn.v_plmn NEQ VLD_PLMN) { /* if HPLMN: this sequence is copied from cmhMM_Registered() */ cmhMM_CnvrtPLMN2INT( mmShrdPrm.usedPLMN.mcc, mmShrdPrm.usedPLMN.mnc, &mccCur, &mncCur ); if( cmhSIM_plmn_is_hplmn (mccCur, mncCur)) { ret = cmhMM_OpReadName(1); } } return ret; } /* check if the registered PLMN or LAC has changed since last registration */ if (memcmp (mmShrdPrm.usedPLMN.mcc, mmShrdPrm.PNNLst.plmn.mcc, SIZE_MCC) NEQ 0 OR memcmp (mmShrdPrm.usedPLMN.mnc, mmShrdPrm.PNNLst.plmn.mnc, SIZE_MNC) NEQ 0 OR mmShrdPrm.lac NEQ mmShrdPrm.PNNLst.lac) { ptrOpl = cmhSIM_GetOPL(); if (ptrOpl->opl_status) { /* search the OPL list for the new PNN record number */ i = 0; pnn_rec_num = 0; /* if PNN record number in OPL is 0, no PNN name is available. */ while (i < ptrOpl->num_rcd) { cmhMM_CnvrtPLMN2INT( mmShrdPrm.usedPLMN.mcc, mmShrdPrm.usedPLMN.mnc, &mccCur, &mncCur ); cmhSIM_getMncMccFrmPLMNsel (ptrOpl->opl_rcd[i].plmn, &mccOpl, &mncOpl); if(cmhSIM_plmn_equal_sim_wc (mccCur, mncCur, mccOpl, mncOpl) AND (ptrOpl->opl_rcd[i].lac1 <= mmShrdPrm.lac) AND (mmShrdPrm.lac <= ptrOpl->opl_rcd[i].lac2)) { pnn_rec_num = ptrOpl->opl_rcd[i].pnn_rec_num; break; } else i++; } if (pnn_rec_num NEQ 0) { /* only read PNN if it is different from the last one saved */ if (mmShrdPrm.PNNLst.pnn_rec_num NEQ pnn_rec_num) { ret = cmhMM_OpReadName(pnn_rec_num); mmShrdPrm.PNNLst.plmn.v_plmn = INVLD_PLMN; return ret; } } } else TRACE_EVENT("OPL list unavailable");; /* no OPL list available */ } } /* if CPHS ONS file is not already read then read it */ if (!pnn_rec_num AND (ONSReadStatus EQ ONS_READ_NOT_DONE)) { #ifdef FF_CPHS ret = cmhMM_ONSReadName(); #endif } return ret; } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSF | | STATE : code ROUTINE : cmhMM_OpReadName | +-------------------------------------------------------------------+ PURPOSE : Sends a SIM read request RESULT: has an error occured ? Returns: FALSE if primitive has been sent and TRUE if not */ GLOBAL BOOL cmhMM_OpReadName(UBYTE rcd) { TRACE_FUNCTION ("cmhMM_OpReadName()"); if (cmhSIM_ReadRecordEF (CMD_SRC_NONE, AT_CMD_NONE, FALSE, NULL, SIM_PNN, rcd, NOT_PRESENT_8BIT, NULL, cmhMM_OpReadNameCb) EQ AT_FAIL) { TRACE_EVENT("FATAL ERROR"); return(TRUE); } return(FALSE); } /* +---------------------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSF | | STATE : code ROUTINE : cmhMM_OpReadNameCb | +---------------------------------------------------------------------------------+ PURPOSE : Call back for SIM retrieval of EF_PNN. */ GLOBAL void cmhMM_OpReadNameCb(SHORT table_id) { UBYTE *data; TRACE_FUNCTION ("cmhMM_OpReadNameCb()"); data = simShrdPrm.atb[table_id].exchData; /* Decode and copy PNN record data to PNN list*/ /*------------------------------------------*/ if (simShrdPrm.atb[table_id].errCode EQ SIM_NO_ERROR) /* Process only if file is read */ { mmShrdPrm.PNNLst.plmn = mmShrdPrm.usedPLMN; mmShrdPrm.PNNLst.lac = mmShrdPrm.lac; mmShrdPrm.PNNLst.pnn_rec_num = simShrdPrm.atb[table_id].recNr; if (*data++ EQ PNN_LONG_NAME_IEI) { mmShrdPrm.PNNLst.long_len = (*data++)-1; /* substract dcs byte from lem */ mmShrdPrm.PNNLst.long_ext_dcs = *data++; memcpy (mmShrdPrm.PNNLst.long_name, data, MINIMUM(mmShrdPrm.PNNLst.long_len, sizeof(mmShrdPrm.PNNLst.long_name))); data += mmShrdPrm.PNNLst.long_len; /* PNN_SHORT_NAME_IEI is an optional field */ if (*data++ EQ PNN_SHORT_NAME_IEI) { mmShrdPrm.PNNLst.shrt_len = (*data++)-1; /* substract dcs byte from len */ mmShrdPrm.PNNLst.shrt_ext_dcs = *data++; memcpy (mmShrdPrm.PNNLst.shrt_name, data, MINIMUM(mmShrdPrm.PNNLst.shrt_len, sizeof(mmShrdPrm.PNNLst.shrt_name))); } else { mmShrdPrm.PNNLst.shrt_len = 0; } mmShrdPrm.PNNLst.next = NULL; } else /* PNN_LONG_NAME_IEI is a mandatory field in PNN, if not present, PNN is invalid */ { /* PNN record number 0 indicates no PNN name is available */ mmShrdPrm.PNNLst.pnn_rec_num = 0; } } cmhMM_Registered (); simShrdPrm.atb[table_id].ntryUsdFlg = FALSE; } /* +---------------------------------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSF | | STATE : code ROUTINE : cmhMM_OpSetPNNLst | +---------------------------------------------------------------------------------------------+ PURPOSE : starts reading of EF_PNN from SIM and creates PNN list for manual PLMN selection. */ GLOBAL void cmhMM_OpSetPNNLst() { T_opl_field *ptrOpl; UBYTE i,j, pnn_rec_num; TRACE_FUNCTION ("cmhMM_OpSetPNNLst()"); ptrOpl = cmhSIM_GetOPL(); if (ptrOpl->opl_status) { mmShrdPrm.pnn_read_cnt = 0; /* search the OPL list for the PNN record number for every entry in the network search lists */ /* OPL list is searched for every entry in the network search lists */ for (j=0; j < MAX_PLMN_ID; j++) { /* check if entry in PLMNLst is valid */ if( mmShrdPrm.PLMNLst[j].v_plmn NEQ INVLD_PLMN ) { pnn_rec_num = 0; /* if PNN record number in OPL is 0, no PNN name is available. */ i = 0; ptrOpl = cmhSIM_GetOPL(); while (i < ptrOpl->num_rcd) /* search OPL list for PLMN nr. j */ { SHORT bcch_mcc, bcch_mnc; SHORT sim_mcc, sim_mnc; cmhMM_CnvrtPLMN2INT (mmShrdPrm.PLMNLst[j].mcc, mmShrdPrm.PLMNLst[j].mnc, &bcch_mcc, &bcch_mnc); cmhSIM_getMncMccFrmPLMNsel (ptrOpl->opl_rcd[i].plmn, &sim_mcc, &sim_mnc); if (cmhSIM_plmn_equal_sim (bcch_mcc, bcch_mnc, sim_mcc, sim_mnc) AND ((ptrOpl->opl_rcd[i].lac1 EQ 0x0000 AND ptrOpl->opl_rcd[i].lac2 EQ 0xFFFE) OR (ptrOpl->opl_rcd[i].lac1 <= mmShrdPrm.LACLst[j] AND mmShrdPrm.LACLst[j] <= ptrOpl->opl_rcd[i].lac2))) { pnn_rec_num = ptrOpl->opl_rcd[i].pnn_rec_num; break; } else i++; } if (pnn_rec_num NEQ 0) { if (cmhSIM_ReadRecordEF (CMD_SRC_NONE, AT_CMD_NONE, FALSE, NULL, SIM_PNN, pnn_rec_num, /* the PNN rec. number is read */ NOT_PRESENT_8BIT, NULL, cmhMM_OpExtractNameCB) EQ AT_FAIL) { TRACE_EVENT("FATAL ERROR"); break; /* try to continue with the next one instead of return since otherwise AT+COPS=? will hang if cmhMM_NetworkLst() is not called! */ } /* in cmhMM_OpExtractNameCB the latest received PNN is placed right after the PNN-list head */ /* pnn_nr array is used for finding the associated plmn and lac in cmhMM_OpExtractNameCB. */ mmShrdPrm.pnn_nr[j] = pnn_rec_num; mmShrdPrm.pnn_read_cnt++; } else { /* name is to be taken from other sources, 3G TS 22.101 */ } } else { break; /* and Invalid PLMN indicates the end of the list. */ } } if (mmShrdPrm.pnn_read_cnt EQ 0) /* nothing processed? */ { if(( mmEntStat.curCmd EQ AT_CMD_COPS) OR ( mmEntStat.curCmd EQ AT_CMD_P_COPS) ) cmhMM_NetworkLst(); /* then print list anyway, otherwise AT+COPS=? will fail. */ } } else { if(( mmEntStat.curCmd EQ AT_CMD_COPS) OR ( mmEntStat.curCmd EQ AT_CMD_P_COPS) ) cmhMM_NetworkLst(); /* then print list anyway, otherwise AT+COPS=? will fail. */ } } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_SMSF | | STATE : code ROUTINE : cmhMM_OpExtractName | +-------------------------------------------------------------------+ PURPOSE : decodes EF_PNN record read from SIM. */ GLOBAL void cmhMM_OpExtractNameCB(SHORT table_id) { UBYTE *data; UBYTE i; T_pnn_name *newPNN; TRACE_FUNCTION ("cmhMM_OpExtractNameCB()"); data = simShrdPrm.atb[table_id].exchData; if (*data++ EQ PNN_LONG_NAME_IEI) { MALLOC(newPNN,sizeof(T_pnn_name)); newPNN->next = NULL; newPNN->pnn_rec_num = simShrdPrm.atb[table_id].recNr; /*find the associated PLMN and LAC for this PNN */ i = 0; while (i < MAX_PLMN_ID) { if (mmShrdPrm.pnn_nr[i] EQ newPNN->pnn_rec_num) { newPNN->plmn = mmShrdPrm.PLMNLst[i]; newPNN->lac = mmShrdPrm.LACLst[i]; break; } else i++; } newPNN->long_len = (*data++)-1; /* substract dcs byte */ newPNN->long_ext_dcs = *data++; memcpy (newPNN->long_name, data, MINIMUM(newPNN->long_len, sizeof(newPNN->long_name))); data += newPNN->long_len; /*----- IEI PNN short name ------*/ if (*data++ EQ PNN_SHORT_NAME_IEI) { newPNN->shrt_len = (*data++)-1; /* substract dcs byte */ newPNN->shrt_ext_dcs = *data++; memcpy (newPNN->shrt_name, data, MINIMUM(newPNN->shrt_len,sizeof(newPNN->shrt_name))); } else { newPNN->shrt_len = 0; } /* insert new element right after the static stored PNN name. */ newPNN->next = mmShrdPrm.PNNLst.next; mmShrdPrm.PNNLst.next = newPNN; } mmShrdPrm.pnn_read_cnt--; /* reading of PNN records completed, network list is prepared */ if (mmShrdPrm.pnn_read_cnt EQ 0) cmhMM_NetworkLst (); /* Deallocation of elements in linked list PNN */ // As you see, you see nothing. // ============================ // Immediate deallocation is not possible as someone could have // the idea to do a AT+COPS=? and immediately thereafter a // AT+COPS=1,0,"T-Mobile D" or AT+COPS=1,1,"TMO D" // A workaround could be to free everything not present in the actual // network list. Until now only a theoretical problem. For further study. // There is a second problem that this MM EONS extension list is not // affected by SAT changes of the respective files. Until now also // only theoretical and for further study. // And there is a third problem. This is, there exist 2 solutions // in the PS for EONS, the first one sitting in SIM related ACI around // the T_pnn data structure and the second one sitting in MM related ACI // around the T_pnn_name data structure. Two solutions for the same // problem. // => We should consider in the future to remove the implementation around // T_pnn_name and to enhance the T_pnn in SIM to end up in only one // implementation. This would improve the PS and save ROM. // Maybe the increasement of PNN_MAX_RECORDS to MAX_PLMN_ID + 1 or // something somewhat bigger will already do, otherwise an // intelligent entry replacement (aging) algorithm has to be introduced. // For further study. simShrdPrm.atb[table_id].ntryUsdFlg = FALSE; } /* +-------------------------------------------------------------------------------------+ | PROJECT : GSM-PS MODULE : CMH | | ROUTINE : cmhMM_OpUpdateName | +-------------------------------------------------------------------------------------+ PURPOSE : Function for EONS support. Updates the operator name by reading EF_PNN. RETURNS: false if PS busy with reading files (primitive has been sent) TRUE if PS can go on with the updating */ GLOBAL BOOL cmhMM_OpUpdateName() { SHORT mncCur, mccCur; /* holds converted mnc and mcc of current PLMN */ T_opl_field *ptrOpl; UBYTE i, pnn_rec_num; TRACE_FUNCTION ("cmhMM_OpUpdateName()"); /* check if OPL is active and allocated */ /* if OPL not activate the first record of PNN holds the operator name of the HPLMN */ if(!psaSIM_ChkSIMSrvSup(SRV_OPL)) { cmhMM_CnvrtPLMN2INT( mmShrdPrm.usedPLMN.mcc, mmShrdPrm.usedPLMN.mnc, &mccCur, &mncCur ); if( cmhSIM_plmn_is_hplmn (mccCur, mncCur)) { return(cmhMM_OpReadName(1)); } return(TRUE); /* no primitive has been sent to SIM */ } else /* OPL is active and allocated */ { ptrOpl = cmhSIM_GetOPL(); if (ptrOpl->opl_status) { /* search the OPL list for the new PNN record number */ i = 0; pnn_rec_num = 0; /* if PNN record number in OPL is 0, no PNN name is available. */ while (i < ptrOpl->num_rcd) { SHORT bcch_mcc, bcch_mnc; SHORT sim_mcc, sim_mnc; cmhMM_CnvrtPLMN2INT (mmShrdPrm.usedPLMN.mcc, mmShrdPrm.usedPLMN.mnc, &bcch_mcc, &bcch_mnc); cmhSIM_getMncMccFrmPLMNsel (ptrOpl->opl_rcd[i].plmn, &sim_mcc, &sim_mnc); if (cmhSIM_plmn_equal_sim (bcch_mcc, bcch_mnc, sim_mcc, sim_mnc) AND (ptrOpl->opl_rcd[i].lac1 <= mmShrdPrm.lac) AND (mmShrdPrm.lac <= ptrOpl->opl_rcd[i].lac2)) { pnn_rec_num = ptrOpl->opl_rcd[i].pnn_rec_num; break; } else i++; } if (pnn_rec_num NEQ 0) { return(cmhMM_OpReadName(pnn_rec_num)); } } else TRACE_EVENT("OPL list unavailable");; /* no OPL list available */ } return(TRUE); /* no primitive has been sent to SIM */ } /* +-------------------------------------------------------------------------------------+ | PROJECT : GSM-PS MODULE : CMH | | ROUTINE : cmhMM_GetCmerSettings | +-------------------------------------------------------------------------------------+ */ GLOBAL void cmhMM_GetCmerSettings(T_ACI_CMD_SRC srcId, T_ACI_MM_CMER_VAL_TYPE *sCmerSettings) { sCmerSettings->sCmerModeParam = cmhPrm[srcId].mmCmdPrm.sIndicationParam.sMmCMERSettings.sCmerModeParam; sCmerSettings->sCmerIndParam = cmhPrm[srcId].mmCmdPrm.sIndicationParam.sMmCMERSettings.sCmerIndParam; sCmerSettings->sCmerBfrParam = cmhPrm[srcId].mmCmdPrm.sIndicationParam.sMmCMERSettings.sCmerBfrParam; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MMF | | STATE : code ROUTINE : cmhMM_ChkIgnoreECC | +--------------------------------------------------------------------+ PURPOSE : This function is used to check if ECC should be set as a normal call. (Issue 17570) RETURN: TRUE - if further ECC checking should be ignored and call must be placed as normal FALSE - if ECC checking should be continued */ GLOBAL BOOL cmhMM_ChkIgnoreECC(CHAR *dialStr) { int i=0; SHORT mnc, mcc; /* remove any CLIR suppression/invocation prior checking for ECC */ /* Implements Measure#32: Row 116 & 117 */ if (!strncmp( dialStr, ksd_supp_clir_str, 4) OR !strncmp( dialStr, ksd_inv_clir_str, 4) ) { dialStr+=4; /* skip CLIR supression/invocation digits */ if ( *dialStr EQ '\0' ) { return( FALSE ); /* end already reached? */ } } if(mmShrdPrm.usedPLMN.v_plmn EQ VLD_PLMN) { cmhMM_CnvrtPLMN2INT( mmShrdPrm.usedPLMN.mcc, mmShrdPrm.usedPLMN.mnc, &mcc, &mnc ); while (ECCIgnoreTable[i].mcc NEQ -1 AND ECCIgnoreTable[i].mnc NEQ -1 ) { if ( ECCIgnoreTable[i].mcc EQ mcc AND (ECCIgnoreTable[i].mnc EQ mnc OR ECCIgnoreTable[i].mnc EQ ALL_MNC) ) { if(!strcmp(ECCIgnoreTable[i].ecc, dialStr)) { TRACE_EVENT("cmhCC_ChkIgnoreECC(): no ECC but normal call detected"); return (TRUE); } } i++; } } return (FALSE); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MMF | | STATE : code ROUTINE : cmhMM_OperatorSelect | +--------------------------------------------------------------------+ PURPOSE : This function encapsulates the common CMH functionality of sAT_PlusCOPS(), sAT_PercentCOPS(), and sAT_PercentNRG(). The body of this function is based on the former sAT_PercentNRG(). */ GLOBAL T_ACI_RETURN cmhMM_OperatorSelect(T_ACI_CMD_SRC srcId, T_ACI_NRG_RGMD regMode, T_ACI_NRG_SVMD srvMode, T_ACI_NRG_FRMT oprFrmt, CHAR *opr) { T_MM_CMD_PRM * pMMCmdPrm; /* points to MM command parameters */ T_SIM_SET_PRM * pSIMSetPrm; /* points to SIM parameter set */ T_ACI_RETURN retVal=AT_FAIL; /* holds return value */ UBYTE rm; /* holds converted registration mode */ TRACE_FUNCTION ("cmhMM_OperatorSelect()"); /* *------------------------------------------------------------------- * check command source *------------------------------------------------------------------- */ if(!cmh_IsVldCmdSrc (srcId)) { mmEntStat.curCmd = AT_CMD_NONE; /*Unset the Current Command */ return( AT_FAIL ); } pMMCmdPrm = &cmhPrm[srcId].mmCmdPrm; pSIMSetPrm = &simShrdPrm.setPrm[srcId]; mmShrdPrm.regModeBeforeAbort = mmShrdPrm.regMode; /* *------------------------------------------------------------------- * process the regMode parameter *------------------------------------------------------------------- */ switch( regMode ) { case( NRG_RGMD_Auto ): rm = MODE_AUTO; break; case( NRG_RGMD_Manual ): case( NRG_RGMD_Both ): rm = MODE_MAN; if(!cmhSIM_isplmnmodebit_set()) { mmEntStat.curCmd = AT_CMD_NONE; /*Unset the Current Command */ ACI_ERR_DESC( ACI_ERR_CLASS_Cme, CME_ERR_OpNotAllow ); return( AT_FAIL ); } break; case( NRG_RGMD_Dereg ): rm = MODE_AUTO; break; default: mmEntStat.curCmd = AT_CMD_NONE; /*Unset the Current Command */ ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter ); return( AT_FAIL ); } /* *------------------------------------------------------------------- * process the srvMode parameter *------------------------------------------------------------------- */ switch( srvMode ) { /* *--------------------------------------------------------------- * setting of registration mode only. This is only used by %NRG. It is obsolete and * should be removed at some point in the future. *--------------------------------------------------------------- */ case( NRG_SVMD_SetRegModeOnly ): /* * Unset the Current Command to match exactly what sAT_PercentNRG() * used to do. */ mmEntStat.curCmd = AT_CMD_NONE; mmShrdPrm.regMode = rm; mmShrdPrm.regModeAutoBack = FALSE; /* * Documentation (8415.052.00.002) says: * * "<srvMode>=3 can be used to change the behaviour of registration * in case of a loss of coverage. If connection to the operator is * lost and <regMode> was set to manual, ME tries to register the previous * operator automatically.". This is not exactly what is done here. * What is done is that the registration mode is set to automatic in MM. * The main difference is that for phase 2+ the HPLMN search period * will be evaluated by RR and the HPLMN may be reselected after 30 minutes, * even without any loss of coverage. */ #ifdef GPRS if( psaG_MM_CMD_SET_REGMD ( rm ) < 0 ) /* restore former registration mode*/ #else if( psaMM_SetRegMode ( rm ) < 0 ) /* set registration mode */ #endif { TRACE_EVENT( "FATAL RETURN psaMM_SetRegMode in %%NRG" ); ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Internal ); retVal = AT_FAIL; } else retVal = AT_CMPL; break; /* *--------------------------------------------------------------- * registration to full service *--------------------------------------------------------------- */ case( NRG_SVMD_Full ): /* For the %NRG case, only if SIM data is available we can start a registration attempt * But the COPS commands dont require that. */ if(( simShrdPrm.SIMStat EQ SS_OK AND simShrdPrm.PINStat EQ PS_RDY ) OR (mmEntStat.curCmd NEQ AT_CMD_NRG)) { switch( regMode ) { case( NRG_RGMD_Auto ): /* automatic registration */ mmShrdPrm.regModeAutoBack = FALSE; mmShrdPrm.regMode = MODE_AUTO; mmShrdPrm.owner = (T_OWN)srcId; mmEntStat.entOwn = srcId; #ifdef GPRS /* Taken from the former sAT_PlusCOPS() * COPS will be request an only GSM registration. * If the ME is an only GPRS mobile, then it is impossible to request only GSM. * This patch will be eliminate an error in this situation. * * brz, 02.07.01 */ if ( cmhGMM_class_eq_CG() EQ TRUE ) { mmEntStat.curCmd = AT_CMD_NONE; /*Unset the Current Command */ return AT_CMPL; } #endif #ifdef GPRS if( psaG_MM_CMD_REG ( ) < 0 ) /* register to network */ #else if( psaMM_Registrate () < 0 ) /* register to network */ #endif { TRACE_EVENT( "FATAL RETURN psaMM_Registrate in cmhMM_OperatorSelect()" ); ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Internal ); retVal = AT_FAIL; break; } cmhMM_Ntfy_NtwRegistrationStatus(CREG_STAT_Search); retVal = AT_EXCT; break; case( NRG_RGMD_Manual ): /* manual registration */ case( NRG_RGMD_Both ): /* manual followed by automatic reg. */ mmShrdPrm.regModeAutoBack = (regMode EQ NRG_RGMD_Both); /* * The following code is for %COPS=1 and %NRG=1. * It will get the IMSI and last registered PLMN from FFS. * If the IMSI has changed or no information is available in FFS, * it will tell MM to register to the operator stored in EF(LOCI). * If the IMSI hasn't changed, it will manually register to the Operator stored in FFS. * */ if( !opr OR !*opr) { UBYTE mcc[SIZE_MCC]; UBYTE mnc[SIZE_MNC]; UBYTE IMSI[MAX_IMSI-1]; char tempIMSI[MAX_IMSI] = {'\0'}; BOOL readFromLOCI =FALSE; mmShrdPrm.slctPLMN.v_plmn = VLD_PLMN; /* Get the IMSI and last registered PLMN from FFS. * Compare the IMSI stored in FFS to the current one. If the same, copy MCC and MNC * to pMMSetPrm -> slctPLMN. This will select this network manually. This has to be * done only when the curCmd is %COPS. For other commands we need to get it * from EF-LOCI. */ if (cmhMM_OperatorReadFromFFS(mcc,mnc,IMSI) AND (mmEntStat.curCmd EQ AT_CMD_P_COPS)) { TRACE_EVENT("Operator and IMSI succesfully read from FFS!"); if (!memcmp(IMSI,simShrdPrm.imsi.field,MAX_IMSI-1)) { memcpy(mmShrdPrm.slctPLMN.mcc, mcc,SIZE_MCC); memcpy(mmShrdPrm.slctPLMN.mnc, mnc,SIZE_MNC); } else { readFromLOCI = TRUE; } } else readFromLOCI = TRUE; /* If the SIM has changed or FFS cannot be read, read EF(LOCI) from the SIM. * This wil now lead to a PLMN_RES with MNC,MCC=0xFFF: */ if (readFromLOCI) { psaSIM_cnvrtIMSI2ASCII(tempIMSI); psaSIM_decodeIMSI(IMSI,simShrdPrm.imsi.c_field,tempIMSI); cmhMM_CnvrtINT2PLMN( 0xFFF, 0xFFF, mmShrdPrm.slctPLMN.mcc, mmShrdPrm.slctPLMN.mnc ); } } else { /* Implements Measure 118 */ if ( cmhMM_cvtPLMNINT2BCD( oprFrmt, opr ) EQ FALSE ) { return( AT_FAIL ); } } mmShrdPrm.regMode = MODE_MAN; mmShrdPrm.owner = (T_OWN)srcId; mmEntStat.entOwn = srcId; #ifdef GPRS if( psaG_MM_CMD_NET_SEL ( ) < 0 ) /* register to network */ #else if( psaMM_NetSel () < 0 ) /* register to network */ #endif { TRACE_EVENT( "FATAL RETURN psaMM_NetSel in %%NRG" ); ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Internal ); retVal = AT_FAIL; break; } cmhMM_Ntfy_NtwRegistrationStatus(CREG_STAT_Search); retVal = AT_EXCT; break; } } /* * No SIM data is available, activate SIM * The following block of code was only available in the former sAT_PercentNRG() * Therefore, it will only be executed by the %NRG command. */ else { /* check SIM entity status */ if( simEntStat.curCmd NEQ AT_CMD_NONE ) return( AT_BUSY ); /* prepare PLMN desc for later use */ if( regMode EQ NRG_RGMD_Manual ) { if( ! opr ) { mmEntStat.curCmd = AT_CMD_NONE; /*Unset the Current Command */ ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter ); return( AT_FAIL ); } /* Implements Measure 118 */ if ( cmhMM_cvtPLMNINT2BCD( oprFrmt, opr ) EQ FALSE ) { return( AT_FAIL ); } } pSIMSetPrm -> actProc = SIM_INITIALISATION; simEntStat.curCmd = AT_CMD_NRG; simShrdPrm.owner = (T_OWN)srcId; simEntStat.entOwn = srcId; if( psaSIM_ActivateSIM() < 0 ) /* activate SIM card */ { TRACE_EVENT( "FATAL RETURN psaSIM in %%NRG" ); ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Internal ); retVal = AT_FAIL; break; } retVal = AT_EXCT; } break; /* *--------------------------------------------------------------- * registration to limited service. * The COPS commands will use this for deregistration *--------------------------------------------------------------- */ case( NRG_SVMD_Limited ): mmShrdPrm.regModeAutoBack = FALSE; switch( mmShrdPrm.regStat ) { case( RS_LMTD_SRV ): mmEntStat.curCmd = AT_CMD_NONE; /*Unset the Current Command */ retVal = AT_CMPL; break; case( RS_NO_SRV ): case( NO_VLD_RS ): /* * if SIM data is available, do not destory it in ACI. * It may be needed later */ if(( simShrdPrm.SIMStat EQ SS_OK AND simShrdPrm.PINStat EQ PS_RDY ) OR (mmEntStat.curCmd NEQ AT_CMD_NRG)) { /* flag a pending request. It only applies to the %NRG case */ if (mmEntStat.curCmd EQ AT_CMD_NRG) regReqPnd = TRUE; mmShrdPrm.owner = (T_OWN)srcId; mmEntStat.entOwn = srcId; #ifdef GPRS mmShrdPrm.nrgCs = GMMREG_DT_COMB; if( psaG_MM_CMD_DEREG ( mmShrdPrm.nrgCs ) < 0 ) /* deregister from network */ #else mmShrdPrm.nrgCs = CS_SIM_REM; if( psaMM_DeRegistrate () < 0 ) /* deregister from network */ #endif /* GPRS */ { TRACE_EVENT( "FATAL RETURN psaMM_DeRegistrate in %%NRG" ); ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Internal ); retVal = AT_FAIL; } else { /* Next line commented out HM 28.08.00 */ /* simShrdPrm.SIMStat = NO_VLD_SS; */ /* no SIM data available */ retVal = AT_EXCT; } } /* * No SIM data is available, try a registration to limited service. * The following block of code was only available in the former sAT_PercentNRG() * Therefore, it will only be executed by the %NRG command. */ else { mmShrdPrm.regMode = MODE_AUTO; mmShrdPrm.owner = (T_OWN)srcId; mmEntStat.entOwn = srcId; #ifdef GPRS if( psaG_MM_CMD_REG ( ) < 0 ) /* register to network */ #else if( psaMM_Registrate () < 0 ) /* register to network */ #endif { TRACE_EVENT( "FATAL RETURN psaMM_Registrate in %%NRG" ); ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Internal ); retVal = AT_FAIL; } else { retVal = AT_EXCT; } } break; case( RS_FULL_SRV ): mmShrdPrm.owner = (T_OWN)srcId; mmEntStat.entOwn = srcId; #ifdef GPRS mmShrdPrm.nrgCs = GMMREG_DT_COMB; if( psaG_MM_CMD_DEREG ( mmShrdPrm.nrgCs ) < 0 ) /* deregister from network */ #else mmShrdPrm.nrgCs = CS_SIM_REM; if( psaMM_DeRegistrate () < 0 ) /* deregister from network */ #endif { TRACE_EVENT( "FATAL RETURN psaMM_Deregistrate in %%NRG" ); ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Internal ); retVal = AT_FAIL; break; } /* Next line commented out HM 28.08.00 */ /* simShrdPrm.SIMStat = NO_VLD_SS; */ /* no SIM data available */ retVal = AT_EXCT; break; } break; /* *--------------------------------------------------------------- * registration to no service. Only used by %NRG *--------------------------------------------------------------- */ case( NRG_SVMD_NoSrv ): mmShrdPrm.regModeAutoBack = FALSE; mmShrdPrm.owner = (T_OWN)srcId; mmEntStat.entOwn = srcId; #ifdef GPRS mmShrdPrm.nrgCs = GMMREG_DT_COMB; if( psaG_MM_CMD_DEREG ( mmShrdPrm.nrgCs ) < 0 ) /* deregister from network */ #else mmShrdPrm.nrgCs = CS_POW_OFF; if( psaMM_DeRegistrate () < 0 ) /* deregister from network */ #endif { TRACE_EVENT( "FATAL RETURN psaMM_Deregistrate in %%NRG" ); ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Internal ); retVal = AT_FAIL; break; } retVal = AT_EXCT; break; default: mmEntStat.curCmd = AT_CMD_NONE; /*Unset the Current Command */ ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter ); return( AT_FAIL ); } /* *------------------------------------------------------------------- * update NRG parameters *------------------------------------------------------------------- */ if (mmEntStat.curCmd EQ AT_CMD_NRG) { pMMCmdPrm -> NRGsrvMode = srvMode; pMMCmdPrm -> NRGregMode = regMode; pMMCmdPrm -> NRGoprFrmt = oprFrmt; } /* *------------------------------------------------------------------- * log command execution *------------------------------------------------------------------- */ #if defined SMI OR defined MFW OR defined FF_MMI_RIV { T_ACI_CLOG cmdLog; /* holds logging info */ cmdLog.atCmd = mmEntStat.curCmd; cmdLog.cmdType = CLOG_TYPE_Set; cmdLog.retCode = retVal; cmdLog.cId = ACI_NumParmNotPresent; cmdLog.sId = ACI_NumParmNotPresent; if (mmEntStat.curCmd EQ AT_CMD_NRG) { cmdLog.cmdPrm.sNRG.srcId = srcId; cmdLog.cmdPrm.sNRG.regMode = regMode; cmdLog.cmdPrm.sNRG.srvMode = srvMode; cmdLog.cmdPrm.sNRG.oprFrmt = oprFrmt; cmdLog.cmdPrm.sNRG.opr = opr; } else /*+COPS and %COPS. At the moment, the same message sent by both */ { cmdLog.cmdPrm.sCOPS.srcId = srcId; cmdLog.cmdPrm.sCOPS.mode = mmShrdPrm.COPSmode; cmdLog.cmdPrm.sCOPS.format = pMMCmdPrm -> COPSfrmt; cmdLog.cmdPrm.sCOPS.oper = opr; } rAT_PercentCLOG( &cmdLog ); } #endif return( retVal ); } /* Implements Measure#32: Row 118, 119, 980, 986, 987, 1036 & 1037 */ /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MMF | | STATE : code ROUTINE : cmhMM_mcc_mnc_print | +--------------------------------------------------------------------+ PURPOSE : This function will write mcc and mnc using sprintf. */ GLOBAL void cmhMM_mcc_mnc_print( CHAR *oper, SHORT mcc, SHORT mnc) { if ((mnc & 0x00F) EQ 0xF) { sprintf (oper, format_03x02x_str, mcc, mnc >> 4); } else { sprintf (oper, format_03x03x_str, mcc, mnc); } return; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MMF | | STATE : code ROUTINE : cmhMM_OperatorQuery | +--------------------------------------------------------------------+ PURPOSE : This function encapsulates the common CMH functionality of qAT_PlusCOPS(), qAT_PercentCOPS(), and qAT_PercentNRG(). It basically gets the Network Operator name based on the format parameter. */ GLOBAL void cmhMM_OperatorQuery( T_ACI_CMD_SRC srcId, T_ACI_COPS_FRMT format, CHAR *oper) { SHORT mcc, mnc; /* holds coverted values for mcc and mnc */ T_OPER_ENTRY plmnDesc; /* entry of operator list */ BOOL found; TRACE_FUNCTION ("cmhMM_OperatorQuery()"); if( mmShrdPrm.regStat EQ RS_FULL_SRV AND mmShrdPrm.usedPLMN.v_plmn EQ VLD_PLMN) { cmhMM_CnvrtPLMN2INT( mmShrdPrm.usedPLMN.mcc, mmShrdPrm.usedPLMN.mnc, &mcc, &mnc ); found = cmhMM_FindPLMN (&plmnDesc, mcc, mnc, mmShrdPrm.lac, FALSE); if (!found) { TRACE_EVENT("!cmhMM_FindPLMN()"); if( format EQ COPS_FRMT_Numeric ) { /* Implements Measure#32: Row 118 & 119 */ cmhMM_mcc_mnc_print(oper, mcc, mnc); } } else { switch( format ) { case( COPS_FRMT_Long ): TRACE_EVENT("COPS_FRMT_Long"); /* Implements Measure 66 */ cmhMM_cvtPnnOpName( plmnDesc.pnn, plmnDesc.long_len, plmnDesc.long_ext_dcs, plmnDesc.longName, oper ); break; case( COPS_FRMT_Short ): /* Implements Measure 66 */ cmhMM_cvtPnnOpName( plmnDesc.pnn, plmnDesc.shrt_len, plmnDesc.shrt_ext_dcs, plmnDesc.shrtName, oper); break; case( COPS_FRMT_Numeric ): /* Implements Measure#32: Row 118 & 119 */ cmhMM_mcc_mnc_print(oper, mcc, mnc); break; } } } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MMF | | STATE : code ROUTINE : cmhMM_OperatorStoreInFFS | +--------------------------------------------------------------------+ PURPOSE : This function stores the Operator given by MCC and MNC, and the IMSI number in the FFS file given by MM_FFS_OPER_FILE. If the directory in which the file is stored does not exist, it will create it. */ GLOBAL BOOL cmhMM_OperatorStoreInFFS(UBYTE* mcc, UBYTE* mnc, UBYTE* IMSI) { #ifndef _SIMULATION_ T_FFS_RET result; #endif T_FFSPLMNIMSI currentPlmnIMSI; TRACE_FUNCTION("cmhMM_OperatorStoreInFFS"); memcpy( currentPlmnIMSI.IMSI, IMSI, MAX_IMSI-1); memcpy(currentPlmnIMSI.mcc,mcc,SIZE_MCC); memcpy(currentPlmnIMSI.mnc,mnc,SIZE_MNC); #ifndef _SIMULATION_ /* Implements Measure#32: Row 120 */ switch(FFS_mkdir(gsm_cops_path)) {/* Check / Create ffs directory */ case EFFS_OK: TRACE_EVENT("cmhMM_OperatorStoreInFFS: Dir Created "); break; case EFFS_EXISTS: TRACE_EVENT("cmhMM_OperatorStoreInFFS:Dir Exists "); break; default: TRACE_EVENT("cmhMM_OperatorStoreInFFS:Dir Not Created"); return ( FALSE ); } /* Implements Measure#32: Row 121 */ result = FFS_fwrite(gsm_cops_operimsi_path, ¤tPlmnIMSI, sizeof(T_FFSPLMNIMSI)); TRACE_EVENT_P1("cmhMM_OperatorStoreInFFS:FFS dir ok,FFS_fwrite res %x", result); if (result < EFFS_OK) return FALSE; #else /*Simulation is defined*/ memcpy(&RAMPlmnIMSI,¤tPlmnIMSI,sizeof(T_FFSPLMNIMSI)); #endif return TRUE; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MMF | | STATE : code ROUTINE : cmhMM_OperatorReadFromFFS | +--------------------------------------------------------------------+ PURPOSE : This function reads the Operator given by MCC and MNC, and the IMSI number from the FFS file given by MM_FFS_OPER_FILE. */ GLOBAL BOOL cmhMM_OperatorReadFromFFS(UBYTE* mcc, UBYTE* mnc, UBYTE* IMSI) { #ifndef _SIMULATION_ T_FFS_RET result; #endif T_FFSPLMNIMSI currentPlmnIMSI; TRACE_FUNCTION("cmhMM_OperatorReadFromFFS()"); #ifndef _SIMULATION_ /* Implements Measure#32: Row 121 */ result = FFS_fread(gsm_cops_operimsi_path, ¤tPlmnIMSI, sizeof(T_FFSPLMNIMSI)); TRACE_EVENT_P1("FFS result = %d",result); if (result < EFFS_OK) return FALSE; #else memcpy(¤tPlmnIMSI,&RAMPlmnIMSI,sizeof(T_FFSPLMNIMSI)); #endif memcpy( IMSI,currentPlmnIMSI.IMSI, MAX_IMSI-1); memcpy(mcc,currentPlmnIMSI.mcc,SIZE_MCC); memcpy(mnc,currentPlmnIMSI.mnc,SIZE_MNC); return TRUE; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MMF | | STATE : code ROUTINE : cmhMM_GetActingHPLMN | +--------------------------------------------------------------------+ PURPOSE : fills the Acting HPLMN if present. */ GLOBAL BOOL cmhMM_GetActingHPLMN(SHORT * mccBuf, SHORT * mncBuf) { TRACE_FUNCTION("cmhMM_GetActingHPLMN"); if(mmShrdPrm.ActingHPLMN.v_plmn EQ VLD_PLMN) { cmhMM_CnvrtPLMN2INT( mmShrdPrm.ActingHPLMN.mcc, mmShrdPrm.ActingHPLMN.mnc, mccBuf, mncBuf ); TRACE_EVENT("Acting HPLMN Present"); return(TRUE); } TRACE_EVENT("Acting HPLMN not Present"); return (FALSE); } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MMF | | STATE : code ROUTINE : cmhMM_ONSReadName | +-------------------------------------------------------------------+ PURPOSE : Sends a SIM read request RESULT: has an error occured ? Returns: FALSE if primitive has been sent and TRUE if not */ GLOBAL BOOL cmhMM_ONSReadName() { TRACE_FUNCTION ("cmhMM_ONSReadName()"); if (cmhSIM_ReadTranspEF (CMD_SRC_NONE, AT_CMD_NONE, FALSE, NULL, SIM_CPHS_ONSTR, 0, NOT_PRESENT_8BIT, NULL, cmhMM_ONSReadNameCb) EQ AT_FAIL) { TRACE_EVENT("FATAL ERROR"); return(TRUE); } ONSReadStatus = ONS_READING; return(FALSE); } /* +-------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : CMH_MMF | | STATE : code ROUTINE : cmhMM_ONSReadNameCb | +-------------------------------------------------------------------+ PURPOSE : Call back for SIM retrieval of EF_ONS. */ GLOBAL void cmhMM_ONSReadNameCb(SHORT table_id) { int i =0; TRACE_FUNCTION ("cmhMM_ONSReadNameCb()"); if(!(simShrdPrm.atb[table_id].exchData NEQ NULL AND simShrdPrm.atb[table_id].exchData[0] NEQ 0xFF AND simShrdPrm.atb[table_id].errCode EQ SIM_NO_ERROR)) { ONSReadStatus = ONS_READ_FAIL; } else { ONSReadStatus = ONS_READ_OVER; memset (&ONSDesc, 0, sizeof (T_OPER_ENTRY)); ONSDesc.long_len = 0; while (simShrdPrm.atb[table_id].exchData[i] NEQ 0xFF AND ONSDesc.long_len < MAX_LONG_OPER_LEN - 1) { ONSDesc.long_len++; i++; } if (ONSDesc.long_len <= MAX_SHRT_OPER_LEN - 1) { ONSDesc.shrt_len = ONSDesc.long_len; } else { ONSDesc.shrt_len = MAX_SHRT_OPER_LEN - 1; } /* Issue OMAPS00058768 : EFons may have fewer bytes than MAX_LONG_OPER_LEN and if all of them are used bytes then we will not come across 0xFF (unused bytes), which causes ONSDesc.long_len = MAX_LONG_OPER_LEN - 1. So this leads to the function memcpy() to copy garbage characters in front of operator name. */ ONSDesc.long_len = MINIMUM(simShrdPrm.atb[table_id].dataLen, ONSDesc.long_len); ONSDesc.shrt_len = MINIMUM(simShrdPrm.atb[table_id].dataLen, ONSDesc.shrt_len); memcpy (ONSDesc.longName, simShrdPrm.atb[table_id].exchData, ONSDesc.long_len); memcpy (ONSDesc.shrtName, simShrdPrm.atb[table_id].exchData, ONSDesc.shrt_len); ONSDesc.long_ext_dcs = ONS_EXT_DCS; ONSDesc.shrt_ext_dcs = ONS_EXT_DCS; } /* Issue OMAPS00058768 : For file update of ONS we no need to call cmhMM_Registered() */ #ifdef SIM_TOOLKIT if (simShrdPrm.fuRef < 0) #endif { cmhMM_Registered (); } #ifdef SIM_TOOLKIT if (simShrdPrm.fuRef >= 0) { psaSAT_FUConfirm (simShrdPrm.fuRef, (USHORT)((simShrdPrm.atb[table_id].errCode EQ SIM_NO_ERROR)? SIM_FU_SUCCESS: SIM_FU_ERROR)); } #endif simShrdPrm.atb[table_id].ntryUsdFlg = FALSE; } /* +-------------------------------------------------------------- + | PROJECT : GSM-PS (6147) MODULE : CMH_MMF | | STATE : code ROUTINE : cmhMM_Reset_ONSDesc | +---------------------------------------------------------------+ PURPOSE :Issue OMAPS00058768: Reset ONSDesc. */ GLOBAL void cmhMM_Reset_ONSDesc() { memset(&ONSDesc,0x00,sizeof(ONSDesc)); ONSReadStatus = ONS_READ_NOT_DONE; } /* Implements Measure 66 */ /* +------------------------------------------------------------------------------ | Function : cmhMM_cvtPnnOpName +------------------------------------------------------------------------------ | Purpose : This function converts PNN Operator Name. | | Parameters : pnn - PLMN Network Name Source | source_len - Source Length | dcs - DCS | source - Source String | oper - Network Operator String | | Return : void +------------------------------------------------------------------------------ */ LOCAL void cmhMM_cvtPnnOpName( UBYTE pnn, UBYTE source_len, UBYTE dcs, CHAR *source, CHAR *oper ) { char Name[(MAX_ALPHA_OPER_LEN*8+6)/7]; TRACE_FUNCTION ("cmhMM_cvtPnnOpName()"); Name[0] = '\0'; if (pnn EQ Read_EONS) { if (source_len) { cmhMM_decodePnnChs( source, source_len, dcs, Name ); } strncpy( oper, Name, MAX_ALPHA_OPER_LEN-1 ); } else { strncpy( oper, source, MAX_ALPHA_OPER_LEN-1 ); } oper[MAX_ALPHA_OPER_LEN-1] = '\0'; } /* Implements Measure 118 */ /* +------------------------------------------------------------------------------ | Function : cmhMM_cvtPLMNINT2BCD +------------------------------------------------------------------------------ | Purpose : This function convert the integer PLMN notation for | mcc and mnc into BCD representation. || | Parameters : oprFrmt - +COPS Parameter Format | oper - Network Operator String | | Return : BOOL +------------------------------------------------------------------------------ */ LOCAL BOOL cmhMM_cvtPLMNINT2BCD ( T_ACI_NRG_FRMT oprFrmt, CHAR *opr) { T_OPER_ENTRY plmnDesc = {"","",0,0,0,0,0,0,0}; BOOL found; TRACE_FUNCTION ("cmhMM_cvtPLMNINT2BCD()"); switch( oprFrmt ) { case( NRG_FRMT_Long ): found = cmhMM_FindName (&plmnDesc, opr, CPOL_FRMT_Long); break; case( NRG_FRMT_Short ): found = cmhMM_FindName (&plmnDesc, opr, CPOL_FRMT_Short); break; case( NRG_FRMT_Numeric ): found = cmhMM_FindNumeric(&plmnDesc, opr); break; default: found = FALSE; break; } if (!found) { mmEntStat.curCmd = AT_CMD_NONE; ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter ); return FALSE; } mmShrdPrm.slctPLMN.v_plmn = VLD_PLMN; cmhMM_CnvrtINT2PLMN( plmnDesc.mcc, plmnDesc.mnc, mmShrdPrm.slctPLMN.mcc, mmShrdPrm.slctPLMN.mnc ); return TRUE; } /* Implements Measure 70 */ /* +------------------------------------------------------------------------------ | Function : cmhMM_decodePnnOpName +------------------------------------------------------------------------------ | Purpose : This function decodes PNN Operator Name | | Parameters : oper_len - Operater Name Length | source_len - Source Length | dcs - DCS | op_name - Source String | | Return : void +------------------------------------------------------------------------------ */ LOCAL void cmhMM_decodePnnOpName( UBYTE oper_len, UBYTE *source_len, UBYTE dcs, CHAR *op_name) { char Name[(MAX_ALPHA_OPER_LEN*8+6)/7]; TRACE_FUNCTION ("cmhMM_decodePnn7to8()"); Name[0]='\0'; if ( *source_len ) { cmhMM_decodePnnChs( op_name, *source_len, dcs, Name ); strncpy ( op_name, Name, oper_len - 1 ); op_name[oper_len - 1] = '\0'; *source_len = strlen( Name ); } } /* +------------------------------------------------------------------------------ | Function : cmhMM_decodePnnChs +------------------------------------------------------------------------------ | Purpose : This function can convert PNN Operator Name . | Presently it is capable of converting only 7 bit default | alphabet to 8 bit alphabet. | | Parameters : Name - Converted Destination String | source_len - Source Length | dcs - DCS | op_name - Source String that needs to be converted | | Return : void +------------------------------------------------------------------------------ */ LOCAL void cmhMM_decodePnnChs( CHAR *op_name, UBYTE source_len, UBYTE dcs, char *Name ) { TRACE_FUNCTION ("cmhMM_decodePnnChs()"); switch ( dcs>>4 & 0x07 ) { case 0x00: utl_cvtPnn7To8( (UBYTE *)op_name, source_len, dcs, (UBYTE *)Name ); break; case 0x01: TRACE_ERROR ( "ERROR: Unhandled UCS2" ); break; default: TRACE_ERROR ( "ERROR: Unknown DCS" ); break; } } /*==== EOF ========================================================*/