/*
+-----------------------------------------------------------------------------
|  Project :
|  Modul   :  J:\g23m-aci\aci_ext\aci_ext_pers.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 :
+-----------------------------------------------------------------------------
*/
#include "aci_all.h"

#include "aci_cmh.h"
#include "ati_cmd.h"
#include "aci_cmd.h"

#ifdef FAX_AND_DATA
#include "aci_fd.h"
#endif    /* of #ifdef FAX_AND_DATA */

#ifndef WIN32
#define ACI_PERSONALISTION_USE_FFS
#endif

#include "aci.h"
#include "psa.h"
#include "psa_sim.h"
#include "psa_sms.h"
#include "psa_mmi.h"
#include "cmh.h"
#include "phb.h"
#include "aoc.h"

#include "psa_sim.h"            /* simShrdPrm */

#include "aci_ext_pers.h"
#include "aci_slock.h"

#ifdef SIM_PERS
#include "general.h" // inluded for UINT8 compilation error in sec_drv.h
#include "sec_drv.h"
#endif

#include "pcm.h"                /* EF_SIMLCKEXT */

#ifdef MMI_SIMLOCK_TEST
  #define ACI_PERSONALISTION_USE_FFS
#endif

#ifdef ACI_PERSONALISTION_USE_FFS
#include "ffs/ffs.h"
#include "ffs_coat.h"
#endif /* ACI_PERSONALISTION_USE_FFS */



#define SLOCK_PCM_NRM 1         /* SIM lock data is stored as SIMLOCK to the PCM */
#define SLOCK_PCM_EXT 2         /* SIM lock data is stored as SIMLOCKEXT to the PCM */

#ifdef SIM_PERS
#define TRUNCATION_KEY_LEN 8         /*  */
#endif

#ifdef _SIMULATION_
EF_SIMLCKEXT simlock_pcm_memory;    /* emulates the PCM memory in WIN32 environment. */
#endif

#include "aci_ext_pers_cus.h" /* the customer specific personalisation data. */



LOCAL void aci_ext_personalisation_MMI_save( void );

static BOOL in_firstsimpersonalisation = FALSE;    /* this will be set when the phone is powered up after FIRST_SIMLOCK */
static BOOL pre_firstsimpersonalisation = FALSE;   /* this will be set when a FIRST_SIM_LOCK is applied. All further locks
                                                      will not be applied but only prepare the lock for the next power-cycle */
LOCAL void decodeB2A (U8 *bcd, U8 bcd_len, U8 *ascii);          /* decode a BCD to ASCII */
LOCAL void encodeA2B (char *ascii, UBYTE *bcd, UBYTE bcd_len);  /* encode ASCII to BCD, fill up with 0xf */
#ifdef SIM_PERS
EXTERN T_SEC_DRV_CONFIGURATION *cfg_data ;
EXTERN  T_ACI_SIM_CONFIG aci_slock_sim_config;     /* SIM configuration, initialised by a T_SIM_MMI_INSERT_IND */
#endif 




/*
+------------------------------------------------------------------------------
|  Function    : aci_ext_personalisation_init
+------------------------------------------------------------------------------
|  Description : Initialisation of this extension. Might be used to initialise variables, set temporary data to default values and so on.
  This method will be called once before any other public method of this extension.
|
|  Parameters  : void
|
|  Return      : void
|
+------------------------------------------------------------------------------
*/


void aci_ext_personalisation_init( void )
{
#ifdef SIM_PERS
  T_SIMLOCK_TYPE lock_type;
  T_SEC_DRV_RETURN  status ;
#endif

  TRACE_FUNCTION("aci_ext_personalisation_init()");

#ifndef MMI_SIMLOCK_TEST
 
#ifdef SIM_PERS
  
  for (lock_type=SIMLOCK_NETWORK;lock_type<= SIMLOCK_FIRST_SIM ;lock_type++)  //prateek: changed loop till simlock_first_sim
  {
    switch (lock_type)
    {
      case SIMLOCK_NETWORK:       
        status =sec_get_REC (lock_type, &personalisation_nw); 
   if (status NEQ SEC_DRV_RET_Ok)
     personalisation_nw = NULL;
   else 
   {
          AciSLockShrd.status[lock_type]=(T_SIMLOCK_STATUS)personalisation_nw->Header.Status;
          AciSLockShrd.dependency[lock_type]=personalisation_nw->Header.Dependency;
        }
      break;
              
      case SIMLOCK_NETWORK_SUBSET:   
        status =sec_get_REC (lock_type, &personalisation_ns); 
        if (status NEQ SEC_DRV_RET_Ok)
          personalisation_ns= NULL;
        else 
        {
          AciSLockShrd.status[lock_type]=(T_SIMLOCK_STATUS)personalisation_ns->Header.Status;
          AciSLockShrd.dependency[lock_type]=personalisation_ns->Header.Dependency;
        }
      break;
    
      case SIMLOCK_SERVICE_PROVIDER:  
   status =sec_get_REC (lock_type, &personalisation_sp); 
        if (status NEQ SEC_DRV_RET_Ok)
          personalisation_sp= NULL;
        else 
        {
          AciSLockShrd.status[lock_type]=(T_SIMLOCK_STATUS)personalisation_sp->Header.Status;
          AciSLockShrd.dependency[lock_type]=personalisation_sp->Header.Dependency;
        }
        break;
    
      case SIMLOCK_CORPORATE:      
        status =sec_get_REC (lock_type, &personalisation_cp); 
        if (status NEQ SEC_DRV_RET_Ok)
          personalisation_cp = NULL;
        else
        {
          AciSLockShrd.status[lock_type]=(T_SIMLOCK_STATUS)personalisation_cp->Header.Status;
          AciSLockShrd.dependency[lock_type]=personalisation_cp->Header.Dependency;
        }
        break;
    
      case SIMLOCK_SIM:                  
        status =sec_get_REC (lock_type, &personalisation_sim); 
        if (status NEQ SEC_DRV_RET_Ok)
          personalisation_sim = NULL;
        else 
        {
          AciSLockShrd.status[lock_type]=(T_SIMLOCK_STATUS)personalisation_sim->Header.Status;
          AciSLockShrd.dependency[lock_type]=personalisation_sim->Header.Dependency;
        }
        break;
    
        case SIMLOCK_FIRST_SIM:               
          status =sec_get_REC (lock_type, &personalisation_first_sim); 
          if (status NEQ SEC_DRV_RET_Ok)
          {
            TRACE_FUNCTION("personalisation_first_sim = NULL");
            personalisation_first_sim = NULL;
          }
          else 
          {
            AciSLockShrd.status[lock_type]=(T_SIMLOCK_STATUS)personalisation_first_sim->Header.Status;
            AciSLockShrd.dependency[lock_type]=personalisation_first_sim->Header.Dependency;
          }
          break;
     }
   }
#endif //SIM_PERS

#else /*for mmi testing, just read FFS*/  //MMI_SIMLOCK_TEST
  
#endif //MMI_SIMLOCK_TEST
}

