summaryrefslogtreecommitdiffstats
path: root/src/phFriNfc_MifULFormat.c
diff options
context:
space:
mode:
authorMartijn Coenen <martijn.coenen@nxp.com>2011-01-13 10:49:03 +0100
committerNick Pelly <npelly@google.com>2011-01-18 11:17:30 -0800
commita6243755a9b438bfbfe0be331ece55953f8cf9eb (patch)
tree4797ff8929bca87c03d2a62ca1224f76eb74862e /src/phFriNfc_MifULFormat.c
parent72854a2c28b99f9ab6aa60c906d5b3c1a36b04d7 (diff)
downloadexternal_libnfc-nxp-a6243755a9b438bfbfe0be331ece55953f8cf9eb.zip
external_libnfc-nxp-a6243755a9b438bfbfe0be331ece55953f8cf9eb.tar.gz
external_libnfc-nxp-a6243755a9b438bfbfe0be331ece55953f8cf9eb.tar.bz2
Implement makeReadOnly() for dynamic T1T/T2T.
The NFC Forum Type 1 Tag and Type 2 Tag specification allows for tags with a dynamic memory layout. Support for making tags with the dynamic layout readonly has been added in this patch. Change-Id: I5bc8912d80f448fdea95e1ee21631c0f186ad79a
Diffstat (limited to 'src/phFriNfc_MifULFormat.c')
-rw-r--r--src/phFriNfc_MifULFormat.c925
1 files changed, 915 insertions, 10 deletions
diff --git a/src/phFriNfc_MifULFormat.c b/src/phFriNfc_MifULFormat.c
index 899249d..3821b37 100644
--- a/src/phFriNfc_MifULFormat.c
+++ b/src/phFriNfc_MifULFormat.c
@@ -49,8 +49,61 @@
#define READ_ONLY_VALUE_IN_OTP 0x0FU
/* Mifare UL OTP block number is 3 */
#define MIFARE_UL_READ_MAX_SIZE 16U
- /* Lock byte value */
- #define MIFARE_UL_LOCK_BYTE_VALUE 0xFFU
+ /* 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
@@ -83,6 +136,53 @@ static NFCSTATUS phFriNfc_MfUL_H_ProRd16Bytes(phFriNfc_sNdefSmtCrdFmt_t *NdefSmt
*/
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*/
@@ -149,9 +249,12 @@ phFriNfc_MfUL_ConvertToReadOnly (
{
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);
+ result = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt);
return result;
}
@@ -205,8 +308,10 @@ void phFriNfc_MfUL_Process(void *Context,
(void *)NdefSmtCrdFmt->SendRecvBuf,
sizeof(NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes));
- NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[2] = MIFARE_UL_LOCK_BYTE_VALUE;
- NdefSmtCrdFmt->AddInfo.Type2Info.LockBytes[3] = MIFARE_UL_LOCK_BYTE_VALUE;
+ 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);
@@ -218,18 +323,146 @@ void phFriNfc_MfUL_Process(void *Context,
NdefSmtCrdFmt->AddInfo.Type2Info.OTPBytes[(otp_lock_page_size - 1)] =
READ_ONLY_VALUE_IN_OTP;
- NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_WR_OTP_BYTES;
- Status = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt);
+ 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:
{
- NdefSmtCrdFmt->State = PH_FRINFC_MFUL_FMT_RO_WR_LOCK_BYTES;
- Status = phFriNfc_MfUL_H_WrRd (NdefSmtCrdFmt);
+ 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 */
@@ -257,6 +490,627 @@ void phFriNfc_MfUL_Process(void *Context,
}
}
+#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_T;
+ /* 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;
@@ -266,7 +1120,7 @@ static NFCSTATUS phFriNfc_MfUL_H_WrRd( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFmt
NdefSmtCrdFmt->AddInfo.Type2Info.CurrentBlock);
/* Call transceive */
- Result = phFriNfc_MfUL_H_Transceive(NdefSmtCrdFmt);
+ Result = phFriNfc_MfUL_H_Transceive (NdefSmtCrdFmt);
return Result;
}
@@ -331,6 +1185,57 @@ static void phFriNfc_MfUL_H_fillSendBuf( phFriNfc_sNdefSmtCrdFmt_t *NdefSmtCrdFm
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