/* * Copyright (C) 2010 NXP Semiconductors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * \file phFriNfc_MifULFormat.c * \brief NFC Ndef Formatting For Mifare ultralight card. * * Project: NFC-FRI * * $Date: Mon Dec 13 14:14:12 2010 $ * $Author: ing02260 $ * $Revision: 1.9 $ * $Aliases: $ * */ #include <phFriNfc_MifULFormat.h> #include <phFriNfc_OvrHal.h> /*! \ingroup grp_file_attributes * \name NDEF Mapping * * File: \ref phFriNfc_MifULFormat.c * */ /*@{*/ #define PHFRINFCMIFULFORMAT_FILEREVISION "$Revision: 1.9 $" #define PHFRINFCMIFULFORMAT_FILEALIASES "$Aliases: $" /*@}*/ #ifdef FRINFC_READONLY_NDEF /* Mifare UL OTP block number is 3 */ #define RD_LOCK_OTP_BLOCK_NUMBER 0x02U #define OTP_BLOCK_NUMBER 0x03U /* READ ONLY value that shall be written in the OTP to make the card read only */ #define READ_ONLY_VALUE_IN_OTP 0x0FU /* Mifare UL OTP block number is 3 */ #define MIFARE_UL_READ_MAX_SIZE 16U /* 1st Lock byte value */ #define MIFARE_UL_LOCK_BYTE1_VALUE 0xF8U /* 2nd Lock byte value */ #define MIFARE_UL_LOCK_BYTE2_VALUE 0xFFU /* Mifare ULC dynamic lock byte address */ #define MIFARE_ULC_DYNAMIC_LOCK_BYTES_ADDR 0x28U /* Type 2 STATIC CARD memory value in the OTP */ #define TYPE_2_STATIC_MEM_SIZE_VALUE 0x06U /* Type 2 DYNAMIC CARD memory value in the OTP */ #define TYPE_2_DYNAMIC_MEM_SIZE_VALUE 0x12U /* Lock byte 3 value to be ORed with the existing value */ #define MIFARE_UL_LOCK_BYTE3_VALUE 0xEEU /* Posiiton of the memory information in the stored OTP bytes */ #define TYPE_2_MEM_SIZE_POSITION 0x02U /* 3rd Lock byte position after reading the block number 0x28 */ #define TYPE_2_LOCK_BYTE3_POS_RD_BLK28 0x00U #ifdef PH_NDEF_MIFARE_ULC /* Lock control TLVs, TYPE identifier */ #define LOCK_CTRL_TYPE_IN_TLV 0x01U /* Lock control TLVs, Length expected */ #define LOCK_CTRL_LEN_IN_TLV 0x03U /* NDEF message TLVs, TYPE identifier */ #define NDEF_TYPE_IN_TLV 0x03U #define MFUL_NULL_TLV 0x00U #define THREE_BYTE_LENGTH_FIELD 0xFFU #define TERMINATOR_TLV 0xFEU #define MIFARE_ULC_SIZE 0xC0U #define MFUL_NIBBLE_SIZE 0x04U #define MFUL_NIBBLE_MASK 0x0FU #define MFUL_BYTE_SIZE_IN_BITS 0x08U #define MFUL_BLOCK_SIZE_IN_BYTES 0x04U /* Initial (0 to 3 blocks) 4 blocks are ignored, i.e., 16 bytes */ #define MFUL_INITIAL_BYTES_IGNORED 0x10U #define MFUL_CONVERT_BITS_TO_BYTES(bits_to_bytes) \ (((bits_to_bytes % MFUL_BYTE_SIZE_IN_BITS) > 0) ? \ ((bits_to_bytes / MFUL_BYTE_SIZE_IN_BITS) + 1) : \ (bits_to_bytes / MFUL_BYTE_SIZE_IN_BITS)) typedef enum phFriNfc_MfUL_Parse { LOCK_TLV_T, LOCK_TLV_L, LOCK_TLV_V, NDEF_TLV_T, NDEF_TLV_L, NDEF_TLV_V }phFriNfc_MfUL_Parse_t; #endif /* #ifdef PH_NDEF_MIFARE_ULC */ #endif /* #ifdef FRINFC_READONLY_NDEF */ /*! * \brief \copydoc page_ovr Helper function for Mifare UL. This function calls the * transceive function */ static NFCSTATUS phFriNfc_MfUL_H_Transceive(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); /*! * \brief \copydoc page_ovr Helper function for Mifare UL. This function calls the * read or write operation */ static NFCSTATUS phFriNfc_MfUL_H_WrRd(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); /*! * \brief \copydoc page_ovr Helper function for Mifare UL. This function fills the * send buffer for transceive function */ static void phFriNfc_MfUL_H_fillSendBuf(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt, uint8_t BlockNo); /*! * \brief \copydoc page_ovr Helper function for Mifare UL. This function shall process * the read bytes */ static NFCSTATUS phFriNfc_MfUL_H_ProRd16Bytes(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); /*! * \brief \copydoc page_ovr Helper function for Mifare UL. This function shall process the * OTP bytes written */ static NFCSTATUS phFriNfc_MfUL_H_ProWrOTPBytes(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); #ifdef FRINFC_READONLY_NDEF #ifdef PH_NDEF_MIFARE_ULC static NFCSTATUS phFriNfc_MfUL_ParseTLVs ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt, uint8_t *data_to_parse, uint8_t size_to_parse); static NFCSTATUS phFriNfc_MfUL_GetLockBytesInfo ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); static NFCSTATUS phFriNfc_MfUL_GetDefaultLockBytesInfo ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); static uint8_t phFriNfc_MfUL_GetSkipSize ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt, uint8_t block_number, uint8_t byte_number); static NFCSTATUS phFriNfc_MfUL_ReadWriteLockBytes ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); static NFCSTATUS phFriNfc_MfUL_UpdateAndWriteLockBits ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); static uint8_t phFriNfc_MfUL_CalcRemainingLockBits ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt); #endif /* #ifdef PH_NDEF_MIFARE_ULC */ #endif /* #ifdef FRINFC_READONLY_NDEF */ static int MemCompare1 ( void *s1, void *s2, unsigned int n ); /*The function does a comparision of two strings and returns a non zero value if two strings are unequal*/ static int MemCompare1 ( void *s1, void *s2, unsigned int n ) { int8_t diff = 0; int8_t *char_1 =(int8_t *)s1; int8_t *char_2 =(int8_t *)s2; if(NULL == s1 || NULL == s2) { PHDBG_CRITICAL_ERROR("NULL pointer passed to memcompare"); } else { for(;((n>0)&&(diff==0));n--,char_1++,char_2++) { diff = *char_1 - *char_2; } } return (int)diff; } void phFriNfc_MfUL_Reset(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) { uint8_t OTPByte[] = PH_FRINFC_MFUL_FMT_OTP_BYTES; NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_0; (void)memcpy(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, OTPByte, sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes)); #ifdef FRINFC_READONLY_NDEF NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[0] = 0; NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[1] = 0; NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[2] = 0; NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[3] = 0; #endif /* #ifdef FRINFC_READONLY_NDEF */ } NFCSTATUS phFriNfc_MfUL_Format(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) { NFCSTATUS Result = NFCSTATUS_SUCCESS; uint8_t OTPByte[] = PH_FRINFC_MFUL_FMT_OTP_BYTES; NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_0; (void)memcpy(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, OTPByte, sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes)); /* Set the state */ NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RD_16BYTES; /* Initialise current block to the lock bits block */ NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_2; /* Start authentication */ Result = phFriNfc_MfUL_H_WrRd(NdefSmtCrdFmt); return Result; } #ifdef FRINFC_READONLY_NDEF NFCSTATUS phFriNfc_MfUL_ConvertToReadOnly ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) { NFCSTATUS result = NFCSTATUS_SUCCESS; NdefSmtCrdFmt->AddInfo.Type2Info.DefaultLockBytesFlag = TRUE; NdefSmtCrdFmt->AddInfo.Type2Info.ReadDataIndex = 0; NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_RD_16BYTES; result = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt); return result; } #endif /* #ifdef FRINFC_READONLY_NDEF */ void phFriNfc_MfUL_Process(void *Context, NFCSTATUS Status) { phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt = (phFriNfc_sNdefSmtCrdFmt_t *)Context; if(Status == NFCSTATUS_SUCCESS) { switch(NdefSmtCrdFmt->State) { case PH_FRINFC_MFUL_FMT_RD_16BYTES: Status = phFriNfc_MfUL_H_ProRd16Bytes(NdefSmtCrdFmt); break; case PH_FRINFC_MFUL_FMT_WR_OTPBYTES: Status = phFriNfc_MfUL_H_ProWrOTPBytes(NdefSmtCrdFmt); break; case PH_FRINFC_MFUL_FMT_WR_TLV: #ifdef PH_NDEF_MIFARE_ULC if (NdefSmtCrdFmt->CardType == PH_FRINFC_NDEFMAP_MIFARE_ULC_CARD) { /* Write NDEF TLV in block number 5 */ NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_5; /* Card already have the OTP bytes so write TLV */ NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_WR_TLV1; Status = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt); } #endif /* #ifdef PH_NDEF_MIFARE_ULC */ break; #ifdef FRINFC_READONLY_NDEF case PH_FRINFC_MFUL_FMT_RO_RD_16BYTES: { if (MIFARE_UL_READ_MAX_SIZE == *NdefSmtCrdFmt->SendRecvLength) { uint8_t otp_lock_page_size = 0; uint8_t i = 0; otp_lock_page_size = sizeof (NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes); (void)memcpy ((void *)NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes, (void *)NdefSmtCrdFmt->SendRecvBuf, sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes)); NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[2] = (uint8_t) (NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[2] | MIFARE_UL_LOCK_BYTE1_VALUE); NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[3] = MIFARE_UL_LOCK_BYTE2_VALUE; i = (uint8_t)(i + otp_lock_page_size); otp_lock_page_size = sizeof (NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes); (void)memcpy ((void *)NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, (void *)(NdefSmtCrdFmt->SendRecvBuf + i), sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes)); NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes[(otp_lock_page_size - 1)] = READ_ONLY_VALUE_IN_OTP; switch (NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes[TYPE_2_MEM_SIZE_POSITION]) { case TYPE_2_STATIC_MEM_SIZE_VALUE: { NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_WR_OTP_BYTES; Status = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt); break; } #ifdef PH_NDEF_MIFARE_ULC case TYPE_2_DYNAMIC_MEM_SIZE_VALUE: { NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_NDEF_PARSE_RD_BYTES; /* Start reading from block 4 */ NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = 4; Status = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt); break; } #endif /* #ifdef PH_NDEF_MIFARE_ULC */ default: { Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_INVALID_DEVICE_REQUEST); break; } } } else { Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } case PH_FRINFC_MFUL_FMT_RO_WR_OTP_BYTES: { switch (NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes[TYPE_2_MEM_SIZE_POSITION]) { case TYPE_2_STATIC_MEM_SIZE_VALUE: #ifdef PH_NDEF_MIFARE_ULC case TYPE_2_DYNAMIC_MEM_SIZE_VALUE: #endif /* #ifdef PH_NDEF_MIFARE_ULC */ { NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_WR_LOCK_BYTES; Status = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt); break; } default: { Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_INVALID_DEVICE_REQUEST); break; } } break; } #ifdef PH_NDEF_MIFARE_ULC case PH_FRINFC_MFUL_FMT_RO_NDEF_PARSE_RD_BYTES: { if (MIFARE_UL_READ_MAX_SIZE == *NdefSmtCrdFmt->SendRecvLength) { Status = phFriNfc_MfUL_ParseTLVs (NdefSmtCrdFmt, NdefSmtCrdFmt->SendRecvBuf, (uint8_t)*NdefSmtCrdFmt->SendRecvLength); if (!Status) { NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = NdefSmtCrdFmt->AddInfo.Type2Info.LockBlockNumber; Status = phFriNfc_MfUL_ReadWriteLockBytes (NdefSmtCrdFmt); } } else { Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } case PH_FRINFC_MFUL_FMT_RO_RD_DYN_LOCK_BYTES: { if (MIFARE_UL_READ_MAX_SIZE == *NdefSmtCrdFmt->SendRecvLength) { (void)memcpy ((void *)NdefSmtCrdFmt->AddInfo.Type2Info.ReadData, (void *)NdefSmtCrdFmt->SendRecvBuf, sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.ReadData)); NdefSmtCrdFmt->AddInfo.Type2Info.ReadDataIndex = 0; Status = phFriNfc_MfUL_UpdateAndWriteLockBits (NdefSmtCrdFmt); } else { Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_INVALID_RECEIVE_LENGTH); } break; } case PH_FRINFC_MFUL_FMT_RO_WR_DYN_LOCK_BYTES: { NdefSmtCrdFmt->AddInfo.Type2Info.ReadDataIndex = (uint8_t) (NdefSmtCrdFmt->AddInfo.Type2Info.ReadDataIndex + MFUL_BLOCK_SIZE_IN_BYTES); if (!phFriNfc_MfUL_CalcRemainingLockBits (NdefSmtCrdFmt)) { /* There is no lock bits to write, then write OTP bytes */ NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_WR_OTP_BYTES; Status = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt); } else if ((NdefSmtCrdFmt->AddInfo.Type2Info.ReadDataIndex < MIFARE_UL_READ_MAX_SIZE) && (phFriNfc_MfUL_CalcRemainingLockBits (NdefSmtCrdFmt))) { /* If remaining lock bits has to be written and the data is already read */ Status = phFriNfc_MfUL_UpdateAndWriteLockBits (NdefSmtCrdFmt); } else { /* Increment current block by 4 because if a data is read then 16 bytes will be given which is 4 blocks */ NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = (uint8_t) (NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock + 4); Status = phFriNfc_MfUL_ReadWriteLockBytes (NdefSmtCrdFmt); } break; } #endif /* #ifdef PH_NDEF_MIFARE_ULC */ case PH_FRINFC_MFUL_FMT_RO_WR_LOCK_BYTES: { /* Do nothing */ break; } #endif /* #ifdef FRINFC_READONLY_NDEF */ #ifdef PH_NDEF_MIFARE_ULC case PH_FRINFC_MFUL_FMT_WR_TLV1: break; #endif /* #ifdef PH_NDEF_MIFARE_ULC */ default: Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_INVALID_DEVICE_REQUEST); break; } } /* Status is not success then call completion routine */ if(Status != NFCSTATUS_PENDING) { phFriNfc_SmtCrdFmt_HCrHandler(NdefSmtCrdFmt, Status); } } #ifdef FRINFC_READONLY_NDEF #ifdef PH_NDEF_MIFARE_ULC static uint8_t phFriNfc_MfUL_GetSkipSize ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt, uint8_t block_number, uint8_t byte_number) { uint8_t skip_size = 0; phFriNfc_Type2_AddInfo_t *ps_type2_info = &NdefSmtCrdFmt->AddInfo.Type2Info; /* This check is added, because the default lock bits is always present after the DATA AREA. So, default lock bytes doesnt have any skip size */ if (!ps_type2_info->DefaultLockBytesFlag) { /* Only check for the lock control TLV */ if ((block_number == ps_type2_info->LockBlockNumber) && (byte_number == ps_type2_info->LockByteNumber)) { skip_size = MFUL_CONVERT_BITS_TO_BYTES(ps_type2_info->NoOfLockBits); } } return skip_size; } static NFCSTATUS phFriNfc_MfUL_GetLockBytesInfo ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_Type2_AddInfo_t *ps_type2_info = &(NdefSmtCrdFmt->AddInfo.Type2Info); uint8_t page_address = 0; uint8_t bytes_offset = 0; uint8_t lock_index = 0; page_address = (uint8_t)(ps_type2_info->DynLockBytes[lock_index] >> MFUL_NIBBLE_SIZE); bytes_offset = (uint8_t)(ps_type2_info->DynLockBytes[lock_index] & MFUL_NIBBLE_MASK); lock_index = (lock_index + 1); ps_type2_info->NoOfLockBits = ps_type2_info->DynLockBytes[lock_index]; lock_index = (lock_index + 1); ps_type2_info->LockBytesPerPage = (ps_type2_info->DynLockBytes[lock_index] & MFUL_NIBBLE_MASK); ps_type2_info->BytesLockedPerLockBit = (ps_type2_info->DynLockBytes[lock_index] >> MFUL_NIBBLE_SIZE); /* Apply the formula to calculate byte address ByteAddr = ((PageAddr * (2 ^ BytesPerPage)) + ByteOffset) */ ps_type2_info->LockByteNumber = (uint8_t)((page_address * (1 << ps_type2_info->LockBytesPerPage)) + bytes_offset); ps_type2_info->LockBlockNumber = (uint8_t)(ps_type2_info->LockByteNumber / MFUL_BLOCK_SIZE_IN_BYTES); ps_type2_info->LockByteNumber = (uint8_t)(ps_type2_info->LockByteNumber % MFUL_BLOCK_SIZE_IN_BYTES); #if 0 if ( /* Out of bound memory check */ ((ps_locktlv_info->ByteAddr + ps_locktlv_info->Size) > (uint16_t)(psNdefMap->TopazContainer.CCByteBuf[2] * TOPAZ_BYTES_PER_BLOCK)) || /* Check the static lock and reserved areas memory blocks */ ((ps_locktlv_info->ByteAddr >= TOPAZ_STATIC_LOCK_RES_START) && (ps_locktlv_info->ByteAddr < TOPAZ_STATIC_LOCK_RES_END)) || (((ps_locktlv_info->ByteAddr + ps_locktlv_info->Size - 1) >= TOPAZ_STATIC_LOCK_RES_START) && ((ps_locktlv_info->ByteAddr + ps_locktlv_info->Size - 1) < TOPAZ_STATIC_LOCK_RES_END)) ) { ps_locktlv_info->ByteAddr = 0; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_NO_NDEF_SUPPORT); } else { ps_locktlv_info->BlkNum = (ps_locktlv_info->ByteAddr / TOPAZ_BYTES_PER_BLOCK); ps_locktlv_info->ByteNum = (ps_locktlv_info->ByteAddr % TOPAZ_BYTES_PER_BLOCK); } #endif /* #if 0 */ return result; } static uint8_t phFriNfc_MfUL_CalcRemainingLockBits ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) { uint8_t lock_bits_remaining = 0; phFriNfc_Type2_AddInfo_t *ps_type2_info = &(NdefSmtCrdFmt->AddInfo.Type2Info); lock_bits_remaining = (uint8_t)(ps_type2_info->NoOfLockBits - ps_type2_info->LockBitsWritten); return lock_bits_remaining; } static NFCSTATUS phFriNfc_MfUL_UpdateAndWriteLockBits ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_Type2_AddInfo_t *ps_type2_info = &(NdefSmtCrdFmt->AddInfo.Type2Info); uint8_t byte_index = 0; uint8_t no_of_bits_left_in_block = 0; uint8_t remaining_lock_bits = 0; uint8_t remaining_lock_bytes = 0; /* Array of 3 is used because the lock bits with 4 bytes in a block is handled in the function phFriNfc_MfUL_ReadWriteLockBytes So use this function only if lock bytes doesnt use the entire block */ uint8_t lock_bytes_value[MFUL_BLOCK_SIZE_IN_BYTES] = {0}; uint8_t lock_byte_index = 0; (void)memcpy ((void *)lock_bytes_value, (void*)(ps_type2_info->ReadData + ps_type2_info->ReadDataIndex), sizeof (ps_type2_info->DynLockBytes)); remaining_lock_bits = phFriNfc_MfUL_CalcRemainingLockBits (NdefSmtCrdFmt); if (ps_type2_info->CurrentBlock == ps_type2_info->LockBlockNumber) { /* 1st write to lock bits, so byte_index is updated */ byte_index = ps_type2_info->LockByteNumber; } no_of_bits_left_in_block = (uint8_t)((MFUL_BLOCK_SIZE_IN_BYTES - byte_index) * MFUL_BYTE_SIZE_IN_BITS); if (no_of_bits_left_in_block >= remaining_lock_bits) { /* Entire lock bits can be written if block size is more than number of lock bits. so allocate the lock bits with value 1b and dont change the remaining bits */ if (remaining_lock_bits % MFUL_BYTE_SIZE_IN_BITS) { /* mod operation has resulted in a value, means lock bits ends in between a byte */ uint8_t mod_value = 0; remaining_lock_bytes = ((remaining_lock_bits / MFUL_BYTE_SIZE_IN_BITS) + 1); /* mod_value is used to fill the only partial bits and remaining bits shall be untouched */ mod_value = (uint8_t)(remaining_lock_bits % MFUL_BYTE_SIZE_IN_BITS); if (remaining_lock_bits > MFUL_BYTE_SIZE_IN_BITS) { /* lock bits to write is greater than 8 bits */ while (lock_byte_index < (remaining_lock_bytes - 1)) { /* Set 1b to all bits left in the block */ lock_bytes_value[byte_index] = 0xFF; lock_byte_index = (uint8_t)(lock_byte_index + 1); byte_index = (uint8_t)(byte_index + 1); } /* Last byte of the lock bits shall be filled partially, Set only the remaining lock bits and dont change the other bit value */ lock_bytes_value[byte_index] = 0; lock_bytes_value[byte_index] = (uint8_t) SET_BITS8 (lock_bytes_value[byte_index], 0, mod_value, 1); } else { /* lock bits to write is less than 8 bits, so there is only one byte to write. Set only the remaining lock bits and dont change the other bit value */ lock_bytes_value[0] = (uint8_t)SET_BITS8 (lock_bytes_value[0], 0, mod_value, 1); } } /* if (remaining_lock_bits % MFUL_BYTE_SIZE_IN_BITS) */ else { /* MOD operation is 00, that means entire byte value shall be 0xFF, means every bit shall be to 1 */ remaining_lock_bytes = (remaining_lock_bits / MFUL_BYTE_SIZE_IN_BITS); while (lock_byte_index < remaining_lock_bytes) { /* Set 1b to all bits left in the block */ lock_bytes_value[byte_index] = 0xFF; lock_byte_index = (uint8_t)(lock_byte_index + 1); byte_index = (uint8_t)(byte_index + 1); } } /* else of if (remaining_lock_bits % MFUL_BYTE_SIZE_IN_BITS) */ ps_type2_info->LockBitsWritten = (uint8_t)(ps_type2_info->LockBitsWritten + remaining_lock_bits); } /* if (no_of_bits_left_in_block >= remaining_lock_bits) */ else { /* Update till the left bits in the block and then carry out next operation after this write */ while (lock_byte_index < (no_of_bits_left_in_block / MFUL_BYTE_SIZE_IN_BITS)) { /* Set 1b to all bits left in the block */ lock_bytes_value[byte_index] = 0xFF; lock_byte_index = (uint8_t)(lock_byte_index + 1); byte_index = (uint8_t)(byte_index + 1); } ps_type2_info->LockBitsWritten = (uint8_t)(ps_type2_info->LockBitsWritten + no_of_bits_left_in_block); } /* else of if (no_of_bits_left_in_block >= remaining_lock_bits) */ /* Copy the values back to the DynLockBytes structure member */ (void)memcpy ((void*)ps_type2_info->DynLockBytes, (void *)lock_bytes_value, sizeof (ps_type2_info->DynLockBytes)); NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_WR_DYN_LOCK_BYTES; result = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt); return result; } static NFCSTATUS phFriNfc_MfUL_ReadWriteLockBytes ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_Type2_AddInfo_t *ps_type2_info = &(NdefSmtCrdFmt->AddInfo.Type2Info); uint8_t write_flag = FALSE; if (/* Lock bytes starts from the beginning of the block */ (0 == ps_type2_info->LockByteNumber) /* To make sure this is the first read */ && (ps_type2_info->CurrentBlock == ps_type2_info->LockBlockNumber) /* Lock bytes are greater than or equal to the block size, i.e., 4 bytes */ && (phFriNfc_MfUL_CalcRemainingLockBits (NdefSmtCrdFmt) >= (MFUL_BLOCK_SIZE_IN_BYTES * MFUL_BYTE_SIZE_IN_BITS))) { /* Then directly write the lock bytes, dont waste time for read */ (void)memset ((void *)ps_type2_info->DynLockBytes, 0xFF, sizeof (ps_type2_info->DynLockBytes)); write_flag = TRUE; } else if (ps_type2_info->CurrentBlock == ps_type2_info->LockBlockNumber) { /* Read is mandatory, First read and then update the block, because chances are there that lock byte may start in between the block */ } else if (/* check if remaining bytes exceeds or same as the block size */ (phFriNfc_MfUL_CalcRemainingLockBits (NdefSmtCrdFmt) >= (MFUL_BLOCK_SIZE_IN_BYTES * MFUL_BYTE_SIZE_IN_BITS))) { /* Then directly write the lock bytes, dont waste time for read */ (void)memset ((void *)ps_type2_info->DynLockBytes, 0xFF, sizeof (ps_type2_info->DynLockBytes)); write_flag = TRUE; } else { /* Read is mandatory, First read and then update the block */ } if (write_flag) { NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_WR_DYN_LOCK_BYTES; result = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt); } else { NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_RD_DYN_LOCK_BYTES; result = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt); } return result; } static NFCSTATUS phFriNfc_MfUL_GetDefaultLockBytesInfo ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) { NFCSTATUS result = NFCSTATUS_SUCCESS; phFriNfc_Type2_AddInfo_t *ps_type2_info = &(NdefSmtCrdFmt->AddInfo.Type2Info); uint16_t lock_byte_start_addr = 0; /* The position of the dynamic lock bits starts from the first byte after the data area */ lock_byte_start_addr = (uint16_t)(MFUL_INITIAL_BYTES_IGNORED + (ps_type2_info->OTPBytes[TYPE_2_MEM_SIZE_POSITION] * 8)); ps_type2_info->LockBlockNumber = (uint8_t)(lock_byte_start_addr / MFUL_BLOCK_SIZE_IN_BYTES); ps_type2_info->LockByteNumber = (uint8_t)(lock_byte_start_addr % MFUL_BLOCK_SIZE_IN_BYTES); /* Default settings NoOfLockBits = [(DataAreaSize - 48)/8] */ ps_type2_info->NoOfLockBits = (uint8_t) (((ps_type2_info->OTPBytes[TYPE_2_MEM_SIZE_POSITION] * 8) - 48)/8); return result; } static NFCSTATUS phFriNfc_MfUL_ParseTLVs ( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt, uint8_t *data_to_parse, uint8_t size_to_parse) { NFCSTATUS result = NFCSTATUS_SUCCESS; static uint8_t lock_mem_ndef_index = 0; static uint8_t skip_lock_mem_size = 0; static uint16_t card_size_remaining = 0; static uint16_t ndef_data_size = 0; static phFriNfc_MfUL_Parse_t parse_tlv = LOCK_TLV_T; uint8_t parse_index = 0; if ((0 == card_size_remaining) && (0 == parse_index)) { /* card size is calculated only once */ card_size_remaining = (uint16_t) (NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes[TYPE_2_MEM_SIZE_POSITION] * 8); } while ((parse_index < size_to_parse) && (NFCSTATUS_SUCCESS == result) && (NDEF_TLV_V != parse_tlv) && (0 != card_size_remaining)) { if (0 == skip_lock_mem_size) { /* Skip the lock TLVs, so get the lock bits */ skip_lock_mem_size = phFriNfc_MfUL_GetSkipSize (NdefSmtCrdFmt, NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock, parse_index); } if (0 != skip_lock_mem_size) { if (skip_lock_mem_size >= (size_to_parse - parse_index)) { /* if skip size is more than the size to parse, then */ card_size_remaining = (uint16_t)(card_size_remaining - (size_to_parse - parse_index)); skip_lock_mem_size = (uint8_t)(skip_lock_mem_size - ((size_to_parse - parse_index))); parse_index = size_to_parse; } else { card_size_remaining = (uint16_t)(card_size_remaining - skip_lock_mem_size); parse_index = (uint8_t)(parse_index + skip_lock_mem_size); skip_lock_mem_size = 0; } } else { switch (parse_tlv) { case LOCK_TLV_T: { switch (*(data_to_parse + parse_index)) { case MFUL_NULL_TLV: { /* Do nothing, parse further */ break; } case LOCK_CTRL_TYPE_IN_TLV: { parse_tlv = LOCK_TLV_L; break; } case NDEF_TYPE_IN_TLV: { parse_tlv = NDEF_TLV_L; /* Default lock bytes shall be taken */ NdefSmtCrdFmt->AddInfo.Type2Info.DefaultLockBytesFlag = TRUE; result = phFriNfc_MfUL_GetDefaultLockBytesInfo (NdefSmtCrdFmt); break; } default: { parse_tlv = LOCK_TLV_T; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_NO_NDEF_SUPPORT); break; } } break; } case LOCK_TLV_L: { if (LOCK_CTRL_LEN_IN_TLV == *(data_to_parse + parse_index)) { parse_tlv = LOCK_TLV_V; } else { skip_lock_mem_size = 0; parse_tlv = LOCK_TLV_T; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_NO_NDEF_SUPPORT); } break; } case LOCK_TLV_V: { switch (lock_mem_ndef_index) { case 0: case 1: { NdefSmtCrdFmt->AddInfo.Type2Info.DefaultLockBytesFlag = FALSE; NdefSmtCrdFmt->AddInfo.Type2Info.DynLockBytes[lock_mem_ndef_index] = *(data_to_parse + parse_index); lock_mem_ndef_index = (uint8_t)(lock_mem_ndef_index + 1); break; } case 2: { NdefSmtCrdFmt->AddInfo.Type2Info.DynLockBytes[lock_mem_ndef_index] = *(data_to_parse + parse_index); parse_tlv = NDEF_TLV_T; lock_mem_ndef_index = 0; result = phFriNfc_MfUL_GetLockBytesInfo (NdefSmtCrdFmt); break; } default: { skip_lock_mem_size = 0; parse_tlv = LOCK_TLV_T; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_NO_NDEF_SUPPORT); break; } } break; } /* switch (lock_mem_ndef_index) in case LOCK_TLV_V */ case NDEF_TLV_T: { switch (*(data_to_parse + parse_index)) { case MFUL_NULL_TLV: { /* Do nothing, parse further */ break; } case NDEF_TYPE_IN_TLV: { parse_tlv = NDEF_TLV_L; break; } default: { skip_lock_mem_size = 0; parse_tlv = LOCK_TLV_T; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_NO_NDEF_SUPPORT); break; } } break; } /* switch (*(data_to_parse + parse_index)) in case NDEF_TLV_T */ case NDEF_TLV_L: { switch (lock_mem_ndef_index) { case 0: { if (THREE_BYTE_LENGTH_FIELD == *(data_to_parse + parse_index)) { lock_mem_ndef_index = (uint8_t)(lock_mem_ndef_index + 1); } else { ndef_data_size = *(data_to_parse + parse_index); parse_tlv = NDEF_TLV_V; lock_mem_ndef_index = 0; } break; } case 1: { ndef_data_size = (uint16_t)(*(data_to_parse + parse_index) << 8); break; } case 2: { ndef_data_size = (uint16_t)(ndef_data_size | *(data_to_parse + parse_index)); parse_tlv = NDEF_TLV_V; lock_mem_ndef_index = 0; break; } } /* switch (lock_mem_ndef_index) in case NDEF_TLV_L */ break; } case NDEF_TLV_V: { break; } default: { skip_lock_mem_size = 0; parse_tlv = LOCK_TLV_T; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_NO_NDEF_SUPPORT); break; } } /* switch (parse_tlv) */ } /* else part of if (0 != skip_lock_mem_size) */ if (0 == card_size_remaining) { skip_lock_mem_size = 0; parse_tlv = LOCK_TLV_T; result = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_NO_NDEF_SUPPORT); } else if (NDEF_TLV_V != parse_tlv) { /* Increment the index */ parse_index = (uint8_t)(parse_index + 1); /* card size is decremented as the memory area is parsed */ card_size_remaining = (uint16_t)(card_size_remaining - 1); } else { /* L field of the NDEF TLV L field can have 1 byte or also 3 bytes */ uint8_t length_to_deduct = 1; if ((NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes[TYPE_2_MEM_SIZE_POSITION] * 8) >= THREE_BYTE_LENGTH_FIELD) { length_to_deduct = 3; } /* parse_tlv has reached the VALUE field of the NDEF TLV */ if ((card_size_remaining - length_to_deduct) < ndef_data_size) { result = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_NO_NDEF_SUPPORT); } lock_mem_ndef_index = 0; skip_lock_mem_size = 0; card_size_remaining = 0; } } /* while ((parse_index < size_to_parse) && (NFCSTATUS_SUCCESS != result) && (NDEF_TLV_V != parse_tlv) && (0 != card_size_remaining)) */ if ((NDEF_TLV_V == parse_tlv) || (NFCSTATUS_SUCCESS != result)) { parse_tlv = LOCK_TLV_T; } else { NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_NDEF_PARSE_RD_BYTES; NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = (NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock + 4); result = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt); } if (NFCSTATUS_PENDING != result) { lock_mem_ndef_index = 0; skip_lock_mem_size = 0; card_size_remaining = 0; } return result; } #endif /* #ifdef PH_NDEF_MIFARE_ULC */ #endif /* #ifdef FRINFC_READONLY_NDEF */ static NFCSTATUS phFriNfc_MfUL_H_WrRd( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt ) { NFCSTATUS Result = NFCSTATUS_SUCCESS; /* Fill the send buffer */ phFriNfc_MfUL_H_fillSendBuf(NdefSmtCrdFmt, NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock); /* Call transceive */ Result = phFriNfc_MfUL_H_Transceive (NdefSmtCrdFmt); return Result; } static NFCSTATUS phFriNfc_MfUL_H_Transceive(phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt) { NFCSTATUS Result = NFCSTATUS_SUCCESS; /* set the data for additional data exchange*/ NdefSmtCrdFmt->psDepAdditionalInfo.DepFlags.MetaChaining = 0; NdefSmtCrdFmt->psDepAdditionalInfo.DepFlags.NADPresent = 0; NdefSmtCrdFmt->psDepAdditionalInfo.NAD = 0; /*set the completion routines for the card operations*/ NdefSmtCrdFmt->SmtCrdFmtCompletionInfo.CompletionRoutine = phFriNfc_NdefSmtCrd_Process; NdefSmtCrdFmt->SmtCrdFmtCompletionInfo.Context = NdefSmtCrdFmt; *NdefSmtCrdFmt->SendRecvLength = PH_FRINFC_SMTCRDFMT_MAX_SEND_RECV_BUF_SIZE; /* Call the Overlapped HAL Transceive function */ Result = phFriNfc_OvrHal_Transceive( NdefSmtCrdFmt->LowerDevice, &NdefSmtCrdFmt->SmtCrdFmtCompletionInfo, NdefSmtCrdFmt->psRemoteDevInfo, NdefSmtCrdFmt->Cmd, &NdefSmtCrdFmt->psDepAdditionalInfo, NdefSmtCrdFmt->SendRecvBuf, NdefSmtCrdFmt->SendLength, NdefSmtCrdFmt->SendRecvBuf, NdefSmtCrdFmt->SendRecvLength); return Result; } static void phFriNfc_MfUL_H_fillSendBuf( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt, uint8_t BlockNo) { #ifdef PH_NDEF_MIFARE_ULC uint8_t NDEFTLV1[4] = {0x01, 0x03, 0xA0, 0x10}; uint8_t NDEFTLV2[4] = {0x44, 0x03, 0x00, 0xFE}; #endif /* #ifdef PH_NDEF_MIFARE_ULC */ uint8_t NDEFTLV[4] = {0x03, 0x00, 0xFE, 0x00}; /* First byte for send buffer is always the block number */ NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_0] = (uint8_t)BlockNo; switch(NdefSmtCrdFmt->State) { #ifdef FRINFC_READONLY_NDEF case PH_FRINFC_MFUL_FMT_RO_RD_16BYTES: { #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareRead; #else /* Read command */ NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareRead; #endif /* #ifdef PH_HAL4_ENABLE */ *NdefSmtCrdFmt->SendRecvBuf = RD_LOCK_OTP_BLOCK_NUMBER; /* Send length for read command is always one */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_1; break; } #ifdef PH_NDEF_MIFARE_ULC case PH_FRINFC_MFUL_FMT_RO_NDEF_PARSE_RD_BYTES: { #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareRead; #else /* Read command */ NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareRead; #endif /* #ifdef PH_HAL4_ENABLE */ *NdefSmtCrdFmt->SendRecvBuf = NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock; /* Send length for read command is always one */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_1; break; } case PH_FRINFC_MFUL_FMT_RO_RD_DYN_LOCK_BYTES: { #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareRead; #else /* Read command */ NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareRead; #endif /* #ifdef PH_HAL4_ENABLE */ *NdefSmtCrdFmt->SendRecvBuf = NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock; /* Send length for read command is always one */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_1; break; } case PH_FRINFC_MFUL_FMT_RO_WR_DYN_LOCK_BYTES: { #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite4; #else /* Write command */ NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareWrite4; #endif /* #ifdef PH_HAL4_ENABLE */ /* Send length for read command is always one */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_5; *NdefSmtCrdFmt->SendRecvBuf = NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock; (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NdefSmtCrdFmt->AddInfo.Type2Info.DynLockBytes, PH_FRINFC_MFUL_FMT_VAL_4); break; } #endif /* #ifdef PH_NDEF_MIFARE_ULC */ case PH_FRINFC_MFUL_FMT_RO_WR_LOCK_BYTES: { #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite4; #else /* Read command */ NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareWrite4; #endif /* #ifdef PH_HAL4_ENABLE */ /* Send length for read command is always one */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_5; *NdefSmtCrdFmt->SendRecvBuf = RD_LOCK_OTP_BLOCK_NUMBER; (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes, PH_FRINFC_MFUL_FMT_VAL_4); break; } case PH_FRINFC_MFUL_FMT_RO_WR_OTP_BYTES: { #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite4; #else /* Read command */ NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareWrite4; #endif /* #ifdef PH_HAL4_ENABLE */ /* Send length for read command is always one */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_5; *NdefSmtCrdFmt->SendRecvBuf = OTP_BLOCK_NUMBER; (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, PH_FRINFC_MFUL_FMT_VAL_4); break; } #endif /* #ifdef FRINFC_READONLY_NDEF */ case PH_FRINFC_MFUL_FMT_RD_16BYTES: #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareRead; #else /* Read command */ NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareRead; #endif /* #ifdef PH_HAL4_ENABLE */ /* Send length for read command is always one */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_1; break; case PH_FRINFC_MFUL_FMT_WR_OTPBYTES: /* Send length for read command is always Five */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_5; /* Write command */ #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite4; #else NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareWrite4; #endif /* #ifdef PH_HAL4_ENABLE */ /* Copy the OTP bytes */ (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, PH_FRINFC_MFUL_FMT_VAL_4); break; case PH_FRINFC_MFUL_FMT_WR_TLV: #ifndef PH_NDEF_MIFARE_ULC default: #endif /* #ifndef PH_NDEF_MIFARE_ULC */ /* Send length for read command is always Five */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_5; /* Write command */ #ifdef PH_HAL4_ENABLE NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite4; #else NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareCmdListMifareWrite4; #endif /* #ifdef PH_HAL4_ENABLE */ /* Copy the NDEF TLV */ #ifdef PH_NDEF_MIFARE_ULC if (NdefSmtCrdFmt->CardType == PH_FRINFC_NDEFMAP_MIFARE_ULC_CARD) { (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NDEFTLV1, PH_FRINFC_MFUL_FMT_VAL_4); } else if (NdefSmtCrdFmt->CardType == PH_FRINFC_NDEFMAP_MIFARE_UL_CARD) { (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NDEFTLV, PH_FRINFC_MFUL_FMT_VAL_4); } else { } #else (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NDEFTLV, PH_FRINFC_MFUL_FMT_VAL_4); #endif /* #ifdef PH_NDEF_MIFARE_ULC */ break; #ifdef PH_NDEF_MIFARE_ULC case PH_FRINFC_MFUL_FMT_WR_TLV1: if (NdefSmtCrdFmt->CardType == PH_FRINFC_NDEFMAP_MIFARE_ULC_CARD) { /* Send length for write command is always Five */ NdefSmtCrdFmt->SendLength = PH_FRINFC_MFUL_FMT_VAL_5; /* Write command */ NdefSmtCrdFmt->Cmd.MfCmd = phHal_eMifareWrite4; (void)memcpy(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_1], NDEFTLV2, PH_FRINFC_MFUL_FMT_VAL_4); } break; default: break; #endif /* #ifdef PH_NDEF_MIFARE_ULC */ } } static NFCSTATUS phFriNfc_MfUL_H_ProRd16Bytes( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt ) { NFCSTATUS Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_SMTCRDFMT, NFCSTATUS_FORMAT_ERROR); uint32_t memcompare = PH_FRINFC_MFUL_FMT_VAL_0; uint8_t ZeroBuf[] = {0x00, 0x00, 0x00, 0x00}; #ifdef PH_NDEF_MIFARE_ULC uint8_t OTPByteUL[] = PH_FRINFC_MFUL_FMT_OTP_BYTES; uint8_t OTPByteULC[] = PH_FRINFC_MFULC_FMT_OTP_BYTES; #endif /* #ifdef PH_NDEF_MIFARE_ULC */ /* Check the lock bits (byte number 2 and 3 of block number 2) */ if ((NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_2] == PH_FRINFC_MFUL_FMT_LOCK_BITS_VAL) && (NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_3] == PH_FRINFC_MFUL_FMT_LOCK_BITS_VAL)) { #ifdef PH_NDEF_MIFARE_ULC if (NdefSmtCrdFmt->SendRecvBuf[8] == 0x02 && NdefSmtCrdFmt->SendRecvBuf[9] == 0x00) { NdefSmtCrdFmt->CardType = PH_FRINFC_NDEFMAP_MIFARE_ULC_CARD; (void)memcpy(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, OTPByteULC, sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes)); } else if (NdefSmtCrdFmt->SendRecvBuf[8] == 0xFF && NdefSmtCrdFmt->SendRecvBuf[9] == 0xFF) { NdefSmtCrdFmt->CardType = PH_FRINFC_NDEFMAP_MIFARE_UL_CARD; (void)memcpy(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, OTPByteUL, sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes)); } else { NdefSmtCrdFmt->CardType = PH_FRINFC_NDEFMAP_MIFARE_UL_CARD; } #endif /* #ifdef PH_NDEF_MIFARE_ULC */ memcompare = (uint32_t) MemCompare1(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_4], NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes, PH_FRINFC_MFUL_FMT_VAL_4); if (memcompare == PH_FRINFC_MFUL_FMT_VAL_0) { /* Write NDEF TLV in block number 4 */ NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_4; /* Card already have the OTP bytes so write TLV */ NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_WR_TLV; } else { /* IS the card new, OTP bytes = {0x00, 0x00, 0x00, 0x00} */ memcompare = (uint32_t)MemCompare1(&NdefSmtCrdFmt->SendRecvBuf[PH_FRINFC_MFUL_FMT_VAL_4], ZeroBuf, PH_FRINFC_MFUL_FMT_VAL_4); /* If OTP bytes are Zero then the card is Zero */ if (memcompare == PH_FRINFC_MFUL_FMT_VAL_0) { /* Write OTP bytes in block number 3 */ NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_3; /* Card already have the OTP bytes so write TLV */ NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_WR_OTPBYTES; } } } #ifdef PH_NDEF_MIFARE_ULC if( ((NdefSmtCrdFmt->State == PH_FRINFC_MFUL_FMT_WR_TLV) || (NdefSmtCrdFmt->State == PH_FRINFC_MFUL_FMT_WR_OTPBYTES)) && ((NdefSmtCrdFmt->CardType == PH_FRINFC_NDEFMAP_MIFARE_ULC_CARD) || (NdefSmtCrdFmt->CardType == PH_FRINFC_NDEFMAP_MIFARE_UL_CARD)) ) #else if((NdefSmtCrdFmt->State == PH_FRINFC_MFUL_FMT_WR_TLV) || (NdefSmtCrdFmt->State == PH_FRINFC_MFUL_FMT_WR_OTPBYTES)) #endif /* #ifdef PH_NDEF_MIFARE_ULC */ { Result = phFriNfc_MfUL_H_WrRd(NdefSmtCrdFmt); } return Result; } static NFCSTATUS phFriNfc_MfUL_H_ProWrOTPBytes( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt ) { NFCSTATUS Result = NFCSTATUS_SUCCESS; /* Card already have the OTP bytes so write TLV */ NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_WR_TLV; /* Write NDEF TLV in block number 4 */ NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock = PH_FRINFC_MFUL_FMT_VAL_4; Result = phFriNfc_MfUL_H_WrRd(NdefSmtCrdFmt); return Result; }