#ifdef SIM_PERS

/*
+------------------------------------------------------------------------------
|  Function    : aci_ext_personalisation_free
+------------------------------------------------------------------------------
|  Description : Free the MEPD structure Memory
|
|  Parameters  : void
|
|  Return      : void
|
+------------------------------------------------------------------------------
*/
void aci_ext_personalisation_free( void )
{
   T_SIMLOCK_TYPE lock_type;

   for (lock_type=SIMLOCK_NETWORK;lock_type<=SIMLOCK_FIRST_SIM;lock_type++)
   {
      switch (lock_type)
      {
         case SIMLOCK_NETWORK:   
           if(personalisation_nw NEQ NULL)
           {
              if(personalisation_nw->pBody NEQ NULL)
              {
                MFREE(personalisation_nw->pBody);
              }
              MFREE(personalisation_nw);
            }
          break; 
      
          case SIMLOCK_NETWORK_SUBSET: 
            if(personalisation_ns NEQ NULL)
            {
               if(personalisation_ns->pBody NEQ NULL)
              {
                MFREE(personalisation_ns->pBody);
               }
               MFREE(personalisation_ns);
             }
          break ; 

          case SIMLOCK_SERVICE_PROVIDER:  
            if(personalisation_sp NEQ NULL)
            {
               if(personalisation_sp->pBody NEQ NULL)
              {
                MFREE(personalisation_sp->pBody);
              }
              MFREE(personalisation_sp);
            }
            break ; 
      
            case SIMLOCK_CORPORATE: 
              if(personalisation_cp NEQ NULL)
             {
                 if(personalisation_cp->pBody NEQ NULL)
                {
                  MFREE(personalisation_cp->pBody);
                }
                MFREE(personalisation_cp);
             }
             break ; 
       
             case SIMLOCK_SIM:   
               if(personalisation_sim NEQ NULL)
               {
                 if(personalisation_sim->pBody NEQ NULL)
                 {
                    MFREE(personalisation_sim->pBody);
                 }
                 MFREE(personalisation_sim);
               }
               break ; 

             case SIMLOCK_FIRST_SIM: 
               if(personalisation_first_sim NEQ NULL)
               {
                  MFREE(personalisation_first_sim);
               }
               break; 
      }
   }
}



/*
  ACI extension method for retrieving the status of a single personalisation type.
  The personalisation status is stored in a separate customer managed memory area
  and the customer has to implement this extension method to return the actual status
  of the questioned personalisation type.
  */
T_SIMLOCK_STATUS aci_ext_personalisation_get_status( T_SIMLOCK_TYPE personalisation_type )
{
  TRACE_FUNCTION("aci_ext_personalisation_get_status()");
  #ifdef SIM_PERS
  switch (personalisation_type)
  {
    case SIMLOCK_FIRST_SIM: /* should not occour */
    case SIMLOCK_SIM:         
      if(personalisation_sim NEQ NULL)      
        return personalisation_sim->Header.Status;
      else 
        return SIMLOCK_FAIL;
                
    case SIMLOCK_NETWORK:       
      if(personalisation_nw NEQ NULL)      
        return personalisation_nw->Header.Status;
      else 
        return SIMLOCK_FAIL;
                    
    case SIMLOCK_NETWORK_SUBSET:     
      if(personalisation_ns NEQ NULL)    
        return personalisation_ns->Header.Status;
      else 
        return SIMLOCK_FAIL;
                    
     case SIMLOCK_SERVICE_PROVIDER:  
       if(personalisation_sp NEQ NULL)     
         return personalisation_sp->Header.Status;
       else 
         return SIMLOCK_FAIL;
     
     case SIMLOCK_CORPORATE:      
       if(personalisation_cp NEQ NULL)    
         return personalisation_cp->Header.Status;
       else 
         return SIMLOCK_FAIL;

     default:  return SIMLOCK_FAIL; /* should not occour */
  }
#endif
}


/*
+------------------------------------------------------------------------------
|  Function    : aci_ext_personalisation_verify_password
+------------------------------------------------------------------------------
|  Description : ACI extension method for verifying the passowrd.
|f the password is false then the counter is increased. If maxcnt is reached then the key
|will been blocked. If the password is correct then the counter is set to 0
|
|  Parameters  : personalisation_type - category type (Network,Network subset, Service Provider,Corporate,SIM actegory)
|                     : passwd  - category password
|
|  Return      : T_SIMLOCK_STATUS   - Return SIMLOCK_DISABLED if compare key pass. 
|                                                     - Return SIMLOCK_FAIL if compare key fails.
|                                                     - Return SIMLOCK_BLOCKED if FC counter is greater than 
|                                                        FC Max.
+------------------------------------------------------------------------------
*/


