| /* |
| * 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_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; |
| |
| /* 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; |
| } |
| |