From 39c251c7d508f89d0ae9f94680d9a27dc406141f Mon Sep 17 00:00:00 2001 From: Federico Cerutti Date: Fri, 28 Dec 2018 13:42:17 +0100 Subject: [PATCH] Fixed Select command and some minor bug fixes Select command did not fall back to READY state if Select was issued on another tag. PrepareFrame allowed the tag to respond to Selected requests even if we were not in SELECTED state. Also fixed Read Single and Read Multiple out of bound reads in case of addressed commands. --- Firmware/Chameleon-Mini/Application/EM4233.c | 123 +++++++++++------- .../Chameleon-Mini/Application/ISO15693-A.c | 12 +- .../Chameleon-Mini/Application/ISO15693-A.h | 2 +- .../Chameleon-Mini/Application/Sl2s2002.h | 3 - .../Application/TITagitstandard.c | 2 +- 5 files changed, 87 insertions(+), 55 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/EM4233.c b/Firmware/Chameleon-Mini/Application/EM4233.c index c94097c..8fc69c7 100644 --- a/Firmware/Chameleon-Mini/Application/EM4233.c +++ b/Firmware/Chameleon-Mini/Application/EM4233.c @@ -3,6 +3,9 @@ * * Created on: 12-05-2018 * Author: ceres-c & MrMoDDoM + * TODO: + * - Check with real tag every command's actual response in addressed/selected State + * (Only EM4233_Read_Single and EM4233_Read_Multiple have been checked up to now) */ #include "ISO15693-A.h" @@ -91,22 +94,21 @@ uint16_t EM4233_Lock_Block(uint8_t* FrameBuf, uint16_t FrameBytes) uint16_t EM4233_Write_Single(uint8_t* FrameBuf, uint16_t FrameBytes) { uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; - uint8_t* Dataptr; - uint8_t PageAddress = *FrameInfo.Parameters; + uint8_t BlockAddress = *FrameInfo.Parameters; + uint8_t* Dataptr = BlockAddress + 0x01; /* Data to write begins on 2nd byte of the frame received by the reader */ uint8_t LockStatus = 0; if (FrameInfo.ParamLen != 5) return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ - if (PageAddress > EM4233_NUMBER_OF_BLCKS) { + if (BlockAddress > EM4233_NUMBER_OF_BLCKS) { // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_OPT_NOT_SUPP; ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ return ResponseByteCount; /* malformed: trying to write in a non-existing block */ } - MemoryReadBlock(&LockStatus, (EM4233_MEM_LSM_ADDRESS + PageAddress), 1); - Dataptr = PageAddress + 0x01; + MemoryReadBlock(&LockStatus, (EM4233_MEM_LSM_ADDRESS + BlockAddress), 1); if (LockStatus & ISO15693_MASK_FACTORY_LOCK) { // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; @@ -117,7 +119,7 @@ uint16_t EM4233_Write_Single(uint8_t* FrameBuf, uint16_t FrameBytes) // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_BLK_CHG_LKD; ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ } else { - MemoryWriteBlock(Dataptr, PageAddress * EM4233_BYTES_PER_BLCK, EM4233_BYTES_PER_BLCK); + MemoryWriteBlock(Dataptr, BlockAddress * EM4233_BYTES_PER_BLCK, EM4233_BYTES_PER_BLCK); FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; ResponseByteCount += 1; } @@ -129,23 +131,25 @@ uint16_t EM4233_Read_Single(uint8_t* FrameBuf, uint16_t FrameBytes) { uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; uint8_t FramePtr; /* holds the address where block's data will be put */ - uint8_t PageAddress = *FrameInfo.Parameters; + uint8_t BlockAddress = FrameInfo.Parameters[0]; uint8_t LockStatus = 0; if (FrameInfo.ParamLen != 1) return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ - if (PageAddress >= EM4233_NUMBER_OF_BLCKS) { /* the reader is requesting a sector out of bound */ - // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; - // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_BLK_NOT_AVL; - ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ - return ResponseByteCount; + if (BlockAddress >= EM4233_NUMBER_OF_BLCKS) { /* check if the reader is requesting a sector out of bound */ + if (FrameInfo.Addressed) { /* If the request is addressed */ + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = 0x0F; /* Magic number from real tag */ + ResponseByteCount += 2; /* Copied this behaviour from real tag, not specified in ISO documents */ + } + return ResponseByteCount; /* If not addressed real tag does not respond */ } FramePtr = 1; if (FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_OPTION) { /* request with option flag set */ - MemoryReadBlock(&LockStatus, (EM4233_MEM_LSM_ADDRESS + PageAddress), 1); + MemoryReadBlock(&LockStatus, (EM4233_MEM_LSM_ADDRESS + BlockAddress), 1); if (LockStatus & ISO15693_MASK_FACTORY_LOCK) { /* tests if the n-th bit of the factory bitmask if set to 1 */ FrameBuf[FramePtr] = ISO15693_MASK_FACTORY_LOCK; /* return bit 1 set as 1 (factory locked) */ } else if (LockStatus & ISO15693_MASK_USER_LOCK) { /* tests if the n-th bit of the user bitmask if set to 1 */ @@ -156,7 +160,7 @@ uint16_t EM4233_Read_Single(uint8_t* FrameBuf, uint16_t FrameBytes) ResponseByteCount += 1; } - MemoryReadBlock(&FrameBuf[FramePtr], PageAddress * EM4233_BYTES_PER_BLCK, EM4233_BYTES_PER_BLCK); + MemoryReadBlock(&FrameBuf[FramePtr], BlockAddress * EM4233_BYTES_PER_BLCK, EM4233_BYTES_PER_BLCK); ResponseByteCount += 4; FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ @@ -175,11 +179,13 @@ uint16_t EM4233_Read_Multiple(uint8_t* FrameBuf, uint16_t FrameBytes) if (FrameInfo.ParamLen != 2) return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ - if (BlockAddress > EM4233_NUMBER_OF_BLCKS) { /* the reader is requesting a starting block out of bound */ - // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; - // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_BLK_NOT_AVL; - ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ - return ResponseByteCount; + if (BlockAddress >= EM4233_NUMBER_OF_BLCKS) { /* the reader is requesting a block out of bound */ + if (FrameInfo.Addressed) { /* If the request is addressed */ + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = 0x0F; /* Magic number from real tag */ + ResponseByteCount += 2; /* Copied this behaviour from real tag, not specified in ISO documents */ + } + return ResponseByteCount; /* If not addressed real tag does not respond */ } else if ((BlockAddress + BlocksNumber) >= EM4233_NUMBER_OF_BLCKS) { /* last block is out of bound */ BlocksNumber = EM4233_NUMBER_OF_BLCKS - BlockAddress; /* we read up to latest block, as real tag does */ } @@ -431,6 +437,7 @@ uint16_t EM4233_Get_Multi_Block_Sec_Stat(uint8_t* FrameBuf, uint16_t FrameBytes) uint16_t EM4233_Select(uint8_t* FrameBuf, uint16_t FrameBytes, uint8_t* Uid) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* I've no idea how this request could generate errors ._. if ( ) { FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; @@ -442,22 +449,48 @@ uint16_t EM4233_Select(uint8_t* FrameBuf, uint16_t FrameBytes, uint8_t* Uid) bool UidEquals = ISO15693CompareUid(&FrameBuf[ISO15693_REQ_ADDR_PARAM], Uid); - if (!FrameInfo.Addressed || FrameInfo.Selected) { + if (!(FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_ADDRESS) || + (FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_SELECT) + ) { /* tag should remain silent if Select is performed without address flag or with select flag */ return ISO15693_APP_NO_RESPONSE; - } else if (State == STATE_SELECTED && !UidEquals) { - /* tag should remain silent if Select is performed while the tag is selected but against another tag */ + } else if (!UidEquals) { + /* tag should remain silent and reset if Select is performed against another UID, + * whether our the tag is selected or not + */ State = STATE_READY; return ISO15693_APP_NO_RESPONSE; - } else if (State != STATE_SELECTED && !UidEquals) { - /* tag should remain silent if Select is performed against another UID */ - return ISO15693_APP_NO_RESPONSE; } else if (State != STATE_SELECTED && UidEquals) { State = STATE_SELECTED; - return ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + ResponseByteCount += 1; + return ResponseByteCount; } +} - return ISO15693_APP_NO_RESPONSE; /* Just because you never know... */ +uint16_t EM4233_Reset_To_Ready(uint8_t* FrameBuf, uint16_t FrameBytes) +{ + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + /* I've no idea how this request could generate errors ._. + if ( ) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC; + ResponseByteCount += 2; + return ResponseByteCount; + } + */ + FrameInfo.Flags = NULL; + FrameInfo.Command = NULL; + FrameInfo.Parameters = NULL; + FrameInfo.ParamLen = 0; + FrameInfo.Addressed = false; + FrameInfo.Selected = false; + + State = STATE_READY; + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + ResponseByteCount += 1; + return ResponseByteCount; } uint16_t EM4233_Login(uint8_t* FrameBuf, uint16_t FrameBytes, uint8_t* Uid) @@ -496,7 +529,14 @@ uint16_t EM4233AppProcess(uint8_t* FrameBuf, uint16_t FrameBytes) uint8_t Uid[ActiveConfiguration.UidSize]; EM4233GetUid(Uid); - if (!ISO15693PrepareFrame(FrameBuf, FrameBytes, &FrameInfo, Uid, MyAFI)) + if (FrameBuf[ISO15693_REQ_ADDR_CMD] == ISO15693_CMD_SELECT) { + /* Select has its own path before PrepareFrame because we have to change the variable State + * from Select to Ready if "Select" cmd is addressed to another tag. + * It felt weird to add this kind of check in ISO15693PrepareFrame, which should not + * interfere with tag specific variables, such as State in this case. + */ + ResponseByteCount = EM4233_Select(FrameBuf, FrameBytes, Uid); + } else if (!ISO15693PrepareFrame(FrameBuf, FrameBytes, &FrameInfo, State == STATE_SELECTED, Uid, MyAFI)) return ISO15693_APP_NO_RESPONSE; if (State == STATE_READY || State == STATE_SELECTED) { @@ -543,30 +583,25 @@ uint16_t EM4233AppProcess(uint8_t* FrameBuf, uint16_t FrameBytes) } else if (*FrameInfo.Command == ISO15693_CMD_GET_BLOCK_SEC) { ResponseByteCount = EM4233_Get_Multi_Block_Sec_Stat(FrameBuf, FrameBytes); - - } else if (*FrameInfo.Command == ISO15693_CMD_SELECT) { - ResponseByteCount = EM4233_Select(FrameBuf, FrameBytes, Uid); + + } else if (*FrameInfo.Command == ISO15693_CMD_RESET_TO_READY) { + ResponseByteCount = EM4233_Reset_To_Ready (FrameBuf, FrameBytes); } else if (*FrameInfo.Command == EM4233_CMD_LOGIN) { ResponseByteCount = EM4233_Login(FrameBuf, FrameBytes, Uid); + } else if (*FrameInfo.Command == ISO15693_CMD_INVENTORY) { + /* This is just a placeholder to avoid falling in the following else */ + } else { - FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; - FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_NOT_SUPP; - ResponseByteCount = 2; + /* EM4233 does not respond to non existing commands */ + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_NOT_SUPP; + // ResponseByteCount = 2; } } else if (State == STATE_QUIET) { if (*FrameInfo.Command == ISO15693_CMD_RESET_TO_READY) { - FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; - ResponseByteCount = 1; - State = STATE_READY; - - FrameInfo.Flags = NULL; - FrameInfo.Command = NULL; - FrameInfo.Parameters = NULL; - FrameInfo.ParamLen = 0; - FrameInfo.Addressed = false; - FrameInfo.Selected = false; + ResponseByteCount = EM4233_Reset_To_Ready (FrameBuf, FrameBytes); } } diff --git a/Firmware/Chameleon-Mini/Application/ISO15693-A.c b/Firmware/Chameleon-Mini/Application/ISO15693-A.c index 9224606..a206bc8 100644 --- a/Firmware/Chameleon-Mini/Application/ISO15693-A.c +++ b/Firmware/Chameleon-Mini/Application/ISO15693-A.c @@ -65,7 +65,7 @@ bool ISO15693CheckCRC(void* FrameBuf, uint16_t FrameBufSize) * * Authors: ceres-c & MrMoDDoM */ -bool ISO15693PrepareFrame(uint8_t* FrameBuf, uint16_t FrameBytes, CurrentFrame* FrameStruct, uint8_t* MyUid, uint8_t MyAFI) +bool ISO15693PrepareFrame(uint8_t* FrameBuf, uint16_t FrameBytes, CurrentFrame* FrameStruct, uint8_t IsSelected, uint8_t* MyUid, uint8_t MyAFI) { if ((FrameBytes < ISO15693_MIN_FRAME_SIZE) || !ISO15693CheckCRC(FrameBuf, FrameBytes - ISO15693_CRC16_SIZE)) /* malformed frame */ @@ -96,8 +96,7 @@ bool ISO15693PrepareFrame(uint8_t* FrameBuf, uint16_t FrameBytes, CurrentFrame* return false; FrameStruct -> Parameters += 0x01; } - else if ( ((*FrameStruct -> Command) == ISO15693_CMD_INVENTORY) && (FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_AFI)) { - /* or if it is Inventory with AFI flag set */ + else if ( ((*FrameStruct -> Command) == ISO15693_CMD_INVENTORY) && (FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_AFI)) { /* or if it is Inventory with AFI flag set */ /* then between CMD and UID is placed another byte which is requested AFI, but we don't need it */ if (FrameBuf[ISO15693_REQ_ADDR_PARAM] != MyAFI) /* if requested AFI is different from our current one, then don't respond */ @@ -107,11 +106,12 @@ bool ISO15693PrepareFrame(uint8_t* FrameBuf, uint16_t FrameBytes, CurrentFrame* FrameStruct -> ParamLen = FrameBuf + (FrameBytes - ISO15693_CRC16_SIZE) - (FrameStruct -> Parameters); - uint8_t *uid = (FrameStruct -> Parameters) - ISO15693_GENERIC_UID_SIZE; - - if (FrameStruct -> Addressed && !ISO15693CompareUid( uid, MyUid)) { + if (FrameStruct -> Addressed && !ISO15693CompareUid(&FrameBuf[ISO15693_REQ_ADDR_PARAM], MyUid)) { /* addressed request but we're not the addressee */ return false; + } else if (FrameStruct -> Selected && !IsSelected) { + /* selected request but we're not in selected state */ + return false; } else { return true; } diff --git a/Firmware/Chameleon-Mini/Application/ISO15693-A.h b/Firmware/Chameleon-Mini/Application/ISO15693-A.h index f99c6b6..42b1655 100644 --- a/Firmware/Chameleon-Mini/Application/ISO15693-A.h +++ b/Firmware/Chameleon-Mini/Application/ISO15693-A.h @@ -88,7 +88,7 @@ typedef struct { void ISO15693AppendCRC(uint8_t* FrameBuf, uint16_t FrameBufSize); bool ISO15693CheckCRC(void* FrameBuf, uint16_t FrameBufSize); -bool ISO15693PrepareFrame(uint8_t* FrameBuf, uint16_t FrameBytes, CurrentFrame* FrameStruct, uint8_t* MyUid, uint8_t MyAFI); +bool ISO15693PrepareFrame(uint8_t* FrameBuf, uint16_t FrameBytes, CurrentFrame* FrameStruct, uint8_t IsSelected, uint8_t* MyUid, uint8_t MyAFI); bool ISO15693AntiColl(uint8_t* FrameBuf, uint16_t FrameBytes, CurrentFrame* FrameStruct, uint8_t* MyUid); INLINE diff --git a/Firmware/Chameleon-Mini/Application/Sl2s2002.h b/Firmware/Chameleon-Mini/Application/Sl2s2002.h index be37eb2..9f58761 100644 --- a/Firmware/Chameleon-Mini/Application/Sl2s2002.h +++ b/Firmware/Chameleon-Mini/Application/Sl2s2002.h @@ -11,9 +11,6 @@ #include "Application.h" #include "ISO15693-A.h" -#define ISO15693_GENERIC_UID_SIZE 8 //ISO15693_UID_SIZE -#define ISO15693_GENERIC_MEM_SIZE 8192 //ISO15693_MAX_MEM_SIZE - void Sl2s2002AppInit(void); void Sl2s2002AppReset(void); void Sl2s2002AppTask(void); diff --git a/Firmware/Chameleon-Mini/Application/TITagitstandard.c b/Firmware/Chameleon-Mini/Application/TITagitstandard.c index 3e1cc5d..3a34177 100644 --- a/Firmware/Chameleon-Mini/Application/TITagitstandard.c +++ b/Firmware/Chameleon-Mini/Application/TITagitstandard.c @@ -67,7 +67,7 @@ uint16_t TITagitstandardAppProcess(uint8_t* FrameBuf, uint16_t FrameBytes) uint8_t Uid[ActiveConfiguration.UidSize]; TITagitstandardGetUid(Uid); - if (!ISO15693PrepareFrame(FrameBuf, FrameBytes, &FrameInfo, Uid, MyAFI)) + if (!ISO15693PrepareFrame(FrameBuf, FrameBytes, &FrameInfo, State == STATE_SELECTED, Uid, MyAFI)) return ISO15693_APP_NO_RESPONSE; switch(State) {