T_SIMLOCK_STATUS aci_ext_personalisation_verify_password( T_SIMLOCK_TYPE personalisation_type, char *passwd)
{

  T_SEC_DRV_RETURN ret;
  UINT8 key_len = 0; /* For truncation check -Samir */


  TRACE_FUNCTION("aci_ext_personalisation_verify_password()");


  aci_slock_set_CFG();
  if(cfg_data EQ NULL)
  {
   return SIMLOCK_FAIL;
  }
  
  if(cfg_data->Flags & SEC_DRV_HDR_FLAG_Truncation)
  {
    key_len = TRUNCATION_KEY_LEN; 
  }
  ret = sec_cmp_KEY(personalisation_type, passwd, key_len) ;
  MFREE(cfg_data);
  
  switch (ret)
  {
    case SEC_DRV_RET_Ok :
      return SIMLOCK_DISABLED;
    break;
  
    case SEC_DRV_RET_KeyWrong :
    case SEC_DRV_RET_KeyMismatch:
    /*Increment failure counter since input password is wrong*/
      ret = sec_FC_Increment();
      aci_slock_set_CFG();
     if(cfg_data EQ NULL)
     {
       return SIMLOCK_FAIL;  
     }
      if(cfg_data->FC_Current >= cfg_data->FC_Max)
      {
        MFREE(cfg_data);
        return SIMLOCK_BLOCKED;
      }
      else 
      {
         MFREE(cfg_data);
         return SIMLOCK_FAIL;  
      }
    break;
  
    default:/*ERROR!- invalid input to sec_cmp_key OR some error in sec_cmp_key*/
      return SIMLOCK_FAIL;
    break;
  }
 }


/*
+------------------------------------------------------------------------------
|  Function    : aci_ext_personalisation_change_password
+------------------------------------------------------------------------------
|  Description : ACI extension method for verifying the passowrd.
|f the password is false then the counter is increased. If maxcnt is reached then the key
|will been blocked. If the password is correct then the counter is set to 0
|
|  Parameters  : personalisation_type - category type (Network,Network subset, Service Provider,Corporate,SIM actegory)
|                     : passwd  - category password
|                     : new_passwd - New Password

|  Return      : T_SIMLOCK_STATUS   - Return OPER_SUCCESS if changes password is successfull. 
|                                                     - Return OPER_FAIL if changes password is fail.
|                                                    
+------------------------------------------------------------------------------
*/

T_SIMLOCK_STATUS  aci_ext_personalisation_change_password( T_SIMLOCK_TYPE personalisation_type, char *passwd, char *new_passwd )
{
  T_SEC_DRV_RETURN   retstat;

  retstat = sec_set_KEY (personalisation_type, passwd, new_passwd, 0);
  switch(retstat)
  {
    case SEC_DRV_RET_Ok : 
          return  OPER_SUCCESS;
    case  SEC_DRV_RET_FCExeeded : 
          AciSLockShrd.blocked = TRUE; 
          return SIMLOCK_BLOCKED ; 
   default : 
         return OPER_FAIL;
  }

}
 

/*
+------------------------------------------------------------------------------
|  Function    : aci_ext_personalisation_set_status
+------------------------------------------------------------------------------
|  Description : ACI extension method for lock/unlock the category record
|
|  Parameters   : personalisation_type - category type (Network,Network subset, Service Provider,Corporate,SIM actegory)
|                     : lock   -   SIMLOCK_ENABLED to lock the category
|                                -   SIMLOCK_DISABLED to unlock the category
|                     : passwd  - category lock/unlock password
|                     
|
|  Return      : T_SIMLOCK_STATUS   - Return SIMLOCK_ENABLED if lock is successfull. 
|                                                     - Return SIMLOCK_DISABLED if unlock is successfull.
|                                                     - Return SIMLOCK_FAIL if lock or unlock fails
|                                                     - Return SIMLOCK_BLOCKED if FC exeeded for wrong password
|                                                     - Return SIMLOCK_FAIL if lock/unlock fail
+------------------------------------------------------------------------------
*/
 
T_SIMLOCK_STATUS aci_ext_personalisation_set_status( T_SIMLOCK_TYPE personalisation_type,
  T_SIMLOCK_STATUS lock, char* passwd)
{

//#ifdef SIM_PERS
  int rec_num = personalisation_type;
  int key_len = 0;
  T_SEC_DRV_RETURN ret;

  TRACE_FUNCTION("aci_ext_personalisation_set_status()");

  if(lock EQ SIMLOCK_ENABLED)
  {
    ret=sec_rec_Lock(rec_num, passwd, key_len,0xffff/*depend mask*/);/*aci_ext_personalisation_verify_password(personalisation_type, passwd);*/
    if (ret EQ SEC_DRV_RET_Ok){
      return SIMLOCK_ENABLED;
    }
    else{
      return SIMLOCK_FAIL;
    }
  }

  if(lock EQ SIMLOCK_DISABLED)
  {
     if(cfg_data->Flags & SEC_DRV_HDR_FLAG_Truncation)
     {
        key_len = TRUNCATION_KEY_LEN; 
     }
     ret = sec_rec_Unlock(rec_num,TEMPORARY_UNLOCK,passwd,key_len,0xffff/*depend mask*/);
     if (ret EQ SEC_DRV_RET_Ok){
       return SIMLOCK_DISABLED;
     }
     else{
       if(ret EQ SEC_DRV_RET_FCExeeded)
      {
         return SIMLOCK_BLOCKED;
      }
      return SIMLOCK_FAIL;
     }
  } 
  return SIMLOCK_FAIL;
  //#endif
}




//#ifdef SIM_PERS

