#include "Commands.h" #include #include #include "XModem.h" #include "../Settings.h" #include "../Chameleon-Mini.h" #include "../LUFA/Version.h" #include "../Configuration.h" #include "../Random.h" #include "../Memory.h" #include "../System.h" #include "../Button.h" #include "../AntennaLevel.h" #include "../Battery.h" #include "../Codec/Codec.h" extern Reader14443Command Reader14443CurrentCommand; extern const PROGMEM CommandEntryType CommandTable[]; CommandStatusIdType CommandGetVersion(char* OutParam) { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR( "ChameleonMini RevG %S using LUFA %S compiled with AVR-GCC %S. Based on the open-source NFC tool ChameleonMini. https://github.com/emsec/ChameleonMini commit %S" ), PSTR(CHAMELEON_MINI_VERSION_STRING), PSTR(LUFA_VERSION_STRING), PSTR(__VERSION__), PSTR(COMMIT_ID) ); return COMMAND_INFO_OK_WITH_TEXT_ID; } CommandStatusIdType CommandGetConfig(char* OutParam) { ConfigurationGetByName(OutParam, TERMINAL_BUFFER_SIZE); return COMMAND_INFO_OK_WITH_TEXT_ID; } CommandStatusIdType CommandSetConfig(char* OutMessage, const char* InParam) { if (COMMAND_IS_SUGGEST_STRING(InParam)) { ConfigurationGetList(OutMessage, TERMINAL_BUFFER_SIZE); return COMMAND_INFO_OK_WITH_TEXT_ID; } else if (ConfigurationSetByName(InParam)) { SettingsSave(); return COMMAND_INFO_OK_ID; } else { return COMMAND_ERR_INVALID_PARAM_ID; } } CommandStatusIdType CommandGetUid(char* OutParam) { uint8_t UidBuffer[COMMAND_UID_BUFSIZE]; uint16_t UidSize = ActiveConfiguration.UidSize; if (UidSize == 0) { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("NO UID.")); return COMMAND_INFO_OK_WITH_TEXT_ID; } ApplicationGetUid(UidBuffer); BufferToHexString(OutParam, TERMINAL_BUFFER_SIZE, UidBuffer, UidSize); return COMMAND_INFO_OK_WITH_TEXT_ID; } CommandStatusIdType CommandSetUid(char* OutMessage, const char* InParam) { uint8_t UidBuffer[COMMAND_UID_BUFSIZE]; uint16_t UidSize = ActiveConfiguration.UidSize; if (strcmp_P(InParam, PSTR(COMMAND_UID_RANDOM)) == 0) { /* Load with random bytes */ for (uint8_t i=0; iCommand) != 0 && ByteCount > 0) { const char* CommandName = EntryPtr->Command; char c; while( (c = pgm_read_byte(CommandName)) != '\0' && ByteCount > 1) { *OutMessage++ = c; CommandName++; ByteCount--; } *OutMessage++ = ','; ByteCount--; EntryPtr++; } *--OutMessage = '\0'; return COMMAND_INFO_OK_WITH_TEXT_ID; } CommandStatusIdType CommandGetRssi(char* OutParam) { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("%5u mV"), AntennaLevelGet()); return COMMAND_INFO_OK_WITH_TEXT_ID; } CommandStatusIdType CommandGetSysTick(char* OutParam) { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("%4.4X"), SystemGetSysTick()); return COMMAND_INFO_OK_WITH_TEXT_ID; } CommandStatusIdType CommandExecParamSend(char* OutMessage, const char* InParams) { if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO14443A_READER) return COMMAND_ERR_INVALID_USAGE_ID; ApplicationReset(); Reader14443CurrentCommand = Reader14443_Send; char const * paramTwo = strchr(InParams, ' '); uint16_t length; if (paramTwo == NULL) // this means, we have to calculate the length { length = strlen(InParams); if (length&1) // return error when length is odd return COMMAND_ERR_INVALID_PARAM_ID; length /= 2; if (length == 1) { ReaderSendBitCount = 7; // this is a short frame } else { ReaderSendBitCount = length * 8; } } else if(paramTwo == (InParams+4)) { // we have a bitcount prepended uint8_t tmp[2]; HexStringToBuffer(tmp, 2, InParams); ReaderSendBitCount = (tmp[0]<<8) + tmp[1]; // set our BitCount to the given value InParams = ++paramTwo; // set InParams to the beginning of the second parameter length = strlen(InParams); if ((length&1) || (length / 2 * 8) < ReaderSendBitCount) // this parameter is malformed, if it is odd or if there are less bits than the BitCount indicates return COMMAND_ERR_INVALID_PARAM_ID; } else { // any other case means we have malformed parameters return COMMAND_ERR_INVALID_PARAM_ID; } HexStringToBuffer(ReaderSendBuffer, (ReaderSendBitCount+7)/8, InParams); Reader14443ACodecStart(); return TIMEOUT_COMMAND; } CommandStatusIdType CommandExecParamSendRaw(char* OutMessage, const char* InParams) { if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO14443A_READER) return COMMAND_ERR_INVALID_USAGE_ID; ApplicationReset(); Reader14443CurrentCommand = Reader14443_Send_Raw; char const * paramTwo = strchr(InParams, ' '); uint16_t length; if (paramTwo == NULL) // this means, we have to calculate the length { length = strlen(InParams); if (length&1) // return error when length is odd return COMMAND_ERR_INVALID_PARAM_ID; length /= 2; if (length == 1) { ReaderSendBitCount = 7; // this is a short frame } else { length *= 8; ReaderSendBitCount = length - (length % 9); // how many bytes+paritybit match into our input? } } else if(paramTwo == (InParams+4)) { // we have a bitcount prepended uint8_t tmp[2]; HexStringToBuffer(tmp, 2, InParams); ReaderSendBitCount = (tmp[0]<<8) + tmp[1]; // set our BitCount to the given value if (ReaderSendBitCount != 7 && (ReaderSendBitCount % 8)) // since we have to add parity bits here (in case this is not a short frame), the number of bits to be sent has to be a multiple of 8 return COMMAND_ERR_INVALID_PARAM_ID; InParams = ++paramTwo; // set InParams to the beginning of the second parameter length = strlen(InParams); if ((length&1) || (length / 2 * 8) < ReaderSendBitCount) // this parameter is malformed, if it is odd or if there are less bits than the BitCount indicates return COMMAND_ERR_INVALID_PARAM_ID; } else { // any other case means we have malformed parameters return COMMAND_ERR_INVALID_PARAM_ID; } HexStringToBuffer(ReaderSendBuffer, (ReaderSendBitCount+7)/8, InParams); Reader14443ACodecStart(); return TIMEOUT_COMMAND; } CommandStatusIdType CommandExecDumpMFU(char* OutMessage) { if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO14443A_READER) return COMMAND_ERR_INVALID_USAGE_ID; ApplicationReset(); Reader14443CurrentCommand = Reader14443_Read_MF_Ultralight; Reader14443AAppInit(); Reader14443ACodecStart(); CommandLinePendingTaskTimeout = &Reader14443AAppTimeout; return TIMEOUT_COMMAND; } CommandStatusIdType CommandExecGetUid(char* OutMessage) // this function is for reading the uid in reader mode { if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO14443A_READER) return COMMAND_ERR_INVALID_USAGE_ID; ApplicationReset(); Reader14443CurrentCommand = Reader14443_Get_UID; Reader14443AAppInit(); Reader14443ACodecStart(); CommandLinePendingTaskTimeout = &Reader14443AAppTimeout; return TIMEOUT_COMMAND; } CommandStatusIdType CommandExecIdentifyCard(char* OutMessage) { if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO14443A_READER) return COMMAND_ERR_INVALID_USAGE_ID; ApplicationReset(); Reader14443CurrentCommand = Reader14443_Indentify; Reader14443AAppInit(); Reader14443ACodecStart(); CommandLinePendingTaskTimeout = &Reader14443AAppTimeout; return TIMEOUT_COMMAND; } CommandStatusIdType CommandGetTimeout(char* OutParam) { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("%u ms"), GlobalSettings.ActiveSettingPtr->PendingTaskTimeout * 100); return COMMAND_INFO_OK_WITH_TEXT_ID; } CommandStatusIdType CommandSetTimeout(char* OutMessage, const char* InParam) { if (COMMAND_IS_SUGGEST_STRING(InParam)) { snprintf_P(OutMessage, TERMINAL_BUFFER_SIZE, PSTR("0 = no timeout\r\n1-600 = 100 ms - 60000 ms timeout")); return COMMAND_INFO_OK_WITH_TEXT_ID; } uint16_t tmp = 601; if (!sscanf(InParam, "%5d", &tmp) || tmp > 600) return COMMAND_ERR_INVALID_PARAM_ID; GlobalSettings.ActiveSettingPtr->PendingTaskTimeout = tmp; return COMMAND_INFO_OK_ID; } CommandStatusIdType CommandGetThreshold(char* OutParam) { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("%u"), ReaderThreshold); return COMMAND_INFO_OK_WITH_TEXT_ID; } CommandStatusIdType CommandSetThreshold(char* OutMessage, const char* InParam) { if (COMMAND_IS_SUGGEST_STRING(InParam)) { snprintf_P(OutMessage, TERMINAL_BUFFER_SIZE, PSTR("Any integer from 0 to %u. Reference voltage will be (VCC * THRESHOLD / 4095) mV."), CODEC_MAXIMUM_THRESHOLD); return COMMAND_INFO_OK_WITH_TEXT_ID; } uint16_t tmp = 0; if (!sscanf(InParam, "%5d", &tmp) || tmp > CODEC_MAXIMUM_THRESHOLD) return COMMAND_ERR_INVALID_PARAM_ID; DACB.CH0DATA = tmp; ReaderThreshold = tmp; return COMMAND_INFO_OK_ID; } CommandStatusIdType CommandSetField(char* OutMessage, const char* InParam) { if (COMMAND_IS_SUGGEST_STRING(InParam)) { snprintf_P(OutMessage, TERMINAL_BUFFER_SIZE, PSTR("%c,%c"), COMMAND_CHAR_TRUE, COMMAND_CHAR_FALSE); return COMMAND_INFO_OK_WITH_TEXT_ID; } if (InParam[0] == COMMAND_CHAR_TRUE) { CodecReaderFieldStart(); } else if(InParam[0] == COMMAND_CHAR_FALSE) { CodecReaderFieldStop(); } else { return COMMAND_ERR_INVALID_PARAM_ID; } return COMMAND_INFO_OK_ID; } CommandStatusIdType CommandGetField(char* OutMessage) { if (CodecGetReaderField()) OutMessage[0] = COMMAND_CHAR_TRUE; else OutMessage[0] = COMMAND_CHAR_FALSE; OutMessage[1] = '\0'; return COMMAND_INFO_OK_WITH_TEXT_ID; }