mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-22 05:14:46 -07:00
Merge branch 'pr/456' into 420
This commit is contained in:
@@ -120,74 +120,32 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
|
|||||||
case NfcVTypeSlix:
|
case NfcVTypeSlix:
|
||||||
furi_string_cat_printf(temp_str, "Type: SLIX\n");
|
furi_string_cat_printf(temp_str, "Type: SLIX\n");
|
||||||
furi_string_cat_printf(temp_str, "Keys:\n");
|
furi_string_cat_printf(temp_str, "Keys:\n");
|
||||||
furi_string_cat_printf(
|
furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
|
||||||
temp_str,
|
|
||||||
" EAS %08lX\n",
|
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
|
|
||||||
break;
|
break;
|
||||||
case NfcVTypeSlixS:
|
case NfcVTypeSlixS:
|
||||||
furi_string_cat_printf(temp_str, "Type: SLIX-S\n");
|
furi_string_cat_printf(temp_str, "Type: SLIX-S\n");
|
||||||
furi_string_cat_printf(temp_str, "Keys:\n");
|
furi_string_cat_printf(temp_str, "Keys:\n");
|
||||||
furi_string_cat_printf(
|
furi_string_cat_printf(temp_str, " Read %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read));
|
||||||
temp_str,
|
furi_string_cat_printf(temp_str, " Write %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write));
|
||||||
" Read %08lX\n",
|
furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy));
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.key_read));
|
furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy));
|
||||||
furi_string_cat_printf(
|
furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
|
||||||
temp_str,
|
|
||||||
" Write %08lX\n",
|
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.key_write));
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
" Privacy %08lX\n",
|
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.key_privacy));
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
" Destroy %08lX\n",
|
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.key_destroy));
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
" EAS %08lX\n",
|
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_s.key_eas));
|
|
||||||
break;
|
break;
|
||||||
case NfcVTypeSlixL:
|
case NfcVTypeSlixL:
|
||||||
furi_string_cat_printf(temp_str, "Type: SLIX-L\n");
|
furi_string_cat_printf(temp_str, "Type: SLIX-L\n");
|
||||||
furi_string_cat_printf(temp_str, "Keys:\n");
|
furi_string_cat_printf(temp_str, "Keys:\n");
|
||||||
furi_string_cat_printf(
|
furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy));
|
||||||
temp_str,
|
furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy));
|
||||||
" Privacy %08lX\n",
|
furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_l.key_privacy));
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
" Destroy %08lX\n",
|
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_l.key_destroy));
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
" EAS %08lX\n",
|
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix_l.key_eas));
|
|
||||||
break;
|
break;
|
||||||
case NfcVTypeSlix2:
|
case NfcVTypeSlix2:
|
||||||
furi_string_cat_printf(temp_str, "Type: SLIX2\n");
|
furi_string_cat_printf(temp_str, "Type: SLIX2\n");
|
||||||
furi_string_cat_printf(temp_str, "Keys:\n");
|
furi_string_cat_printf(temp_str, "Keys:\n");
|
||||||
furi_string_cat_printf(
|
furi_string_cat_printf(temp_str, " Read %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read));
|
||||||
temp_str,
|
furi_string_cat_printf(temp_str, " Write %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write));
|
||||||
" Read %08lX\n",
|
furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy));
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.key_read));
|
furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy));
|
||||||
furi_string_cat_printf(
|
furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
|
||||||
temp_str,
|
|
||||||
" Write %08lX\n",
|
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.key_write));
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
" Privacy %08lX\n",
|
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.key_privacy));
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
" Destroy %08lX\n",
|
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.key_destroy));
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
" EAS %08lX\n",
|
|
||||||
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix2.key_eas));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n");
|
furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n");
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
void nfc_scene_nfcv_key_input_byte_input_callback(void* context) {
|
void nfc_scene_nfcv_key_input_byte_input_callback(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
NfcVSlixLData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix_l;
|
NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
|
||||||
memcpy(data->key_privacy, nfc->byte_input_store, 4);
|
memcpy(data->key_privacy, nfc->byte_input_store, 4);
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ typedef enum {
|
|||||||
|
|
||||||
static bool nfc_scene_nfcv_unlock_worker_callback(NfcWorkerEvent event, void* context) {
|
static bool nfc_scene_nfcv_unlock_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
NfcVSlixLData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix_l;
|
NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
|
||||||
if(event == NfcWorkerEventNfcVPassKey) {
|
if(event == NfcWorkerEventNfcVPassKey) {
|
||||||
memcpy(data->key_privacy, nfc->byte_input_store, 4);
|
memcpy(data->key_privacy, nfc->byte_input_store, 4);
|
||||||
|
|||||||
@@ -2028,6 +2028,7 @@ Function,-,nfca_signal_free,void,NfcaSignal*
|
|||||||
Function,-,nfcv_emu_deinit,void,NfcVData*
|
Function,-,nfcv_emu_deinit,void,NfcVData*
|
||||||
Function,-,nfcv_emu_init,void,"FuriHalNfcDevData*, NfcVData*"
|
Function,-,nfcv_emu_init,void,"FuriHalNfcDevData*, NfcVData*"
|
||||||
Function,-,nfcv_emu_loop,_Bool,"FuriHalNfcTxRxContext*, FuriHalNfcDevData*, NfcVData*, uint32_t"
|
Function,-,nfcv_emu_loop,_Bool,"FuriHalNfcTxRxContext*, FuriHalNfcDevData*, NfcVData*, uint32_t"
|
||||||
|
Function,-,nfcv_emu_send,void,"FuriHalNfcTxRxContext*, NfcVData*, uint8_t*, uint8_t, NfcVSendFlags"
|
||||||
Function,-,nfcv_inventory,ReturnCode,uint8_t*
|
Function,-,nfcv_inventory,ReturnCode,uint8_t*
|
||||||
Function,-,nfcv_read_blocks,ReturnCode,"NfcVReader*, NfcVData*"
|
Function,-,nfcv_read_blocks,ReturnCode,"NfcVReader*, NfcVData*"
|
||||||
Function,-,nfcv_read_card,_Bool,"NfcVReader*, FuriHalNfcDevData*, NfcVData*"
|
Function,-,nfcv_read_card,_Bool,"NfcVReader*, FuriHalNfcDevData*, NfcVData*"
|
||||||
|
|||||||
|
@@ -681,7 +681,7 @@ bool nfc_device_load_slix_data(FlipperFormat* file, NfcDevice* dev) {
|
|||||||
|
|
||||||
static bool nfc_device_save_slix_s_data(FlipperFormat* file, NfcDevice* dev) {
|
static bool nfc_device_save_slix_s_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool saved = false;
|
bool saved = false;
|
||||||
NfcVSlixSData* data = &dev->dev_data.nfcv_data.sub_data.slix_s;
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(!flipper_format_write_comment_cstr(file, "SLIX-S specific data")) break;
|
if(!flipper_format_write_comment_cstr(file, "SLIX-S specific data")) break;
|
||||||
@@ -707,7 +707,7 @@ static bool nfc_device_save_slix_s_data(FlipperFormat* file, NfcDevice* dev) {
|
|||||||
|
|
||||||
bool nfc_device_load_slix_s_data(FlipperFormat* file, NfcDevice* dev) {
|
bool nfc_device_load_slix_s_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
NfcVSlixSData* data = &dev->dev_data.nfcv_data.sub_data.slix_s;
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
memset(data, 0, sizeof(NfcVData));
|
memset(data, 0, sizeof(NfcVData));
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -734,7 +734,7 @@ bool nfc_device_load_slix_s_data(FlipperFormat* file, NfcDevice* dev) {
|
|||||||
|
|
||||||
static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
|
static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool saved = false;
|
bool saved = false;
|
||||||
NfcVSlixLData* data = &dev->dev_data.nfcv_data.sub_data.slix_l;
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(!flipper_format_write_comment_cstr(file, "SLIX-L specific data")) break;
|
if(!flipper_format_write_comment_cstr(file, "SLIX-L specific data")) break;
|
||||||
@@ -755,7 +755,7 @@ static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
|
|||||||
|
|
||||||
bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
|
bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
NfcVSlixLData* data = &dev->dev_data.nfcv_data.sub_data.slix_l;
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
memset(data, 0, sizeof(NfcVData));
|
memset(data, 0, sizeof(NfcVData));
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -777,7 +777,7 @@ bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) {
|
|||||||
|
|
||||||
static bool nfc_device_save_slix2_data(FlipperFormat* file, NfcDevice* dev) {
|
static bool nfc_device_save_slix2_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool saved = false;
|
bool saved = false;
|
||||||
NfcVSlix2Data* data = &dev->dev_data.nfcv_data.sub_data.slix2;
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(!flipper_format_write_comment_cstr(file, "SLIX2 specific data")) break;
|
if(!flipper_format_write_comment_cstr(file, "SLIX2 specific data")) break;
|
||||||
@@ -803,7 +803,7 @@ static bool nfc_device_save_slix2_data(FlipperFormat* file, NfcDevice* dev) {
|
|||||||
|
|
||||||
bool nfc_device_load_slix2_data(FlipperFormat* file, NfcDevice* dev) {
|
bool nfc_device_load_slix2_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
NfcVSlix2Data* data = &dev->dev_data.nfcv_data.sub_data.slix2;
|
NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix;
|
||||||
memset(data, 0, sizeof(NfcVData));
|
memset(data, 0, sizeof(NfcVData));
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
|
|||||||
|
|
||||||
NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data;
|
NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data;
|
||||||
FuriHalNfcTxRxContext tx_rx = {};
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
uint8_t* key_data = nfcv_data->sub_data.slix_l.key_privacy;
|
uint8_t *key_data = nfcv_data->sub_data.slix.key_privacy;
|
||||||
uint32_t key = 0;
|
uint32_t key = 0;
|
||||||
|
|
||||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
@@ -186,7 +186,7 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
|
|||||||
furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCV);
|
furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCV);
|
||||||
|
|
||||||
furi_hal_console_printf("Detect presence\r\n");
|
furi_hal_console_printf("Detect presence\r\n");
|
||||||
ReturnCode ret = slix_l_get_random(nfcv_data);
|
ReturnCode ret = slix_get_random(nfcv_data);
|
||||||
|
|
||||||
if(ret == ERR_NONE) {
|
if(ret == ERR_NONE) {
|
||||||
/* there is some chip, responding with a RAND */
|
/* there is some chip, responding with a RAND */
|
||||||
@@ -212,14 +212,14 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
|
|||||||
nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
|
nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(slix_l_get_random(NULL) == ERR_NONE) {
|
while(slix_get_random(NULL) == ERR_NONE) {
|
||||||
furi_delay_ms(100);
|
furi_delay_ms(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_hal_console_printf(
|
furi_hal_console_printf(
|
||||||
" => chip is already visible, wait for chip to disappear.\r\n");
|
" => chip is already visible, wait for chip to disappear.\r\n");
|
||||||
nfc_worker->callback(NfcWorkerEventAborted, nfc_worker->context);
|
nfc_worker->callback(NfcWorkerEventAborted, nfc_worker->context);
|
||||||
while(slix_l_get_random(NULL) == ERR_NONE) {
|
while(slix_get_random(NULL) == ERR_NONE) {
|
||||||
furi_delay_ms(100);
|
furi_delay_ms(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,14 +238,14 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
|
|||||||
key |= key_data[2] << 8;
|
key |= key_data[2] << 8;
|
||||||
key |= key_data[3] << 0;
|
key |= key_data[3] << 0;
|
||||||
|
|
||||||
ret = slix_l_unlock(nfcv_data, 4);
|
ret = slix_unlock(nfcv_data, 4);
|
||||||
} else {
|
} else {
|
||||||
key = 0x7FFD6E5B;
|
key = 0x7FFD6E5B;
|
||||||
key_data[0] = key >> 24;
|
key_data[0] = key >> 24;
|
||||||
key_data[1] = key >> 16;
|
key_data[1] = key >> 16;
|
||||||
key_data[2] = key >> 8;
|
key_data[2] = key >> 8;
|
||||||
key_data[3] = key >> 0;
|
key_data[3] = key >> 0;
|
||||||
ret = slix_l_unlock(nfcv_data, 4);
|
ret = slix_unlock(nfcv_data, 4);
|
||||||
|
|
||||||
if(ret != ERR_NONE) {
|
if(ret != ERR_NONE) {
|
||||||
/* main key failed, trying second one */
|
/* main key failed, trying second one */
|
||||||
@@ -256,7 +256,7 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
|
|||||||
furi_delay_ms(20);
|
furi_delay_ms(20);
|
||||||
furi_hal_nfc_ll_txrx_on();
|
furi_hal_nfc_ll_txrx_on();
|
||||||
|
|
||||||
if(slix_l_get_random(nfcv_data) != ERR_NONE) {
|
if(slix_get_random(nfcv_data) != ERR_NONE) {
|
||||||
furi_hal_console_printf(" reset failed\r\n");
|
furi_hal_console_printf(" reset failed\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,7 +265,7 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
|
|||||||
key_data[1] = key >> 16;
|
key_data[1] = key >> 16;
|
||||||
key_data[2] = key >> 8;
|
key_data[2] = key >> 8;
|
||||||
key_data[3] = key >> 0;
|
key_data[3] = key >> 0;
|
||||||
ret = slix_l_unlock(nfcv_data, 4);
|
ret = slix_unlock(nfcv_data, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(ret != ERR_NONE) {
|
if(ret != ERR_NONE) {
|
||||||
@@ -281,7 +281,7 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
|
|||||||
furi_hal_nfc_ll_txrx_on();
|
furi_hal_nfc_ll_txrx_on();
|
||||||
|
|
||||||
/* wait for disappearing */
|
/* wait for disappearing */
|
||||||
while(slix_l_get_random(NULL) == ERR_NONE) {
|
while(slix_get_random(NULL) == ERR_NONE) {
|
||||||
furi_delay_ms(100);
|
furi_delay_ms(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,108 +180,92 @@ void nfcv_crc(uint8_t* data, uint32_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfcv_emu_free(NfcVData* data) {
|
void nfcv_emu_free(NfcVData* data) {
|
||||||
digital_sequence_free(data->emulation.nfcv_signal);
|
digital_sequence_free(data->emu_air.nfcv_signal);
|
||||||
digital_signal_free(data->emulation.nfcv_resp_unmod_256);
|
digital_signal_free(data->emu_air.nfcv_resp_unmod_256);
|
||||||
digital_signal_free(data->emulation.nfcv_resp_pulse_32);
|
digital_signal_free(data->emu_air.nfcv_resp_pulse_32);
|
||||||
digital_signal_free(data->emulation.nfcv_resp_one);
|
digital_signal_free(data->emu_air.nfcv_resp_one);
|
||||||
digital_signal_free(data->emulation.nfcv_resp_zero);
|
digital_signal_free(data->emu_air.nfcv_resp_zero);
|
||||||
digital_signal_free(data->emulation.nfcv_resp_sof);
|
digital_signal_free(data->emu_air.nfcv_resp_sof);
|
||||||
digital_signal_free(data->emulation.nfcv_resp_eof);
|
digital_signal_free(data->emu_air.nfcv_resp_eof);
|
||||||
|
|
||||||
data->emulation.nfcv_signal = NULL;
|
data->emu_air.nfcv_signal = NULL;
|
||||||
data->emulation.nfcv_resp_unmod_256 = NULL;
|
data->emu_air.nfcv_resp_unmod_256 = NULL;
|
||||||
data->emulation.nfcv_resp_pulse_32 = NULL;
|
data->emu_air.nfcv_resp_pulse_32 = NULL;
|
||||||
data->emulation.nfcv_resp_one = NULL;
|
data->emu_air.nfcv_resp_one = NULL;
|
||||||
data->emulation.nfcv_resp_zero = NULL;
|
data->emu_air.nfcv_resp_zero = NULL;
|
||||||
data->emulation.nfcv_resp_sof = NULL;
|
data->emu_air.nfcv_resp_sof = NULL;
|
||||||
data->emulation.nfcv_resp_eof = NULL;
|
data->emu_air.nfcv_resp_eof = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfcv_emu_alloc(NfcVData* data) {
|
void nfcv_emu_alloc(NfcVData* data) {
|
||||||
if(!data->emulation.nfcv_signal) {
|
if(!data->emu_air.nfcv_signal) {
|
||||||
/* assuming max frame length is 255 bytes */
|
/* assuming max frame length is 255 bytes */
|
||||||
data->emulation.nfcv_signal = digital_sequence_alloc(8 * 255 + 2, &gpio_spi_r_mosi);
|
data->emu_air.nfcv_signal = digital_sequence_alloc(8 * 255 + 2, &gpio_spi_r_mosi);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!data->emulation.nfcv_resp_unmod_256) {
|
if(!data->emu_air.nfcv_resp_unmod_256) {
|
||||||
/* unmodulated 256/fc signal as building block */
|
/* unmodulated 256/fc signal as building block */
|
||||||
data->emulation.nfcv_resp_unmod_256 = digital_signal_alloc(4);
|
data->emu_air.nfcv_resp_unmod_256 = digital_signal_alloc(4);
|
||||||
data->emulation.nfcv_resp_unmod_256->start_level = false;
|
data->emu_air.nfcv_resp_unmod_256->start_level = false;
|
||||||
data->emulation.nfcv_resp_unmod_256->edge_timings[0] =
|
data->emu_air.nfcv_resp_unmod_256->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_UNMOD_256 * DIGITAL_SIGNAL_UNIT_S);
|
||||||
(uint32_t)(NFCV_RESP_SUBC1_UNMOD_256 * DIGITAL_SIGNAL_UNIT_S);
|
data->emu_air.nfcv_resp_unmod_256->edge_cnt = 1;
|
||||||
data->emulation.nfcv_resp_unmod_256->edge_cnt = 1;
|
|
||||||
}
|
}
|
||||||
if(!data->emulation.nfcv_resp_pulse_32) {
|
if(!data->emu_air.nfcv_resp_pulse_32) {
|
||||||
/* modulated fc/32 pulse as building block */
|
/* modulated fc/32 pulse as building block */
|
||||||
data->emulation.nfcv_resp_pulse_32 = digital_signal_alloc(4);
|
data->emu_air.nfcv_resp_pulse_32 = digital_signal_alloc(4);
|
||||||
data->emulation.nfcv_resp_pulse_32->start_level = true;
|
data->emu_air.nfcv_resp_pulse_32->start_level = true;
|
||||||
data->emulation.nfcv_resp_pulse_32->edge_timings[0] =
|
data->emu_air.nfcv_resp_pulse_32->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S);
|
||||||
(uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S);
|
data->emu_air.nfcv_resp_pulse_32->edge_timings[1] = (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S);
|
||||||
data->emulation.nfcv_resp_pulse_32->edge_timings[1] =
|
data->emu_air.nfcv_resp_pulse_32->edge_cnt = 2;
|
||||||
(uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S);
|
|
||||||
data->emulation.nfcv_resp_pulse_32->edge_cnt = 2;
|
|
||||||
}
|
}
|
||||||
if(!data->emulation.nfcv_resp_one) {
|
if(!data->emu_air.nfcv_resp_one) {
|
||||||
/* logical one: 256/fc unmodulated then 8 pulses fc/32 */
|
/* logical one: 256/fc unmodulated then 8 pulses fc/32 */
|
||||||
data->emulation.nfcv_resp_one = digital_signal_alloc(24);
|
data->emu_air.nfcv_resp_one = digital_signal_alloc(24);
|
||||||
digital_signal_append(data->emulation.nfcv_resp_one, data->emulation.nfcv_resp_unmod_256);
|
digital_signal_append(data->emu_air.nfcv_resp_one, data->emu_air.nfcv_resp_unmod_256);
|
||||||
for(size_t i = 0; i < 8; i++) {
|
for(size_t i = 0; i < 8; i++) {
|
||||||
digital_signal_append(
|
digital_signal_append(data->emu_air.nfcv_resp_one, data->emu_air.nfcv_resp_pulse_32);
|
||||||
data->emulation.nfcv_resp_one, data->emulation.nfcv_resp_pulse_32);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!data->emulation.nfcv_resp_zero) {
|
if(!data->emu_air.nfcv_resp_zero) {
|
||||||
/* logical zero: 8 pulses fc/32 then 256/fc unmodulated */
|
/* logical zero: 8 pulses fc/32 then 256/fc unmodulated */
|
||||||
data->emulation.nfcv_resp_zero = digital_signal_alloc(24);
|
data->emu_air.nfcv_resp_zero = digital_signal_alloc(24);
|
||||||
for(size_t i = 0; i < 8; i++) {
|
for(size_t i = 0; i < 8; i++) {
|
||||||
digital_signal_append(
|
digital_signal_append(data->emu_air.nfcv_resp_zero, data->emu_air.nfcv_resp_pulse_32);
|
||||||
data->emulation.nfcv_resp_zero, data->emulation.nfcv_resp_pulse_32);
|
|
||||||
}
|
}
|
||||||
digital_signal_append(data->emulation.nfcv_resp_zero, data->emulation.nfcv_resp_unmod_256);
|
digital_signal_append(data->emu_air.nfcv_resp_zero, data->emu_air.nfcv_resp_unmod_256);
|
||||||
}
|
}
|
||||||
if(!data->emulation.nfcv_resp_sof) {
|
if(!data->emu_air.nfcv_resp_sof) {
|
||||||
/* SOF: unmodulated 768/fc, 24 pulses fc/32, logic 1 */
|
/* SOF: unmodulated 768/fc, 24 pulses fc/32, logic 1 */
|
||||||
data->emulation.nfcv_resp_sof = digital_signal_alloc(128);
|
data->emu_air.nfcv_resp_sof = digital_signal_alloc(128);
|
||||||
digital_signal_append(data->emulation.nfcv_resp_sof, data->emulation.nfcv_resp_unmod_256);
|
digital_signal_append(data->emu_air.nfcv_resp_sof, data->emu_air.nfcv_resp_unmod_256);
|
||||||
digital_signal_append(data->emulation.nfcv_resp_sof, data->emulation.nfcv_resp_unmod_256);
|
digital_signal_append(data->emu_air.nfcv_resp_sof, data->emu_air.nfcv_resp_unmod_256);
|
||||||
digital_signal_append(data->emulation.nfcv_resp_sof, data->emulation.nfcv_resp_unmod_256);
|
digital_signal_append(data->emu_air.nfcv_resp_sof, data->emu_air.nfcv_resp_unmod_256);
|
||||||
for(size_t i = 0; i < 24; i++) {
|
for(size_t i = 0; i < 24; i++) {
|
||||||
digital_signal_append(
|
digital_signal_append(data->emu_air.nfcv_resp_sof, data->emu_air.nfcv_resp_pulse_32);
|
||||||
data->emulation.nfcv_resp_sof, data->emulation.nfcv_resp_pulse_32);
|
|
||||||
}
|
}
|
||||||
digital_signal_append(data->emulation.nfcv_resp_sof, data->emulation.nfcv_resp_one);
|
digital_signal_append(data->emu_air.nfcv_resp_sof, data->emu_air.nfcv_resp_one);
|
||||||
}
|
}
|
||||||
if(!data->emulation.nfcv_resp_eof) {
|
if(!data->emu_air.nfcv_resp_eof) {
|
||||||
/* EOF: logic 0, 24 pulses fc/32, unmodulated 768/fc */
|
/* EOF: logic 0, 24 pulses fc/32, unmodulated 768/fc */
|
||||||
data->emulation.nfcv_resp_eof = digital_signal_alloc(128);
|
data->emu_air.nfcv_resp_eof = digital_signal_alloc(128);
|
||||||
digital_signal_append(data->emulation.nfcv_resp_eof, data->emulation.nfcv_resp_zero);
|
digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_zero);
|
||||||
for(size_t i = 0; i < 24; i++) {
|
for(size_t i = 0; i < 24; i++) {
|
||||||
digital_signal_append(
|
digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_pulse_32);
|
||||||
data->emulation.nfcv_resp_eof, data->emulation.nfcv_resp_pulse_32);
|
|
||||||
}
|
}
|
||||||
digital_signal_append(data->emulation.nfcv_resp_eof, data->emulation.nfcv_resp_unmod_256);
|
digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_unmod_256);
|
||||||
digital_signal_append(data->emulation.nfcv_resp_eof, data->emulation.nfcv_resp_unmod_256);
|
digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_unmod_256);
|
||||||
digital_signal_append(data->emulation.nfcv_resp_eof, data->emulation.nfcv_resp_unmod_256);
|
digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_unmod_256);
|
||||||
/* add extra silence */
|
/* add extra silence */
|
||||||
digital_signal_append(data->emulation.nfcv_resp_eof, data->emulation.nfcv_resp_unmod_256);
|
digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_unmod_256);
|
||||||
}
|
}
|
||||||
|
|
||||||
digital_sequence_set_signal(
|
digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_SOF, data->emu_air.nfcv_resp_sof);
|
||||||
data->emulation.nfcv_signal, NFCV_SIG_SOF, data->emulation.nfcv_resp_sof);
|
digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_BIT0, data->emu_air.nfcv_resp_zero);
|
||||||
digital_sequence_set_signal(
|
digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_BIT1, data->emu_air.nfcv_resp_one);
|
||||||
data->emulation.nfcv_signal, NFCV_SIG_BIT0, data->emulation.nfcv_resp_zero);
|
digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_EOF, data->emu_air.nfcv_resp_eof);
|
||||||
digital_sequence_set_signal(
|
|
||||||
data->emulation.nfcv_signal, NFCV_SIG_BIT1, data->emulation.nfcv_resp_one);
|
|
||||||
digital_sequence_set_signal(
|
|
||||||
data->emulation.nfcv_signal, NFCV_SIG_EOF, data->emulation.nfcv_resp_eof);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfcv_emu_send(
|
void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* data, uint8_t length, NfcVSendFlags flags) {
|
||||||
FuriHalNfcTxRxContext* tx_rx,
|
|
||||||
NfcVData* nfcv,
|
|
||||||
uint8_t* data,
|
|
||||||
uint8_t length,
|
|
||||||
NfcVSendFlags flags) {
|
|
||||||
/* picked default value (0) to match the most common format */
|
/* picked default value (0) to match the most common format */
|
||||||
if(!flags) {
|
if(!flags) {
|
||||||
flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof |
|
flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof |
|
||||||
@@ -293,10 +277,10 @@ static void nfcv_emu_send(
|
|||||||
length += 2;
|
length += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
digital_sequence_clear(nfcv->emulation.nfcv_signal);
|
digital_sequence_clear(nfcv->emu_air.nfcv_signal);
|
||||||
|
|
||||||
if(flags & NfcVSendFlagsSof) {
|
if(flags & NfcVSendFlagsSof) {
|
||||||
digital_sequence_add(nfcv->emulation.nfcv_signal, NFCV_SIG_SOF);
|
digital_sequence_add(nfcv->emu_air.nfcv_signal, NFCV_SIG_SOF);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int bit_total = 0; bit_total < length * 8; bit_total++) {
|
for(int bit_total = 0; bit_total < length * 8; bit_total++) {
|
||||||
@@ -304,17 +288,15 @@ static void nfcv_emu_send(
|
|||||||
uint32_t bit_pos = bit_total % 8;
|
uint32_t bit_pos = bit_total % 8;
|
||||||
uint8_t bit_val = 0x01 << bit_pos;
|
uint8_t bit_val = 0x01 << bit_pos;
|
||||||
|
|
||||||
digital_sequence_add(
|
digital_sequence_add(nfcv->emu_air.nfcv_signal, (data[byte_pos] & bit_val) ? NFCV_SIG_BIT1 : NFCV_SIG_BIT0);
|
||||||
nfcv->emulation.nfcv_signal,
|
|
||||||
(data[byte_pos] & bit_val) ? NFCV_SIG_BIT1 : NFCV_SIG_BIT0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(flags & NfcVSendFlagsEof) {
|
if(flags & NfcVSendFlagsEof) {
|
||||||
digital_sequence_add(nfcv->emulation.nfcv_signal, NFCV_SIG_EOF);
|
digital_sequence_add(nfcv->emu_air.nfcv_signal, NFCV_SIG_EOF);
|
||||||
}
|
}
|
||||||
|
|
||||||
FURI_CRITICAL_ENTER();
|
FURI_CRITICAL_ENTER();
|
||||||
digital_sequence_send(nfcv->emulation.nfcv_signal);
|
digital_sequence_send(nfcv->emu_air.nfcv_signal);
|
||||||
FURI_CRITICAL_EXIT();
|
FURI_CRITICAL_EXIT();
|
||||||
furi_hal_gpio_write(&gpio_spi_r_mosi, false);
|
furi_hal_gpio_write(&gpio_spi_r_mosi, false);
|
||||||
|
|
||||||
@@ -338,93 +320,52 @@ static int nfcv_uidcmp(uint8_t* dst, uint8_t* src) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t nfcv_read_be(uint8_t* data, uint32_t length) {
|
void nfcv_emu_handle_packet(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in, uint8_t* payload, uint32_t payload_length) {
|
||||||
uint32_t value = 0;
|
|
||||||
|
|
||||||
for(uint32_t pos = 0; pos < length; pos++) {
|
|
||||||
value <<= 8;
|
|
||||||
value |= data[pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfcv_emu_handle_packet(
|
|
||||||
FuriHalNfcTxRxContext* tx_rx,
|
|
||||||
FuriHalNfcDevData* nfc_data,
|
|
||||||
NfcVData* nfcv_data,
|
|
||||||
uint8_t* payload,
|
|
||||||
uint32_t payload_length) {
|
|
||||||
if(!payload_length) {
|
if(!payload_length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t flags = payload[0];
|
NfcVData* nfcv_data = (NfcVData*)nfcv_data_in;
|
||||||
uint8_t command = payload[1];
|
NfcVEmuProtocolCtx* ctx = &nfcv_data->emu_protocol_ctx;
|
||||||
bool addressed = !(flags & RFAL_NFCV_REQ_FLAG_INVENTORY) &&
|
|
||||||
(flags & RFAL_NFCV_REQ_FLAG_ADDRESS);
|
|
||||||
bool advanced = (command >= 0xA0);
|
|
||||||
uint8_t address_offset = 2 + (advanced ? 1 : 0);
|
|
||||||
uint8_t payload_offset = address_offset + (addressed ? 8 : 0);
|
|
||||||
uint8_t* address = &payload[address_offset];
|
|
||||||
uint8_t response_buffer[32];
|
|
||||||
NfcVSendFlags response_flags = NfcVSendFlagsNormal;
|
|
||||||
|
|
||||||
if(addressed && nfcv_uidcmp(address, nfc_data->uid)) {
|
ctx->frame = payload;
|
||||||
FURI_LOG_D(TAG, "addressed command 0x%02X, but not for us:", command);
|
ctx->frame_length = payload_length;
|
||||||
FURI_LOG_D(
|
ctx->flags = ctx->frame[0];
|
||||||
TAG,
|
ctx->command = ctx->frame[1];
|
||||||
" dest: %02X%02X%02X%02X%02X%02X%02X%02X",
|
ctx->addressed = !(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) && (ctx->flags & RFAL_NFCV_REQ_FLAG_ADDRESS);
|
||||||
address[7],
|
ctx->advanced = (ctx->command >= 0xA0);
|
||||||
address[6],
|
ctx->address_offset = 2 + (ctx->advanced ? 1 : 0);
|
||||||
address[5],
|
ctx->payload_offset = ctx->address_offset + (ctx->addressed ? 8 : 0);
|
||||||
address[4],
|
ctx->response_flags = NfcVSendFlagsNormal;
|
||||||
address[3],
|
|
||||||
address[2],
|
/* first give control to the card specific protocol handler */
|
||||||
address[1],
|
if(nfcv_data->emu_protocol_filter != NULL) {
|
||||||
address[0]);
|
if(nfcv_data->emu_protocol_filter(tx_rx, nfc_data, nfcv_data)) {
|
||||||
FURI_LOG_D(
|
|
||||||
TAG,
|
|
||||||
" our UID: %02X%02X%02X%02X%02X%02X%02X%02X",
|
|
||||||
nfc_data->uid[0],
|
|
||||||
nfc_data->uid[1],
|
|
||||||
nfc_data->uid[2],
|
|
||||||
nfc_data->uid[3],
|
|
||||||
nfc_data->uid[4],
|
|
||||||
nfc_data->uid[5],
|
|
||||||
nfc_data->uid[6],
|
|
||||||
nfc_data->uid[7]);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch(nfcv_data->type) {
|
if(ctx->addressed) {
|
||||||
case NfcVTypeSlixL:
|
uint8_t* address = &ctx->frame[ctx->address_offset];
|
||||||
if(nfcv_data->sub_data.slix_l.privacy && command != ISO15693_CMD_NXP_GET_RANDOM_NUMBER &&
|
if(nfcv_uidcmp(address, nfc_data->uid)) {
|
||||||
command != ISO15693_CMD_NXP_SET_PASSWORD) {
|
FURI_LOG_D(TAG, "addressed command 0x%02X, but not for us:", ctx->command);
|
||||||
snprintf(
|
FURI_LOG_D(TAG, " dest: %02X%02X%02X%02X%02X%02X%02X%02X", address[7], address[6], address[5], address[4], address[3], address[2], address[1], address[0]);
|
||||||
nfcv_data->last_command,
|
FURI_LOG_D(TAG, " our UID: %02X%02X%02X%02X%02X%02X%02X%02X", nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3], nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], nfc_data->uid[7]);
|
||||||
sizeof(nfcv_data->last_command),
|
|
||||||
"command 0x%02X ignored, privacy mode",
|
|
||||||
command);
|
|
||||||
FURI_LOG_D(TAG, "%s", nfcv_data->last_command);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unfortunately our response is quicker than the original NFC tag which causes frame misses */
|
/* unfortunately our response is quicker than the original NFC tag which causes frame misses */
|
||||||
furi_delay_us(270);
|
furi_delay_us(270);
|
||||||
|
|
||||||
switch(command) {
|
switch(ctx->command) {
|
||||||
case ISO15693_INVENTORY: {
|
case ISO15693_INVENTORY: {
|
||||||
response_buffer[0] = ISO15693_NOERROR;
|
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||||
response_buffer[1] = nfcv_data->dsfid;
|
ctx->response_buffer[1] = nfcv_data->dsfid;
|
||||||
nfcv_uidcpy(&response_buffer[2], nfc_data->uid);
|
nfcv_uidcpy(&ctx->response_buffer[2], nfc_data->uid);
|
||||||
|
|
||||||
nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 10, response_flags);
|
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 10, ctx->response_flags);
|
||||||
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY");
|
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -439,54 +380,77 @@ void nfcv_emu_handle_packet(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ISO15693_READ_MULTI_BLOCK: {
|
|
||||||
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ_MULTI_BLOCK");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ISO15693_WRITE_MULTI_BLOCK: {
|
|
||||||
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE_MULTI_BLOCK");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ISO15693_SELECT: {
|
case ISO15693_SELECT: {
|
||||||
response_buffer[0] = ISO15693_NOERROR;
|
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||||
nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 1, response_flags);
|
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags);
|
||||||
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SELECT");
|
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SELECT");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ISO15693_READ_MULTI_BLOCK:
|
||||||
case ISO15693_READBLOCK: {
|
case ISO15693_READBLOCK: {
|
||||||
uint8_t block = payload[payload_offset];
|
uint8_t block = ctx->frame[ctx->payload_offset];
|
||||||
|
uint8_t blocks = 1;
|
||||||
|
|
||||||
if(block >= nfcv_data->block_num) {
|
if(ctx->command == ISO15693_READ_MULTI_BLOCK) {
|
||||||
response_buffer[0] = ISO15693_ERROR_BLOCK_WRITE;
|
blocks = ctx->frame[ctx->payload_offset + 1] + 1;
|
||||||
nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 1, response_flags);
|
}
|
||||||
|
|
||||||
|
if(block + blocks > nfcv_data->block_num) {
|
||||||
|
ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC;
|
||||||
|
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags);
|
||||||
} else {
|
} else {
|
||||||
response_buffer[0] = ISO15693_NOERROR;
|
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||||
memcpy(
|
memcpy(&ctx->response_buffer[1], &nfcv_data->data[nfcv_data->block_size * block], nfcv_data->block_size * blocks);
|
||||||
&response_buffer[1],
|
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1 + nfcv_data->block_size * blocks, ctx->response_flags);
|
||||||
&nfcv_data->data[nfcv_data->block_size * block],
|
|
||||||
nfcv_data->block_size);
|
|
||||||
nfcv_emu_send(
|
|
||||||
tx_rx, nfcv_data, response_buffer, 1 + nfcv_data->block_size, response_flags);
|
|
||||||
}
|
}
|
||||||
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ BLOCK %d", block);
|
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ BLOCK %d", block);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ISO15693_WRITE_MULTI_BLOCK:
|
||||||
case ISO15693_WRITEBLOCK: {
|
case ISO15693_WRITEBLOCK: {
|
||||||
uint8_t block = payload[payload_offset];
|
uint8_t block = ctx->frame[ctx->payload_offset];
|
||||||
uint8_t* data = &payload[payload_offset + 1];
|
uint8_t blocks = 1;
|
||||||
|
uint8_t data_pos = 1;
|
||||||
|
|
||||||
if(block >= nfcv_data->block_num) {
|
if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) {
|
||||||
response_buffer[0] = ISO15693_ERROR_BLOCK_WRITE;
|
blocks = ctx->frame[ctx->payload_offset + 1] + 1;
|
||||||
|
data_pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *data = &ctx->frame[ctx->payload_offset + data_pos];
|
||||||
|
uint32_t data_len = nfcv_data->block_size * blocks;
|
||||||
|
|
||||||
|
if(block + blocks > nfcv_data->block_num || ctx->payload_offset + data_len + 2 > payload_length) {
|
||||||
|
ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC;
|
||||||
} else {
|
} else {
|
||||||
response_buffer[0] = ISO15693_NOERROR;
|
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||||
memcpy(
|
memcpy(&nfcv_data->data[nfcv_data->block_size * block], &ctx->frame[ctx->payload_offset + data_pos], data_len);
|
||||||
&nfcv_data->data[nfcv_data->block_size * block],
|
}
|
||||||
&response_buffer[1],
|
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags);
|
||||||
nfcv_data->block_size);
|
|
||||||
|
if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) {
|
||||||
|
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE MULTI BLOCK %d, %d blocks", block, blocks);
|
||||||
|
} else {
|
||||||
|
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE BLOCK %d <- %02X %02X %02X %02X", block, data[0], data[1], data[2], data[3]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ISO15693_GET_SYSTEM_INFO: {
|
||||||
|
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||||
|
ctx->response_buffer[1] = 0x0F;
|
||||||
|
nfcv_uidcpy(&ctx->response_buffer[2], nfc_data->uid);
|
||||||
|
ctx->response_buffer[10] = nfcv_data->dsfid; /* DSFID */
|
||||||
|
ctx->response_buffer[11] = nfcv_data->afi; /* AFI */
|
||||||
|
ctx->response_buffer[12] = nfcv_data->block_num - 1; /* number of blocks */
|
||||||
|
ctx->response_buffer[13] = nfcv_data->block_size - 1; /* block size */
|
||||||
|
ctx->response_buffer[14] = nfcv_data->ic_ref; /* IC reference */
|
||||||
|
|
||||||
|
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 15, ctx->response_flags);
|
||||||
|
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SYSTEMINFO");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 1, response_flags);
|
nfcv_emu_send(tx_rx, nfcv_data, response_buffer, 1, response_flags);
|
||||||
snprintf(
|
snprintf(
|
||||||
@@ -553,6 +517,7 @@ void nfcv_emu_handle_packet(
|
|||||||
password = nfcv_data->sub_data.slix_l.key_eas;
|
password = nfcv_data->sub_data.slix_l.key_eas;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "unsupported: %02X", ctx->command);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +585,8 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
|
|||||||
|
|
||||||
furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc);
|
furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc);
|
||||||
|
|
||||||
|
nfcv_data->emu_protocol_handler = &nfcv_emu_handle_packet;
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Starting NfcV emulation");
|
FURI_LOG_D(TAG, "Starting NfcV emulation");
|
||||||
FURI_LOG_D(
|
FURI_LOG_D(
|
||||||
TAG,
|
TAG,
|
||||||
@@ -636,39 +603,32 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
|
|||||||
switch(nfcv_data->type) {
|
switch(nfcv_data->type) {
|
||||||
case NfcVTypeSlixL:
|
case NfcVTypeSlixL:
|
||||||
FURI_LOG_D(TAG, " Card type: SLIX-L");
|
FURI_LOG_D(TAG, " Card type: SLIX-L");
|
||||||
FURI_LOG_D(
|
slix_l_prepare(nfcv_data);
|
||||||
TAG,
|
|
||||||
" Privacy pass: 0x%08lX",
|
|
||||||
nfcv_read_be(nfcv_data->sub_data.slix_l.key_privacy, 4));
|
|
||||||
FURI_LOG_D(
|
|
||||||
TAG,
|
|
||||||
" Destroy pass: 0x%08lX",
|
|
||||||
nfcv_read_be(nfcv_data->sub_data.slix_l.key_destroy, 4));
|
|
||||||
FURI_LOG_D(
|
|
||||||
TAG, " EAS pass: 0x%08lX", nfcv_read_be(nfcv_data->sub_data.slix_l.key_eas, 4));
|
|
||||||
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix_l.privacy ? "ON" : "OFF");
|
|
||||||
break;
|
break;
|
||||||
case NfcVTypeSlixS:
|
case NfcVTypeSlixS:
|
||||||
FURI_LOG_D(TAG, " Card type: SLIX-S");
|
FURI_LOG_D(TAG, " Card type: SLIX-S");
|
||||||
|
slix_s_prepare(nfcv_data);
|
||||||
break;
|
break;
|
||||||
case NfcVTypeSlix2:
|
case NfcVTypeSlix2:
|
||||||
FURI_LOG_D(TAG, " Card type: SLIX2");
|
FURI_LOG_D(TAG, " Card type: SLIX2");
|
||||||
|
slix2_prepare(nfcv_data);
|
||||||
|
break;
|
||||||
|
case NfcVTypeSlix:
|
||||||
|
FURI_LOG_D(TAG, " Card type: SLIX");
|
||||||
|
slix_prepare(nfcv_data);
|
||||||
break;
|
break;
|
||||||
case NfcVTypePlain:
|
case NfcVTypePlain:
|
||||||
FURI_LOG_D(TAG, " Card type: Plain");
|
FURI_LOG_D(TAG, " Card type: Plain");
|
||||||
break;
|
break;
|
||||||
case NfcVTypeSlix:
|
|
||||||
FURI_LOG_D(TAG, " Card type: SLIX-L");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate a 512 edge buffer, more than enough */
|
/* allocate a 512 edge buffer, more than enough */
|
||||||
nfcv_data->emulation.reader_signal = pulse_reader_alloc(&gpio_spi_r_miso, 512);
|
nfcv_data->emu_air.reader_signal = pulse_reader_alloc(&gpio_spi_r_miso, 512);
|
||||||
/* timebase shall be 1 ns */
|
/* timebase shall be 1 ns */
|
||||||
pulse_reader_set_timebase(nfcv_data->emulation.reader_signal, PulseReaderUnitNanosecond);
|
pulse_reader_set_timebase(nfcv_data->emu_air.reader_signal, PulseReaderUnitNanosecond);
|
||||||
/* and configure to already calculate the number of bits */
|
/* and configure to already calculate the number of bits */
|
||||||
pulse_reader_set_bittime(nfcv_data->emulation.reader_signal, PULSE_DURATION_NS);
|
pulse_reader_set_bittime(nfcv_data->emu_air.reader_signal, PULSE_DURATION_NS);
|
||||||
pulse_reader_start(nfcv_data->emulation.reader_signal);
|
pulse_reader_start(nfcv_data->emu_air.reader_signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfcv_emu_deinit(NfcVData* nfcv_data) {
|
void nfcv_emu_deinit(NfcVData* nfcv_data) {
|
||||||
@@ -676,7 +636,7 @@ void nfcv_emu_deinit(NfcVData* nfcv_data) {
|
|||||||
rfal_platform_spi_release();
|
rfal_platform_spi_release();
|
||||||
nfcv_emu_free(nfcv_data);
|
nfcv_emu_free(nfcv_data);
|
||||||
|
|
||||||
pulse_reader_free(nfcv_data->emulation.reader_signal);
|
pulse_reader_free(nfcv_data->emu_air.reader_signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfcv_emu_loop(
|
bool nfcv_emu_loop(
|
||||||
@@ -695,8 +655,8 @@ bool nfcv_emu_loop(
|
|||||||
bool wait_for_pulse = false;
|
bool wait_for_pulse = false;
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
uint32_t periods =
|
|
||||||
pulse_reader_receive(nfcv_data->emulation.reader_signal, timeout_ms * 1000);
|
uint32_t periods = pulse_reader_receive(nfcv_data->emu_air.reader_signal, timeout_ms * 1000);
|
||||||
|
|
||||||
if(periods == PULSE_READER_NO_EDGE) {
|
if(periods == PULSE_READER_NO_EDGE) {
|
||||||
break;
|
break;
|
||||||
@@ -844,12 +804,12 @@ bool nfcv_emu_loop(
|
|||||||
|
|
||||||
if(frame_state == NFCV_FRAME_STATE_EOF) {
|
if(frame_state == NFCV_FRAME_STATE_EOF) {
|
||||||
/* we know that this code uses TIM2, so stop pulse reader */
|
/* we know that this code uses TIM2, so stop pulse reader */
|
||||||
pulse_reader_stop(nfcv_data->emulation.reader_signal);
|
pulse_reader_stop(nfcv_data->emu_air.reader_signal);
|
||||||
if(tx_rx->sniff_rx) {
|
if(tx_rx->sniff_rx) {
|
||||||
tx_rx->sniff_rx(frame_payload, frame_pos * 8, false, tx_rx->sniff_context);
|
tx_rx->sniff_rx(frame_payload, frame_pos * 8, false, tx_rx->sniff_context);
|
||||||
}
|
}
|
||||||
nfcv_emu_handle_packet(tx_rx, nfc_data, nfcv_data, frame_payload, frame_pos);
|
nfcv_data->emu_protocol_handler(tx_rx, nfc_data, nfcv_data, frame_payload, frame_pos);
|
||||||
pulse_reader_start(nfcv_data->emulation.reader_signal);
|
pulse_reader_start(nfcv_data->emu_air.reader_signal);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
#define NFCV_SIG_BIT1 2
|
#define NFCV_SIG_BIT1 2
|
||||||
#define NFCV_SIG_EOF 3
|
#define NFCV_SIG_EOF 3
|
||||||
|
|
||||||
/* */
|
/* ISO15693 command codes */
|
||||||
#define ISO15693_INVENTORY 0x01
|
#define ISO15693_INVENTORY 0x01
|
||||||
#define ISO15693_STAYQUIET 0x02
|
#define ISO15693_STAYQUIET 0x02
|
||||||
#define ISO15693_READBLOCK 0x20
|
#define ISO15693_READBLOCK 0x20
|
||||||
@@ -50,25 +50,7 @@
|
|||||||
#define ISO15693_GET_SYSTEM_INFO 0x2B
|
#define ISO15693_GET_SYSTEM_INFO 0x2B
|
||||||
#define ISO15693_READ_MULTI_SECSTATUS 0x2C
|
#define ISO15693_READ_MULTI_SECSTATUS 0x2C
|
||||||
|
|
||||||
// ISO15693 MANUFACTURER CODES
|
/* ISO15693 RESPONSE ERROR CODES */
|
||||||
#define ISO15693_MANUFACTURER_NXP 0x04
|
|
||||||
|
|
||||||
// ISO15693-3 CUSTOM NXP COMMANDS
|
|
||||||
#define ISO15693_CMD_NXP_SET_EAS 0xA2
|
|
||||||
#define ISO15693_CMD_NXP_RESET_EAS 0xA3
|
|
||||||
#define ISO15693_CMD_NXP_LOCK_EAS 0xA4
|
|
||||||
#define ISO15693_CMD_NXP_EAS_ALARM 0xA5
|
|
||||||
#define ISO15693_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6
|
|
||||||
#define ISO15693_CMD_NXP_WRITE_EAS_ID 0xA7
|
|
||||||
#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ 0xB0
|
|
||||||
#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1
|
|
||||||
#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2
|
|
||||||
#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3
|
|
||||||
#define ISO15693_CMD_NXP_WRITE_PASSWORD 0xB4
|
|
||||||
#define ISO15693_CMD_NXP_DESTROY 0xB9
|
|
||||||
#define ISO15693_CMD_NXP_ENABLE_PRIVACY 0xBA
|
|
||||||
|
|
||||||
// ISO15693 RESPONSE ERROR CODES
|
|
||||||
#define ISO15693_NOERROR 0x00
|
#define ISO15693_NOERROR 0x00
|
||||||
#define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported
|
#define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported
|
||||||
#define ISO15693_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error)
|
#define ISO15693_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error)
|
||||||
@@ -93,11 +75,6 @@ typedef enum {
|
|||||||
NfcVTypeSlix2 = 4,
|
NfcVTypeSlix2 = 4,
|
||||||
} NfcVType;
|
} NfcVType;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t key_eas[4];
|
|
||||||
uint8_t rand[2];
|
|
||||||
} NfcVSlixData;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NfcVSendFlagsNormal = 0,
|
NfcVSendFlagsNormal = 0,
|
||||||
NfcVSendFlagsSof = 1 << 0,
|
NfcVSendFlagsSof = 1 << 0,
|
||||||
@@ -117,31 +94,10 @@ typedef struct {
|
|||||||
uint8_t key_eas[4];
|
uint8_t key_eas[4];
|
||||||
uint8_t rand[2];
|
uint8_t rand[2];
|
||||||
bool privacy;
|
bool privacy;
|
||||||
} NfcVSlix2Data;
|
} NfcVSlixData;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t key_read[4];
|
|
||||||
uint8_t key_write[4];
|
|
||||||
uint8_t key_privacy[4];
|
|
||||||
uint8_t key_destroy[4];
|
|
||||||
uint8_t key_eas[4];
|
|
||||||
uint8_t rand[2];
|
|
||||||
bool privacy;
|
|
||||||
} NfcVSlixSData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t key_privacy[4];
|
|
||||||
uint8_t key_destroy[4];
|
|
||||||
uint8_t key_eas[4];
|
|
||||||
uint8_t rand[2];
|
|
||||||
bool privacy;
|
|
||||||
} NfcVSlixLData;
|
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
NfcVSlixData slix;
|
NfcVSlixData slix;
|
||||||
NfcVSlix2Data slix2;
|
|
||||||
NfcVSlixSData slix_s;
|
|
||||||
NfcVSlixLData slix_l;
|
|
||||||
} NfcVSubtypeData;
|
} NfcVSubtypeData;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -155,7 +111,26 @@ typedef struct {
|
|||||||
DigitalSignal* nfcv_resp_unmod_256;
|
DigitalSignal* nfcv_resp_unmod_256;
|
||||||
DigitalSignal* nfcv_resp_unmod_768;
|
DigitalSignal* nfcv_resp_unmod_768;
|
||||||
DigitalSequence* nfcv_signal;
|
DigitalSequence* nfcv_signal;
|
||||||
} NfcVEmuData;
|
} NfcVEmuAir;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t* frame; /* ISO15693-2 incoming raw data from air layer */
|
||||||
|
uint8_t frame_length; /* ISO15693-2 length of incoming data */
|
||||||
|
|
||||||
|
uint8_t flags; /* ISO15693-3 flags of the header as specified */
|
||||||
|
uint8_t command; /* ISO15693-3 command at offset 1 as specified */
|
||||||
|
bool addressed; /* ISO15693-3 flags: addressed frame */
|
||||||
|
bool advanced; /* ISO15693-3 command: advanced command */
|
||||||
|
uint8_t address_offset; /* ISO15693-3 offset of the address in frame, if addressed is set */
|
||||||
|
uint8_t payload_offset; /* ISO15693-3 offset of the payload in frame */
|
||||||
|
|
||||||
|
uint8_t response_buffer[128]; /* pre-allocated response buffer */
|
||||||
|
NfcVSendFlags response_flags; /* flags to use when sending response */
|
||||||
|
} NfcVEmuProtocolCtx;
|
||||||
|
|
||||||
|
typedef void (*NfcVEmuProtocolHandler) (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data, uint8_t* payload, uint32_t payload_length);
|
||||||
|
typedef bool (*NfcVEmuProtocolFilter) (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* common ISO15693 fields */
|
/* common ISO15693 fields */
|
||||||
@@ -169,7 +144,10 @@ typedef struct {
|
|||||||
/* specfic variant infos */
|
/* specfic variant infos */
|
||||||
NfcVType type;
|
NfcVType type;
|
||||||
NfcVSubtypeData sub_data;
|
NfcVSubtypeData sub_data;
|
||||||
NfcVEmuData emulation;
|
NfcVEmuAir emu_air;
|
||||||
|
NfcVEmuProtocolCtx emu_protocol_ctx;
|
||||||
|
NfcVEmuProtocolHandler emu_protocol_handler;
|
||||||
|
NfcVEmuProtocolFilter emu_protocol_filter;
|
||||||
|
|
||||||
/* runtime data */
|
/* runtime data */
|
||||||
char last_command[128];
|
char last_command[128];
|
||||||
@@ -190,8 +168,6 @@ bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* d
|
|||||||
|
|
||||||
void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data);
|
void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data);
|
||||||
void nfcv_emu_deinit(NfcVData* nfcv_data);
|
void nfcv_emu_deinit(NfcVData* nfcv_data);
|
||||||
bool nfcv_emu_loop(
|
|
||||||
FuriHalNfcTxRxContext* tx_rx,
|
bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t timeout_ms);
|
||||||
FuriHalNfcDevData* nfc_data,
|
void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* data, uint8_t length, NfcVSendFlags flags);
|
||||||
NfcVData* nfcv_data,
|
|
||||||
uint32_t timeout_ms);
|
|
||||||
|
|||||||
@@ -5,6 +5,20 @@
|
|||||||
#include "nfc_util.h"
|
#include "nfc_util.h"
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include "furi_hal_nfc.h"
|
#include "furi_hal_nfc.h"
|
||||||
|
#include <furi_hal_random.h>
|
||||||
|
|
||||||
|
#define TAG "SLIX"
|
||||||
|
|
||||||
|
static uint32_t slix_read_be(uint8_t *data, uint32_t length) {
|
||||||
|
uint32_t value = 0;
|
||||||
|
|
||||||
|
for(uint32_t pos = 0; pos < length; pos++) {
|
||||||
|
value <<= 8;
|
||||||
|
value |= data[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t slix_get_ti(FuriHalNfcDevData* nfc_data) {
|
uint8_t slix_get_ti(FuriHalNfcDevData* nfc_data) {
|
||||||
return (nfc_data->uid[3] >> 3) & 3;
|
return (nfc_data->uid[3] >> 3) & 3;
|
||||||
@@ -40,7 +54,7 @@ bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode slix_l_get_random(NfcVData* data) {
|
ReturnCode slix_get_random(NfcVData* data) {
|
||||||
uint16_t received = 0;
|
uint16_t received = 0;
|
||||||
uint8_t rxBuf[32];
|
uint8_t rxBuf[32];
|
||||||
|
|
||||||
@@ -60,36 +74,43 @@ ReturnCode slix_l_get_random(NfcVData* data) {
|
|||||||
return ERR_PROTO;
|
return ERR_PROTO;
|
||||||
}
|
}
|
||||||
if(data != NULL) {
|
if(data != NULL) {
|
||||||
data->sub_data.slix_l.rand[0] = rxBuf[2];
|
data->sub_data.slix.rand[0] = rxBuf[2];
|
||||||
data->sub_data.slix_l.rand[1] = rxBuf[1];
|
data->sub_data.slix.rand[1] = rxBuf[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode slix_l_unlock(NfcVData* data, uint32_t password_id) {
|
ReturnCode slix_unlock(NfcVData* data, uint32_t password_id) {
|
||||||
furi_assert(rand);
|
furi_assert(rand);
|
||||||
|
|
||||||
uint16_t received = 0;
|
uint16_t received = 0;
|
||||||
uint8_t rxBuf[32];
|
uint8_t rxBuf[32];
|
||||||
uint8_t cmd_set_pass[] = {
|
uint8_t cmd_set_pass[] = {
|
||||||
password_id,
|
password_id,
|
||||||
data->sub_data.slix_l.rand[1],
|
data->sub_data.slix.rand[1],
|
||||||
data->sub_data.slix_l.rand[0],
|
data->sub_data.slix.rand[0],
|
||||||
data->sub_data.slix_l.rand[1],
|
data->sub_data.slix.rand[1],
|
||||||
data->sub_data.slix_l.rand[0]};
|
data->sub_data.slix.rand[0]
|
||||||
uint8_t* password = NULL;
|
};
|
||||||
|
uint8_t *password = NULL;
|
||||||
|
|
||||||
switch(password_id) {
|
switch(password_id) {
|
||||||
case 4:
|
case SLIX_PASS_READ:
|
||||||
password = data->sub_data.slix_l.key_privacy;
|
password = data->sub_data.slix.key_read;
|
||||||
break;
|
break;
|
||||||
case 8:
|
case SLIX_PASS_WRITE:
|
||||||
password = data->sub_data.slix_l.key_destroy;
|
password = data->sub_data.slix.key_write;
|
||||||
break;
|
break;
|
||||||
case 10:
|
case SLIX_PASS_PRIVACY:
|
||||||
password = data->sub_data.slix_l.key_eas;
|
password = data->sub_data.slix.key_privacy;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_DESTROY:
|
||||||
|
password = data->sub_data.slix.key_destroy;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_EASAFI:
|
||||||
|
password = data->sub_data.slix.key_eas;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -116,3 +137,221 @@ ReturnCode slix_l_unlock(NfcVData* data, uint32_t password_id) {
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool slix_generic_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in, uint32_t password_supported) {
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
furi_assert(nfc_data);
|
||||||
|
furi_assert(nfcv_data_in);
|
||||||
|
|
||||||
|
NfcVData* nfcv_data = (NfcVData*)nfcv_data_in;
|
||||||
|
NfcVEmuProtocolCtx* ctx = &nfcv_data->emu_protocol_ctx;
|
||||||
|
NfcVSlixData* slix = &nfcv_data->sub_data.slix;
|
||||||
|
|
||||||
|
if(slix->privacy &&
|
||||||
|
ctx->command != ISO15693_CMD_NXP_GET_RANDOM_NUMBER &&
|
||||||
|
ctx->command != ISO15693_CMD_NXP_SET_PASSWORD) {
|
||||||
|
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command),
|
||||||
|
"command 0x%02X ignored, privacy mode", ctx->command);
|
||||||
|
FURI_LOG_D(TAG, "%s", nfcv_data->last_command);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
switch(ctx->command) {
|
||||||
|
case ISO15693_CMD_NXP_GET_RANDOM_NUMBER: {
|
||||||
|
slix->rand[0] = furi_hal_random_get();
|
||||||
|
slix->rand[1] = furi_hal_random_get();
|
||||||
|
|
||||||
|
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||||
|
ctx->response_buffer[1] = slix->rand[1];
|
||||||
|
ctx->response_buffer[2] = slix->rand[0];
|
||||||
|
|
||||||
|
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 3, ctx->response_flags);
|
||||||
|
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command),
|
||||||
|
"GET_RANDOM_NUMBER -> 0x%02X%02X", slix->rand[0], slix->rand[1]);
|
||||||
|
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ISO15693_CMD_NXP_SET_PASSWORD: {
|
||||||
|
uint8_t password_id = ctx->frame[ctx->payload_offset];
|
||||||
|
|
||||||
|
if(!(password_id & password_supported)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *password_xored = &ctx->frame[ctx->payload_offset + 1];
|
||||||
|
uint8_t *rand = slix->rand;
|
||||||
|
uint8_t *password = NULL;
|
||||||
|
uint8_t password_rcv[4];
|
||||||
|
|
||||||
|
switch(password_id) {
|
||||||
|
case SLIX_PASS_READ:
|
||||||
|
password = slix->key_read;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_WRITE:
|
||||||
|
password = slix->key_write;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_PRIVACY:
|
||||||
|
password = slix->key_privacy;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_DESTROY:
|
||||||
|
password = slix->key_destroy;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_EASAFI:
|
||||||
|
password = slix->key_eas;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int pos = 0; pos < 4; pos++) {
|
||||||
|
password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2];
|
||||||
|
}
|
||||||
|
uint32_t pass_expect = slix_read_be(password, 4);
|
||||||
|
uint32_t pass_received = slix_read_be(password_rcv, 4);
|
||||||
|
|
||||||
|
/* if the password is all-zeroes, just accept any password*/
|
||||||
|
if(!pass_expect || pass_expect == pass_received) {
|
||||||
|
switch(password_id) {
|
||||||
|
case SLIX_PASS_READ:
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_WRITE:
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_PRIVACY:
|
||||||
|
slix->privacy = false;
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_DESTROY:
|
||||||
|
FURI_LOG_D(TAG, "Pooof! Got destroyed");
|
||||||
|
break;
|
||||||
|
case SLIX_PASS_EASAFI:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||||
|
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags);
|
||||||
|
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command),
|
||||||
|
"SET_PASSWORD #%02X 0x%08lX OK", password_id, pass_received);
|
||||||
|
} else {
|
||||||
|
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command),
|
||||||
|
"SET_PASSWORD #%02X 0x%08lX/%08lX FAIL", password_id, pass_received, pass_expect);
|
||||||
|
}
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ISO15693_CMD_NXP_ENABLE_PRIVACY: {
|
||||||
|
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||||
|
|
||||||
|
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags);
|
||||||
|
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command),
|
||||||
|
"ISO15693_CMD_NXP_ENABLE_PRIVACY");
|
||||||
|
|
||||||
|
slix->privacy = true;
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix_l_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) {
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
furi_assert(nfc_data);
|
||||||
|
furi_assert(nfcv_data_in);
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
/* many SLIX share some of the functions, place that in a generic handler */
|
||||||
|
if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void slix_l_prepare(NfcVData* nfcv_data) {
|
||||||
|
FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
|
||||||
|
FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
|
||||||
|
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
|
||||||
|
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
|
||||||
|
|
||||||
|
nfcv_data->emu_protocol_filter = &slix_l_protocol_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix_s_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) {
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
furi_assert(nfc_data);
|
||||||
|
furi_assert(nfcv_data_in);
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
/* many SLIX share some of the functions, place that in a generic handler */
|
||||||
|
if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void slix_s_prepare(NfcVData* nfcv_data) {
|
||||||
|
FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
|
||||||
|
FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
|
||||||
|
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
|
||||||
|
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
|
||||||
|
|
||||||
|
nfcv_data->emu_protocol_filter = &slix_s_protocol_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) {
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
furi_assert(nfc_data);
|
||||||
|
furi_assert(nfcv_data_in);
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
/* many SLIX share some of the functions, place that in a generic handler */
|
||||||
|
if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_EASAFI)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void slix_prepare(NfcVData* nfcv_data) {
|
||||||
|
FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
|
||||||
|
FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
|
||||||
|
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
|
||||||
|
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
|
||||||
|
|
||||||
|
nfcv_data->emu_protocol_filter = &slix_protocol_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slix2_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) {
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
furi_assert(nfc_data);
|
||||||
|
furi_assert(nfcv_data_in);
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
/* many SLIX share some of the functions, place that in a generic handler */
|
||||||
|
if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void slix2_prepare(NfcVData* nfcv_data) {
|
||||||
|
FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
|
||||||
|
FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
|
||||||
|
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
|
||||||
|
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
|
||||||
|
|
||||||
|
nfcv_data->emu_protocol_filter = &slix2_protocol_filter;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,13 +5,41 @@
|
|||||||
#include "nfc_util.h"
|
#include "nfc_util.h"
|
||||||
#include <furi_hal_nfc.h>
|
#include <furi_hal_nfc.h>
|
||||||
|
|
||||||
|
#define ISO15693_MANUFACTURER_NXP 0x04
|
||||||
|
|
||||||
|
/* ISO15693-3 CUSTOM NXP COMMANDS */
|
||||||
|
#define ISO15693_CMD_NXP_SET_EAS 0xA2
|
||||||
|
#define ISO15693_CMD_NXP_RESET_EAS 0xA3
|
||||||
|
#define ISO15693_CMD_NXP_LOCK_EAS 0xA4
|
||||||
|
#define ISO15693_CMD_NXP_EAS_ALARM 0xA5
|
||||||
|
#define ISO15693_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6
|
||||||
|
#define ISO15693_CMD_NXP_WRITE_EAS_ID 0xA7
|
||||||
|
#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ 0xB0
|
||||||
|
#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1
|
||||||
#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2
|
#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2
|
||||||
#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3
|
#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3
|
||||||
#define ISO15693_MANUFACTURER_NXP 0x04
|
#define ISO15693_CMD_NXP_WRITE_PASSWORD 0xB4
|
||||||
|
#define ISO15693_CMD_NXP_DESTROY 0xB9
|
||||||
|
#define ISO15693_CMD_NXP_ENABLE_PRIVACY 0xBA
|
||||||
|
|
||||||
|
/* available passwords */
|
||||||
|
#define SLIX_PASS_READ 0x01
|
||||||
|
#define SLIX_PASS_WRITE 0x02
|
||||||
|
#define SLIX_PASS_PRIVACY 0x04
|
||||||
|
#define SLIX_PASS_DESTROY 0x08
|
||||||
|
#define SLIX_PASS_EASAFI 0x10
|
||||||
|
|
||||||
|
#define SLIX_PASS_ALL (SLIX_PASS_READ|SLIX_PASS_WRITE|SLIX_PASS_PRIVACY|SLIX_PASS_DESTROY|SLIX_PASS_EASAFI)
|
||||||
|
|
||||||
bool slix_check_card_type(FuriHalNfcDevData* nfc_data);
|
bool slix_check_card_type(FuriHalNfcDevData* nfc_data);
|
||||||
bool slix2_check_card_type(FuriHalNfcDevData* nfc_data);
|
bool slix2_check_card_type(FuriHalNfcDevData* nfc_data);
|
||||||
bool slix_s_check_card_type(FuriHalNfcDevData* nfc_data);
|
bool slix_s_check_card_type(FuriHalNfcDevData* nfc_data);
|
||||||
bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data);
|
bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data);
|
||||||
ReturnCode slix_l_get_random(NfcVData* data);
|
|
||||||
ReturnCode slix_l_unlock(NfcVData* data, uint32_t password_id);
|
ReturnCode slix_get_random(NfcVData* data);
|
||||||
|
ReturnCode slix_unlock(NfcVData* data, uint32_t password_id);
|
||||||
|
|
||||||
|
void slix_prepare(NfcVData* nfcv_data);
|
||||||
|
void slix_s_prepare(NfcVData* nfcv_data);
|
||||||
|
void slix_l_prepare(NfcVData* nfcv_data);
|
||||||
|
void slix2_prepare(NfcVData* nfcv_data);
|
||||||
|
|||||||
Reference in New Issue
Block a user