/*
+------------------------------------------------------------------------------
|  Function    : aci_ext_slock_reset_fc
+------------------------------------------------------------------------------
|  Description : For Failure Counter reset. Uses Security Drv. method to reset FC
|
|  Parameters   : fckey -  Password for resetting FC counter
|                     
|
|  Return      : T_OPER_RET_STATUS   - Return OPER_SUCCESS if FC reset is successfull. 
|                                                     - Return OPER_FAIL if FC reset is fail
|                                                    
+------------------------------------------------------------------------------
*/


T_OPER_RET_STATUS  aci_ext_slock_reset_fc(char *fckey)
{
  T_SEC_DRV_RETURN retstat;

  TRACE_FUNCTION("aci_ext_slock_reset_fc ()");

  if ((retstat= sec_FC_Reset(fckey,0)) NEQ SEC_DRV_RET_Ok)
  {
    return OPER_FAIL;
  }
  else{
    return OPER_SUCCESS;
   }
}



/*
+------------------------------------------------------------------------------
|  Function    : aci_ext_slock_sup_info
+------------------------------------------------------------------------------
|  Description : For Supplementary Info( e.g. FC MAX, FC Current value).
|
|  Parameters   : sup_info -which has the element info type and Data value.  
|                     
|
|  Return      : T_OPER_RET_STATUS   - Return OPER_SUCCESS if successfully read the Info type data
|                                                         value from security driver. Info type data value is filled in this 
|                                                         Function
|                                                     - Return OPER_FAIL if unable to read Info type data value from 
|                                                        security driverl
|                                                    
+------------------------------------------------------------------------------
*/


T_OPER_RET_STATUS  aci_ext_slock_sup_info (T_SUP_INFO *sup_info)
{
  T_SEC_DRV_RETURN retstat;
  T_SEC_DRV_CONFIGURATION *cfg_data;

  TRACE_FUNCTION("aci_ext_slock_sup_info ()");

  if ((retstat= sec_get_CFG(&cfg_data)) NEQ SEC_DRV_RET_Ok)
  return OPER_FAIL;
  else 
  {
     switch(sup_info->infoType )
     {
        case(FCMAX ): sup_info->datavalue = cfg_data->FC_Max;     break;
        case(FCATTEMPTSLEFT): sup_info->datavalue = ((cfg_data->FC_Max) - (cfg_data->FC_Current));  break; 
        case(FCRESETFAILMAX ): sup_info->datavalue = cfg_data->FC_Reset_Fail_Max ;   break;
        case(FCRESETFAILATTEMPTSLEFT): sup_info->datavalue = ((cfg_data->FC_Reset_Fail_Max) - (cfg_data->FC_Reset_Fail_Current));  break;   
        case(FCRESETSUCCESSMAX ): sup_info->datavalue = cfg_data->FC_Reset_Success_Max ;   break;
        case(FCRESETSUCCESSATTEMPTSLEFT): sup_info->datavalue = ((cfg_data->FC_Reset_Success_Max) - (cfg_data->FC_Reset_Success_Current));  break; 
        case (TIMERFLAG): sup_info->datavalue =(cfg_data->Flags & SEC_DRV_HDR_FLAG_Unlock_Timer)?(1):(0) ;break; 
        case (ETSIFLAG) :  sup_info->datavalue =(cfg_data->Flags & SEC_DRV_HDR_FLAG_ETSI_Flag)?(1):(0) ;   break;
        case (AIRTELINDFLAG) :  sup_info->datavalue =(cfg_data->Flags & SEC_DRV_HDR_FLAG_Airtel_Ind)?(1):(0) ; break;
     }  /*end of switch*/

     MFREE(cfg_data);/*  deallocate configuration data allocated from Security Driver;    */  
     return OPER_SUCCESS;    
  }
}


/*
+------------------------------------------------------------------------------
|  Function    : aci_ext_auto_personalise
+------------------------------------------------------------------------------
|  Description : It Auto personalise the sim. If Add new IMSI flag set and If Code is not present
|                      then adds the code in the MEPD data  and lock the category ( Network, Sub Network,
|                      sim )
|  Parameters : void  
|                     
|
|  Return        :    void
|                                                    
+------------------------------------------------------------------------------
*/

