/* * Copyright (c), NXP Semiconductors Gratkorn / Austria * * (C)NXP Semiconductors * All rights are reserved. Reproduction in whole or in part is * prohibited without the written consent of the copyright owner. * NXP reserves the right to make changes without notice at any time. * NXP makes no warranty, expressed, implied or statutory, including but * not limited to any implied warranty of merchantability or fitness for any *particular purpose, or that the use will not infringe any third party patent, * copyright or trademark. NXP must not be liable for any loss or damage * arising from its use. */ /** \file * Generic MIFARE Plus contactless IC Application Component of Reader Library Framework. * $Author$ * $Revision$ (v07.10.00) * $Date$ * * History: * CHu: Generated 31. July 2009 * */ #include #include #include #include "phalMfp_Int.h" #include #ifdef NXPBUILD__PHAL_MFP phStatus_t phalMfp_Int_ComputeErrorResponse( uint16_t wNumBytesReceived, uint8_t bStatus, uint8_t bLayer4Comm ) { phStatus_t PH_MEMLOC_REM status; /* Invalid error response */ if (wNumBytesReceived == 0U) { return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFP); } /* validate received response */ if (wNumBytesReceived == 1U) { if (0U != (bLayer4Comm)) { switch (bStatus) { case PHAL_MFP_RESP_ACK_ISO4: status = PH_ERR_SUCCESS; break; case PHAL_MFP_RESP_ERR_AUTH: status = PHAL_MFP_ERR_AUTH; break; case PHAL_MFP_RESP_ERR_CMD_OVERFLOW: status = PHAL_MFP_ERR_CMD_OVERFLOW; break; case PHAL_MFP_RESP_ERR_MAC_PCD: status = PHAL_MFP_ERR_MAC_PCD; break; case PHAL_MFP_RESP_ERR_BNR: status = PHAL_MFP_ERR_BNR; break; case PHAL_MFP_RESP_ERR_CMD_INVALID: status = PHAL_MFP_ERR_CMD_INVALID; break; case PHAL_MFP_RESP_ERR_FORMAT: status = PHAL_MFP_ERR_FORMAT; break; case PHAL_MFP_RESP_ERR_GEN_FAILURE: status = PHAL_MFP_ERR_GEN_FAILURE; break; case PHAL_MFP_RESP_ERR_EXT: status = PHAL_MFP_ERR_EXT; break; default: status = PH_ERR_PROTOCOL_ERROR; break; } return PH_ADD_COMPCODE(status, PH_COMP_AL_MFP); }else { switch(bStatus) { case PHAL_MFP_RESP_ACK_ISO3: case PHAL_MFP_RESP_ACK_ISO4: status = PH_ERR_SUCCESS; break; /* Mapping of NAK codes: */ case PHAL_MFP_RESP_NACK0: status = PHPAL_MIFARE_ERR_NAK0; break; case PHAL_MFP_RESP_NACK1: status = PHPAL_MIFARE_ERR_NAK1; break; case PHAL_MFP_RESP_NACK4: status = PHPAL_MIFARE_ERR_NAK4; break; case PHAL_MFP_RESP_NACK5: status = PHPAL_MIFARE_ERR_NAK5; break; default: status = PH_ERR_PROTOCOL_ERROR; break; } return PH_ADD_COMPCODE(status, PH_COMP_PAL_MIFARE); /* For compatibility reasons with SW stack we use here PAL MIFARE product */ } } /* validate received response with wNumBytesReceived > 1 */ if (bStatus != PHAL_MFP_RESP_ACK_ISO4) { return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFP); } /* proper error response */ return PH_ERR_SUCCESS; } phStatus_t phalMfp_Int_WritePerso( void * pPalMifareDataParams, uint8_t bLayer4Comm, uint16_t wBlockNr, uint8_t * pValue ) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aCmd[3]; uint8_t * PH_MEMLOC_REM pResponse = NULL; uint16_t PH_MEMLOC_REM wRxLength = 0; /* parameter checking */ if (pValue == NULL) { return PH_ADD_COMPCODE_FIXED(PH_ERR_INVALID_PARAMETER, PH_COMP_AL_MFP); } /* command frame */ aCmd[0] = PHAL_MFP_CMD_WRITEPERSO; aCmd[1] = (uint8_t)(wBlockNr & 0xFFU); /* LSB */ aCmd[2] = (uint8_t)(wBlockNr >> 8U); /* MSB */ /* exchange command/response */ if (0U != (bLayer4Comm)) { /* command header */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, aCmd, 3, &pResponse, &wRxLength)); /* command exchange */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, pValue, PHAL_MFP_MIFARE_BLOCK_SIZE, &pResponse, &wRxLength)); } else { /* command header */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL3( pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, aCmd, 3, &pResponse, &wRxLength)); /* command exchange */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL3( pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, pValue, PHAL_MFP_MIFARE_BLOCK_SIZE, &pResponse, &wRxLength)); } /* check response */ if (wRxLength == 1U) { PH_CHECK_SUCCESS_FCT(statusTmp, phalMfp_Int_ComputeErrorResponse(wRxLength, pResponse[0], bLayer4Comm)); } else { return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFP); } return PH_ERR_SUCCESS; } phStatus_t phalMfp_Int_CommitPerso( void * pPalMifareDataParams, uint8_t bLayer4Comm ) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aCmd[1]; uint8_t * PH_MEMLOC_REM pResponse = NULL; uint16_t PH_MEMLOC_REM wRxLength = 0; /* command code */ aCmd[0] = PHAL_MFP_CMD_COMMITPERSO; /* exchange command/response */ if (0U != (bLayer4Comm)) { /* command exchange */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pPalMifareDataParams, PH_EXCHANGE_DEFAULT, aCmd, 1, &pResponse, &wRxLength)); } else { /* command exchange */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL3( pPalMifareDataParams, PH_EXCHANGE_DEFAULT, aCmd, 1, &pResponse, &wRxLength)); } /* check response */ if (wRxLength == 1U) { PH_CHECK_SUCCESS_FCT(statusTmp, phalMfp_Int_ComputeErrorResponse(wRxLength, pResponse[0], bLayer4Comm)); } else { return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFP); } return PH_ERR_SUCCESS; } phStatus_t phalMfp_Int_ResetAuth(void * pPalMifareDataParams) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aCmd[1 /* command code */]; uint8_t * PH_MEMLOC_REM pResponse = NULL; uint16_t PH_MEMLOC_REM wRxLength = 0; /* command code */ aCmd[0] = PHAL_MFP_CMD_RAUTH; /* command exchange */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pPalMifareDataParams, PH_EXCHANGE_DEFAULT, aCmd, 1, &pResponse, &wRxLength)); /* check response */ PH_CHECK_SUCCESS_FCT(statusTmp, phalMfp_Int_ComputeErrorResponse(wRxLength, pResponse[0], 1)); return PH_ERR_SUCCESS; } phStatus_t phalMfp_Int_PrepareProximityCheck( void * pPalMifareDataParams ) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aCmd[1]; uint8_t * PH_MEMLOC_REM pResponse = NULL; uint16_t PH_MEMLOC_REM wRxLength = 0; /* command code */ aCmd[0] = PHAL_MFP_CMD_PPC; /* command exchange */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pPalMifareDataParams, PH_EXCHANGE_DEFAULT, aCmd, 1, &pResponse, &wRxLength)); /* check response */ if (wRxLength == 1U) { PH_CHECK_SUCCESS_FCT(statusTmp, phalMfp_Int_ComputeErrorResponse(wRxLength, pResponse[0], 1)); } else { return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFP); } return PH_ERR_SUCCESS; } phStatus_t phalMfp_Int_ProximityCheck( void * pPalMifareDataParams, uint8_t bNumSteps, uint8_t * pRndC, uint8_t * pRndRC ) { phStatus_t PH_MEMLOC_REM statusTmp = 0; uint8_t PH_MEMLOC_REM aCmd[1 /* command code */ + 1 /* length */ + 7 /* max RndC length */]; uint8_t * PH_MEMLOC_REM pResponse = NULL; uint16_t PH_MEMLOC_REM wRxLength = 0; uint8_t PH_MEMLOC_REM bPayloadLen; uint8_t PH_MEMLOC_REM bRndCLen = 0; uint8_t PH_MEMLOC_REM bRndRCLen = 0; phStatus_t PH_MEMLOC_REM status = PH_ERR_SUCCESS; /* parameter checking */ if ((bNumSteps == 0U) || (bNumSteps > PHAL_MFP_PC_RND_LEN) || (pRndC == NULL) || (pRndRC == NULL)) { return PH_ADD_COMPCODE_FIXED(PH_ERR_INVALID_PARAMETER, PH_COMP_AL_MFP); } /*Enabling Min FDT for PC*/ PH_CHECK_SUCCESS_FCT(status, phpalMifare_SetMinFdtPc(pPalMifareDataParams, 1)); /* command code */ aCmd[0] = PHAL_MFP_CMD_PC; /* Proximity Check loop */ while (0U != (bNumSteps--)) { /* RndC length */ if (0U != (bNumSteps)) { bPayloadLen = 1; } else { bPayloadLen = PHAL_MFP_PC_RND_LEN - bRndCLen; } /* Length */ aCmd[1] = bPayloadLen; /* RndC */ (void)memcpy(&aCmd[2], &pRndC[bRndCLen], bPayloadLen); /* command exchange */ statusTmp = phpalMifare_ExchangePc( pPalMifareDataParams, PH_EXCHANGE_DEFAULT, aCmd, 2u + bPayloadLen, &pResponse, &wRxLength); if (statusTmp == PH_ERR_SUCCESS) { /* check response */ if (wRxLength == (uint16_t)bPayloadLen) { /* copy RndR */ (void)memcpy(&pRndRC[bRndRCLen], pResponse, wRxLength); bRndRCLen = bRndRCLen + (uint8_t)wRxLength; /* copy RndC */ (void)memcpy(&pRndRC[bRndRCLen], &pRndC[bRndCLen], wRxLength); bRndRCLen = bRndRCLen + (uint8_t)wRxLength; bRndCLen = bRndCLen + (uint8_t)wRxLength; } else { statusTmp = phalMfp_Int_ComputeErrorResponse(wRxLength, pResponse[0], 1); } } } /*Disabling Min FDT for PC*/ PH_CHECK_SUCCESS_FCT(status, phpalMifare_SetMinFdtPc(pPalMifareDataParams, 0)); PH_CHECK_SUCCESS(statusTmp); /* We expect to have exactly 7 bytes RndR + 7 bytes RndC */ if (bRndRCLen != (PHAL_MFP_PC_RND_LEN * 2U)) { return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFP); } return PH_ERR_SUCCESS; } phStatus_t phalMfp_Int_MultiBlockRead( void * pPalMifareDataParams, uint8_t bBlockNr, uint8_t bNumBlocks, uint8_t * pBlocks ) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aCmd[1 /* command code */ + 1 /* wBlockNr */ + 1 /* bNumBlocks */]; uint8_t * PH_MEMLOC_REM pResponse = NULL; uint16_t PH_MEMLOC_REM wRxLength = 0; /* parameter checking */ if (pBlocks == NULL) { return PH_ADD_COMPCODE_FIXED(PH_ERR_INVALID_PARAMETER, PH_COMP_AL_MFP); } /* command frame */ aCmd[0] = PHAL_MFP_CMD_MBREAD; aCmd[1] = bBlockNr; aCmd[2] = bNumBlocks; /* command exchange */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL3( pPalMifareDataParams, PH_EXCHANGE_DEFAULT, aCmd, 3, &pResponse, &wRxLength)); /* check response */ if (((wRxLength % PHAL_MFP_MIFARE_BLOCK_SIZE) == 0U) && (wRxLength <= (uint16_t)(3u * PHAL_MFP_MIFARE_BLOCK_SIZE))) { /* pass back read bytes */ (void)memcpy(pBlocks, pResponse, wRxLength); } else { PH_CHECK_SUCCESS_FCT(statusTmp, phalMfp_Int_ComputeErrorResponse(wRxLength, pResponse[0], 0)); } return PH_ERR_SUCCESS; } phStatus_t phalMfp_Int_MultiBlockWrite( void * pPalMifareDataParams, uint8_t bBlockNr, uint8_t bNumBlocks, uint8_t * pBlocks ) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aCmd[1 /* command code */ + 1 /* wBlockNr */ + 1 /* bNumBlocks */]; uint8_t * PH_MEMLOC_REM pResponse = NULL; uint16_t PH_MEMLOC_REM wRxLength = 0; /* parameter checking */ if (pBlocks == NULL) { return PH_ADD_COMPCODE_FIXED(PH_ERR_INVALID_PARAMETER, PH_COMP_AL_MFP); } /* command frame */ aCmd[0] = PHAL_MFP_CMD_MBWRITE; aCmd[1] = bBlockNr; aCmd[2] = bNumBlocks; /* command exchange */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL3( pPalMifareDataParams, PH_EXCHANGE_DEFAULT, aCmd, 3, &pResponse, &wRxLength)); /* command exchange */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL3( pPalMifareDataParams, PH_EXCHANGE_DEFAULT, pBlocks, (uint16_t)(bNumBlocks * PHAL_MFP_MIFARE_BLOCK_SIZE), &pResponse, &wRxLength)); return PH_ERR_SUCCESS; } phStatus_t phalMfp_Int_CreateValueBlock( uint8_t * pValue, uint8_t bAddrData, uint8_t * pBlock ) { pBlock[0] = (uint8_t)(pValue[0]); pBlock[1] = (uint8_t)(pValue[1]); pBlock[2] = (uint8_t)(pValue[2]); pBlock[3] = (uint8_t)(pValue[3]); pBlock[4] = (uint8_t)(~pBlock[0]); pBlock[5] = (uint8_t)(~pBlock[1]); pBlock[6] = (uint8_t)(~pBlock[2]); pBlock[7] = (uint8_t)(~pBlock[3]); pBlock[8] = (uint8_t)(pBlock[0]); pBlock[9] = (uint8_t)(pBlock[1]); pBlock[10] = (uint8_t)(pBlock[2]); pBlock[11] = (uint8_t)(pBlock[3]); pBlock[12] = (uint8_t)bAddrData; pBlock[13] = (uint8_t)~bAddrData; pBlock[14] = (uint8_t)bAddrData; pBlock[15] = (uint8_t)~bAddrData; return PH_ERR_SUCCESS; } phStatus_t phalMfp_Int_CheckValueBlockFormat( uint8_t * pBlock ) { /* check format of value block */ if ((pBlock[0] != pBlock[8]) || (pBlock[1] != pBlock[9]) || (pBlock[2] != pBlock[10]) || (pBlock[3] != pBlock[11]) || (pBlock[4] != (pBlock[0] ^ 0xFFU)) || (pBlock[5] != (pBlock[1] ^ 0xFFU)) || (pBlock[6] != (pBlock[2] ^ 0xFFU)) || (pBlock[7] != (pBlock[3] ^ 0xFFU)) || (pBlock[12] != pBlock[14]) || (pBlock[13] != pBlock[15]) || (pBlock[12] != (pBlock[13]^ 0xFFU))) { return PH_ADD_COMPCODE_FIXED(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFP); } return PH_ERR_SUCCESS; } #endif /* NXPBUILD__PHAL_MFP */