T_AUTOLOCK_STATUS aci_ext_auto_personalise(T_SIMLOCK_TYPE   current_lock)
{
  UBYTE imsi_sim[MAX_IMSI_LEN+1];
  T_SIMLOCK_TYPE type;
  static UINT16 flag  = 0xffff;
  UINT16 dependMask = 0xffff;
 
  TRACE_FUNCTION("aci_ext_auto_personalise()");
 
  psaSIM_decodeIMSI(simShrdPrm.imsi.field, simShrdPrm.imsi.c_field, (char *)imsi_sim);
 
  if((AciSLockShrd.dependency[SIMLOCK_FIRST_SIM] & NW_AUTO_LOCK)AND (flag & NW_AUTO_LOCK))
  {
     type = SIMLOCK_NETWORK;
     sim_code_present_in_me = FALSE;
     aci_slock_check_NWlock(imsi_sim,1);
     flag &= ~(NW_AUTO_LOCK);

    if(sim_code_present_in_me EQ FALSE)
    {
      aci_ext_add_code(type);
    }
  }

  if((AciSLockShrd.dependency[SIMLOCK_FIRST_SIM] & NS_AUTO_LOCK)AND (flag & NS_AUTO_LOCK))
  {
     type = SIMLOCK_NETWORK_SUBSET;
     flag &= ~(NS_AUTO_LOCK);
     sim_code_present_in_me = FALSE;
     aci_slock_check_NSlock(imsi_sim,1);
     if(sim_code_present_in_me EQ FALSE)
     {
       aci_ext_add_code(type);
     }
  }

  if((AciSLockShrd.dependency[SIMLOCK_FIRST_SIM] & SIM_AUTO_LOCK ) AND (flag & SIM_AUTO_LOCK))
  {
    flag &= ~(SIM_AUTO_LOCK);
    type = SIMLOCK_SIM;
    sim_code_present_in_me = FALSE;
    aci_slock_check_SMlock(imsi_sim,1);
    if(sim_code_present_in_me EQ FALSE)
    {
      aci_ext_add_code(type);
    }
  }

 if((AciSLockShrd.dependency[SIMLOCK_FIRST_SIM] & SP_AUTO_LOCK) AND (flag & SP_AUTO_LOCK))
 {
  if (psaSIM_ChkSIMSrvSup(SRV_GrpLvl1))
  {
     if(aci_slock_sim_config.sim_read_gid1 EQ FALSE)
     {
      aci_slock_sim_read_sim(SIM_GID1, NOT_PRESENT_8BIT, MAX_GID);
      return AUTOLOCK_EXCT ;
     }
     else 
      {       
       type = SIMLOCK_SERVICE_PROVIDER;
       sim_code_present_in_me = FALSE;
       aci_slock_check_SPlock(imsi_sim,1);
       TRACE_FUNCTION_P1("SP sim_code_present_in_me = %d", sim_code_present_in_me);
       switch(sim_code_present_in_me)
        {
         case FALSE : 
               aci_ext_add_code(type);
               break;
         case CHECK_FAIL :
              dependMask &= ~(SP_AUTO_LOCK) ;
              break;
         case TRUE : 
              break;
         }
         flag &= ~(SP_AUTO_LOCK);
      
     }
  }
  else 
  {
     flag &= ~(SP_AUTO_LOCK);
     dependMask &= ~(SP_AUTO_LOCK) ;
  }
 } 


if((AciSLockShrd.dependency[SIMLOCK_FIRST_SIM] & CP_AUTO_LOCK)AND (flag & CP_AUTO_LOCK)) 
 {

   if (psaSIM_ChkSIMSrvSup(SRV_GrpLvl1))
     {
        if(aci_slock_sim_config.sim_read_gid1 EQ FALSE)
        {
         aci_slock_sim_read_sim(SIM_GID1, NOT_PRESENT_8BIT, MAX_GID);
         return AUTOLOCK_EXCT ;
        }
     }

  if (psaSIM_ChkSIMSrvSup(SRV_GrpLvl2))
     {
        if(aci_slock_sim_config.sim_read_gid2 EQ FALSE)
        {
         aci_slock_sim_read_sim(SIM_GID2, NOT_PRESENT_8BIT, MAX_GID);
         return AUTOLOCK_EXCT ;
        }
     }
   
 if(psaSIM_ChkSIMSrvSup(SRV_GrpLvl1) AND psaSIM_ChkSIMSrvSup(SRV_GrpLvl2))
 {
   type = SIMLOCK_CORPORATE;
   sim_code_present_in_me = FALSE;
   aci_slock_check_CPlock(imsi_sim,1);
   switch(sim_code_present_in_me)
    {
      case FALSE : 
           aci_ext_add_code(type);
           break;
      case CHECK_FAIL :
           dependMask &= ~(CP_AUTO_LOCK) ;
           break;
       case TRUE : 
            break;
    }
   flag &= ~(CP_AUTO_LOCK);
 }
  else 
  {
   flag &= ~(CP_AUTO_LOCK);
   dependMask &= ~(CP_AUTO_LOCK) ;
  }
  
}


 sec_rec_Lock(SIMLOCK_FIRST_SIM,NULL,0,dependMask); 
 return AUTOLOCK_CMPL ;
  
}




/*
+------------------------------------------------------------------------------
|  Function    : aci_ext_add_code
+------------------------------------------------------------------------------
|  Description : It append the category code in MEPD. It foolows FIFO procedure while adding the code
|  Parameters : type -- category type (Network,Network subset, Service Provider,Corporate,SIM actegory)  
|  Return        :  void
|                                                    
+------------------------------------------------------------------------------
*/


void aci_ext_add_code(T_SIMLOCK_TYPE type)
{
  UINT16 index =0;
  UBYTE max_num_user_codes;
  UBYTE num_user_codes;
  UBYTE curr_user_code_index;
  UBYTE  imsi_field[20];

  TRACE_FUNCTION("aci_ext_add_code()");
  switch (type)
  {
    case SIMLOCK_NETWORK :
      max_num_user_codes =((UBYTE *) personalisation_nw->pBody)[index];
      index += MAX_NUM_USERCODE_SIZE;
      index += NUM_OPCODE_SIZE ;
      index += OPCODE_LEN_SIZE + ((UBYTE *) personalisation_nw->pBody)[OPCODE_LEN_INDEX];

      num_user_codes = ((UBYTE *)personalisation_nw->pBody)[index];
      index +=NUM_USER_CODE_SIZE;
      curr_user_code_index = ((UBYTE *)personalisation_nw->pBody)[index];
      index += CURR_USER_CODE_INDEX_SIZE ;
    
      memcpy(imsi_field,simShrdPrm.imsi.field,simShrdPrm.imsi.c_field);
      if(simShrdPrm.mnc_len EQ 3)
        imsi_field[NW_CODE_LEN-1] |= 0xf0;  
      else 
        imsi_field[NW_CODE_LEN-1] |= 0xff;
    
      /*
       * If no user code is present, curr_user_code_index will be ff. After that, curr_user_code_index starts from 0
       */
      if((curr_user_code_index EQ 0xff) || (curr_user_code_index EQ max_num_user_codes -1)) 
        curr_user_code_index = 0;  
      else 
        curr_user_code_index++;

      if(num_user_codes < max_num_user_codes)
        num_user_codes++;
    
      memcpy(&((UBYTE *)personalisation_nw->pBody)[index + curr_user_code_index*NW_CODE_LEN/*multiplication added*/],imsi_field,NW_CODE_LEN);
      ((UBYTE *)personalisation_nw->pBody)[index - CURR_USER_CODE_INDEX_SIZE] = curr_user_code_index;
      ((UBYTE *)personalisation_nw->pBody)[index - CURR_USER_CODE_INDEX_SIZE - NUM_USER_CODE_SIZE] = num_user_codes;
      sec_set_REC(type, personalisation_nw);
    break;

    
    case SIMLOCK_NETWORK_SUBSET :
      max_num_user_codes = ((UBYTE *)personalisation_ns->pBody)[index];
      index += MAX_NUM_USERCODE_SIZE;
      index += NUM_OPCODE_SIZE ;
      index += OPCODE_LEN_SIZE + ((UBYTE *) personalisation_ns->pBody)[OPCODE_LEN_INDEX];
  
      num_user_codes = ((UBYTE *) personalisation_ns->pBody)[index];
      index +=NUM_USER_CODE_SIZE;
      curr_user_code_index = ((UBYTE *)personalisation_ns->pBody)[index];
      index += CURR_USER_CODE_INDEX_SIZE ;
  
      memcpy(imsi_field,simShrdPrm.imsi.field,simShrdPrm.imsi.c_field);
      if(simShrdPrm.mnc_len EQ 3)
        imsi_field[NW_NS_CODE_LEN-1] |= 0xf0;  //prateek: unused nibbles to be '00' and not 'FF' to avoid problems during decodeIMSI
      else 
        imsi_field[NW_NS_CODE_LEN-1] |= 0xff;
    
      /*
       * If no user code is present, curr_user_code_index will be ff. After that, curr_user_code_index starts from 0
       */
      if((curr_user_code_index EQ 0xff) || (curr_user_code_index EQ max_num_user_codes -1)) 
        curr_user_code_index = 0;  
      else 
        curr_user_code_index++;
  
      if(num_user_codes < max_num_user_codes)
        num_user_codes++;
    
      memcpy(&((UBYTE *)personalisation_ns->pBody)[index + curr_user_code_index*NW_NS_CODE_LEN/*multiplication added*/],imsi_field,NW_NS_CODE_LEN);
      ((UBYTE *)personalisation_ns->pBody)[index - CURR_USER_CODE_INDEX_SIZE] = curr_user_code_index;
      ((UBYTE *)personalisation_ns->pBody)[index - CURR_USER_CODE_INDEX_SIZE - NUM_USER_CODE_SIZE] = num_user_codes;
      sec_set_REC(type, personalisation_ns);
    break;
    
    case SIMLOCK_SERVICE_PROVIDER :
      if(!psaSIM_ChkSIMSrvSup(SRV_GrpLvl1) OR (aci_slock_sim_config.sim_gidl1[0] EQ 0xff))
      {
        TRACE_FUNCTION("not adding sp as no service or maybe gid1 is ff");
        break;
      }
        
      max_num_user_codes =((UBYTE *) personalisation_sp->pBody)[index];
      index += MAX_NUM_USERCODE_SIZE;
      index += NUM_OPCODE_SIZE ;
      index += OPCODE_LEN_SIZE +  ((UBYTE *)personalisation_sp->pBody)[OPCODE_LEN_INDEX];
  
      num_user_codes = ((UBYTE *)personalisation_sp->pBody)[index];
      index +=NUM_USER_CODE_SIZE;
      curr_user_code_index = ((UBYTE *)personalisation_sp->pBody)[index];
      index += CURR_USER_CODE_INDEX_SIZE ;
      
      memcpy(imsi_field,simShrdPrm.imsi.field,simShrdPrm.imsi.c_field);
      if(simShrdPrm.mnc_len EQ 3)
        imsi_field[NW_CODE_LEN-1] |= 0xf0;  //prateek: unused nibbles to be '00' and not 'FF' to avoid problems during decodeIMSI
      else 
        imsi_field[NW_CODE_LEN-1] |= 0xff;
    
      if (psaSIM_ChkSIMSrvSup(SRV_GrpLvl1))
      {
        memcpy(imsi_field+NW_CODE_LEN,aci_slock_sim_config.sim_gidl1,GID1_LEN);
        /*
          * If no user code is present, curr_user_code_index will be ff. After that, curr_user_code_index starts from 0
              */
        if((curr_user_code_index EQ 0xff) || (curr_user_code_index EQ max_num_user_codes -1)) 
          curr_user_code_index = 0;  
        else 
          curr_user_code_index++;
  
        if(num_user_codes < max_num_user_codes)
          num_user_codes++;
      
        memcpy(&((UBYTE *)personalisation_sp->pBody)[index + curr_user_code_index*(NW_CODE_LEN+GID1_LEN)],imsi_field,NW_CODE_LEN+GID1_LEN);
        ((UBYTE *)personalisation_sp->pBody)[index - CURR_USER_CODE_INDEX_SIZE] = curr_user_code_index;
        ((UBYTE *)personalisation_sp->pBody)[index - CURR_USER_CODE_INDEX_SIZE - NUM_USER_CODE_SIZE] = num_user_codes;
        sec_set_REC(type, personalisation_sp);
       }
     break;
    
    case SIMLOCK_CORPORATE :
      if( !psaSIM_ChkSIMSrvSup(SRV_GrpLvl1) OR !psaSIM_ChkSIMSrvSup(SRV_GrpLvl2) OR (aci_slock_sim_config.sim_gidl1[0] EQ 0xff) OR (aci_slock_sim_config.sim_gidl2[0] EQ 0xff))
      {
        TRACE_FUNCTION("not adding cp as no service or maybe gid1/gid2 is ff");
        break;
      }
      
      max_num_user_codes = ((UBYTE *)personalisation_cp->pBody)[index];
      index += MAX_NUM_USERCODE_SIZE;
      index += NUM_OPCODE_SIZE ;
      index += OPCODE_LEN_SIZE +  ((UBYTE *)personalisation_cp->pBody)[OPCODE_LEN_INDEX];
    
      num_user_codes = ((UBYTE *)personalisation_cp->pBody)[index];
      index +=NUM_USER_CODE_SIZE;
      curr_user_code_index =((UBYTE *) personalisation_cp->pBody)[index];
      index += CURR_USER_CODE_INDEX_SIZE ;
      
      memcpy(imsi_field,simShrdPrm.imsi.field,simShrdPrm.imsi.c_field);
      if(simShrdPrm.mnc_len EQ 3)
        imsi_field[NW_CODE_LEN-1] |= 0xf0;  //prateek: unused nibbles to be '00' and not 'FF' to avoid problems during decodeIMSI
      else
        /* if(curr_user_code_index NEQ 0) */
        imsi_field[NW_CODE_LEN-1] |= 0xff;
    
      if (psaSIM_ChkSIMSrvSup(SRV_GrpLvl1))
      {
        memcpy(imsi_field+NW_CODE_LEN,aci_slock_sim_config.sim_gidl1,GID1_LEN);
        if (psaSIM_ChkSIMSrvSup(SRV_GrpLvl2))
        {
          memcpy(imsi_field+NW_CODE_LEN+GID1_LEN,aci_slock_sim_config.sim_gidl2,GID2_LEN);
          /*
          * If no user code is present, curr_user_code_index will be ff. After that, curr_user_code_index starts from 0
          */
          if((curr_user_code_index EQ 0xff) || (curr_user_code_index EQ max_num_user_codes -1)) 
            curr_user_code_index = 0;  
          else 
            curr_user_code_index++;
      
          if(num_user_codes < max_num_user_codes)
            num_user_codes++;
      
          memcpy(&((UBYTE *)personalisation_cp->pBody)[index + (curr_user_code_index*(NW_CODE_LEN+GID1_LEN+GID2_LEN))],imsi_field,NW_CODE_LEN+GID1_LEN+GID2_LEN);
          ((UBYTE *)personalisation_cp->pBody)[index - CURR_USER_CODE_INDEX_SIZE] = curr_user_code_index;
          ((UBYTE *)personalisation_cp->pBody)[index - CURR_USER_CODE_INDEX_SIZE - NUM_USER_CODE_SIZE] = num_user_codes;
          sec_set_REC(type, personalisation_cp);
        }
      }
    break;
    
    case SIMLOCK_SIM :
      max_num_user_codes = ((UBYTE *)personalisation_sim->pBody)[index];
      index += MAX_NUM_USERCODE_SIZE;
      index += NUM_OPCODE_SIZE ;
      index += OPCODE_LEN_SIZE +  ((UBYTE *)personalisation_sim->pBody)[OPCODE_LEN_INDEX];
  
      num_user_codes = ((UBYTE *)personalisation_sim->pBody)[index];
      index +=NUM_USER_CODE_SIZE;
      curr_user_code_index =((UBYTE *) personalisation_sim->pBody)[index];    
      index += CURR_USER_CODE_INDEX_SIZE ;
  
      memcpy(imsi_field,simShrdPrm.imsi.field,simShrdPrm.imsi.c_field);

      /*
       * If no user code is present, curr_user_code_index will be ff. After that, curr_user_code_index starts from 0
       */
      if((curr_user_code_index EQ 0xff) || (curr_user_code_index EQ max_num_user_codes -1)) 
        curr_user_code_index = 0;  
      else 
        curr_user_code_index++;
  
      if(num_user_codes < max_num_user_codes)
        num_user_codes++;
    
      memcpy(&((UBYTE *)personalisation_sim->pBody)[index + (curr_user_code_index*NW_NS_MSIN_CODE_LEN)],imsi_field,NW_NS_MSIN_CODE_LEN);
      ((UBYTE *)personalisation_sim->pBody)[index - CURR_USER_CODE_INDEX_SIZE] = curr_user_code_index;
      ((UBYTE *)personalisation_sim->pBody)[index - CURR_USER_CODE_INDEX_SIZE - NUM_USER_CODE_SIZE] = num_user_codes;
      sec_set_REC(type, personalisation_sim);
    break;
  }
}

#endif //SIM_PERS



/*
  PURPOSE : convert bcd to ASCII

*/

LOCAL void decodeB2A (U8 *bcd, U8 bcd_len, U8 *ascii)
{
  int i;

  TRACE_FUNCTION("decodeB2A()");

  for (i=0; i<bcd_len*2; i++)
  {
    ascii[i] = (i & 1) ? (bcd[i/2]>>4)+'0' : (bcd[i/2]&0x0f)+'0';
    if (ascii[i]>'9')
      break;  /* stop if invalid digit */
  }
  ascii[i] = 0;
}

LOCAL void encodeA2B (char *ascii, UBYTE *bcd, UBYTE bcd_len)
{
  UBYTE i;
  UBYTE digit;

  TRACE_FUNCTION("encodeA2B()");

  for (i=0; i<bcd_len*2; i++)                 /* fill the whole field, pad remaining with 0xf */
  {
    if (i<strlen(ascii))
    {
      digit = ascii[i];
      if (digit >= '0' OR digit <= '9')
      {
        digit-= '0';
      }
      else
      {
        TRACE_EVENT_P1("[WRN] invalid digit in PIN \"%d\", skipping!", digit);
        digit = 0x0f;
      }
    }
    else
    {
      digit = 0x0f;  /* unused nibbles are set to 'F'. */
    }

    if ((i & 1) EQ 0)
    {
      /* process PIN digit 1,3,5,... at i=0,2,4,...*/
      bcd[i/2]  = digit;
    }
    else
    {
      /* process PIN digit 2,4,6,... at i=1,3,5,...*/
      bcd[i/2] |= digit << 4;
    }
  }
}

/* That is a workaround to buld simulation test cases */
#ifdef _SIMULATION_ 
  #define effs_t int
  #define EFFS_OK 0
  #define FFS_fread(a,  b, c) 0
  #define FFS_fwrite(a,  b, c) 0
#endif /*_SIMULATION_*/ 

#define FFS_MMILOCK_STATUS "/gsm/MELOCK/SecCode"

/*
+------------------------------------------------------------------------------
|  Function    : aci_ext_personalisation_CS_get_status
+------------------------------------------------------------------------------
|  Description : Reads value of CS lock from file and returns it
|  Parameters : void  
|                     
|
|  Return        :    status of CS lock
|  Remark:     :  It is proposed to implement through security driver
|                                                    
+------------------------------------------------------------------------------
*/
T_SIMLOCK_STATUS aci_ext_personalisation_CS_get_status()
{
  effs_t ffs_rslt;
  TRACE_FUNCTION("aci_ext_personalisation_CS_get_status()");

  ffs_rslt = FFS_fread(FFS_MMILOCK_STATUS,  &MMI_personalisation_status, sizeof(MMI_personalisation_status));
  if(ffs_rslt < EFFS_OK)   /* error */
  {
    TRACE_EVENT_P1("unable to read %s", FFS_MMILOCK_STATUS);                    
    return SIMLOCK_FAIL;
  }
  return (T_SIMLOCK_STATUS) MMI_personalisation_status.State;
}


/*
+------------------------------------------------------------------------------
|  Function    : aci_ext_personalisation_CS_set_status
+------------------------------------------------------------------------------
|  Description : Reads value of CS lock from file compare passwords and if correct, sets CS lock status
|  Parameters : lock - enable or disable
|                      passwd - password to change lock
|                     
|
|  Return        :  status of operation
|  Remark:     :  It is proposed to implement through security driver
|                                                    
+------------------------------------------------------------------------------
*/
T_SIMLOCK_STATUS aci_ext_personalisation_CS_set_status(T_SIMLOCK_STATUS lock , char * passwd)
{
  effs_t ffs_rslt;
  U8 exp_pin[6+1];   /* +1 for '\0' */    
  T_SIMLOCK_STATUS result;
  TRACE_FUNCTION("aci_ext_personalisation_CS_set_status()");    

  /* Read data from FFS */ 

  ffs_rslt = FFS_fread(FFS_MMILOCK_STATUS,  &MMI_personalisation_status, sizeof(MMI_personalisation_status));

  if(ffs_rslt < EFFS_OK)   /* error */
  {
    TRACE_EVENT_P1("unable to read %s", FFS_MMILOCK_STATUS);
    return SIMLOCK_FAIL;
  }
 
  decodeB2A(MMI_personalisation_status.Cur_code, 3, exp_pin);    
  
  if (strncmp((char *)exp_pin, (char *)passwd, 3))  
  {    
     /* Block personalisation lock, if tried too often! */    
     MMI_personalisation_status.cnt++;   
     if (MMI_personalisation_status.cnt >= MMI_personalisation_status.maxcnt)    
     {      
        result = SIMLOCK_BLOCKED;
     }    
     else
     {
        result = SIMLOCK_LOCKED;
     }
   }  
   else 
   {    
      /* correct pin passed */
     MMI_personalisation_status.cnt = 0; 
     MMI_personalisation_status.State = lock; 
     result = lock;
    }
    ffs_rslt = FFS_fwrite(FFS_MMILOCK_STATUS,  &MMI_personalisation_status, sizeof(MMI_personalisation_status));

    if (ffs_rslt < EFFS_OK)
    {
      TRACE_EVENT_P1("unable to write %s", FFS_MMILOCK_STATUS);                    
      return SIMLOCK_FAIL;
    }
    return result;
}

/*
+------------------------------------------------------------------------------
|  Function    : aci_ext_personalisation_CS_change_password
+------------------------------------------------------------------------------
|  Description : Reads value of CS lock from file compare passwords and if correct, sets new password
|  Parameters : passwd - old password
|                      new_passwd - new password
|                     
|
|  Return        :  status of operation
|  Remark:     :  It is proposed to implement through security driver
|                                                    
+------------------------------------------------------------------------------
*/
T_SIMLOCK_STATUS aci_ext_personalisation_CS_change_password( char *passwd, char *new_passwd )
{
  effs_t ffs_rslt;
  U8 exp_pin[6+1];   /* +1 for '\0' */    
  T_SIMLOCK_STATUS result;

  TRACE_FUNCTION("aci_ext_personalisation_CS_change_password()");

  ffs_rslt = FFS_fread(FFS_MMILOCK_STATUS,  &MMI_personalisation_status, sizeof(MMI_personalisation_status));
  if(ffs_rslt < EFFS_OK)   /* error */
  {
    TRACE_EVENT_P1("unable to read %s", FFS_MMILOCK_STATUS);  
    return SIMLOCK_FAIL;
  }


  decodeB2A(MMI_personalisation_status.Cur_code, 3, exp_pin);

  if (strncmp((char *)exp_pin, (char *)passwd, 3))
  {
    /* Block personalisation lock, if tried too often! */
    MMI_personalisation_status.cnt++;
    if (MMI_personalisation_status.cnt >= MMI_personalisation_status.maxcnt)    
     {      
        result = SIMLOCK_BLOCKED;
     }    
     else
     {
        result = SIMLOCK_LOCKED;
     }
  }
  else
  {
    /* correct pin passed */
    MMI_personalisation_status.cnt=0;
    if ((new_passwd NEQ NULL) AND (strlen(new_passwd) > 0))
    {
      encodeA2B(new_passwd, MMI_personalisation_status.Cur_code, 3);
    }
    result = (T_SIMLOCK_STATUS) MMI_personalisation_status.State;  
  }
   ffs_rslt = FFS_fwrite(FFS_MMILOCK_STATUS,  &MMI_personalisation_status, sizeof(MMI_personalisation_status));

  if (ffs_rslt < EFFS_OK)
  {
    TRACE_EVENT_P1("unable to write %s", FFS_MMILOCK_STATUS);  
    return SIMLOCK_FAIL;
  }
  return result;
}


