[FL-1526] Mifare Ultralight emulation (#645)

* rfal: add discovery parameter for passing listen activation
* nfc: add discovery parameter to furi_hal_nfc_listen
* mifare_ul: add emulation parsing commands
* nfc: add mifare ul emulation
* nfc: switch to mifare ultralight emulation form menu
* furi-hal-nfc: add first frame reception in emulation mode
* nfc: change argument check
* nfc: rework nfc worker and mifare ul lib
* mifare_ul: add write and cnt increment commands
* nfc: add card modification check
* mifare_ul: add data changed flag
* nfc: add shodow files
* nfc: add restore original file

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
gornekich 2021-08-17 00:45:04 +03:00 committed by GitHub
parent e1d80d5402
commit c122317468
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 354 additions and 69 deletions

View file

@ -151,9 +151,10 @@ void nfc_text_store_clear(Nfc* nfc) {
int32_t nfc_app(void* p) {
Nfc* nfc = nfc_alloc();
char* args = p;
// Check argument and run corresponding scene
if(p && nfc_device_load(&nfc->dev, p)) {
if((*args != '\0') && nfc_device_load(&nfc->dev, p)) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneStart);

View file

@ -64,7 +64,7 @@ void nfc_cli_emulate(Cli* cli, string_t args, void* context) {
};
while(!cli_cmd_interrupt_received(cli)) {
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, 100)) {
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) {
printf("Reader detected\r\n");
furi_hal_nfc_deactivate();
}

View file

@ -8,6 +8,7 @@
static const char* nfc_app_folder = "/any/nfc";
static const char* nfc_app_extension = ".nfc";
static const char* nfc_app_shadow_extension = ".shd";
static bool nfc_device_read_hex(string_t str, uint8_t* buff, uint16_t len) {
string_strim(str);
@ -259,7 +260,11 @@ void nfc_device_set_name(NfcDevice* dev, const char* name) {
strlcpy(dev->dev_name, name, NFC_DEV_NAME_MAX_LEN);
}
bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
static bool nfc_device_save_file(
NfcDevice* dev,
const char* dev_name,
const char* folder,
const char* extension) {
furi_assert(dev);
FileWorker* file_worker = file_worker_alloc(false);
@ -275,7 +280,7 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
break;
};
// First remove nfc device file if it was saved
string_printf(dev_file_name, "%s/%s%s", nfc_app_folder, dev_name, nfc_app_extension);
string_printf(dev_file_name, "%s/%s%s", folder, dev_name, extension);
if(!file_worker_remove(file_worker, string_get_cstr(dev_file_name))) {
break;
};
@ -316,16 +321,42 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
return true;
}
bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_extension);
}
bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) {
dev->shadow_file_exist = true;
return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_shadow_extension);
}
static bool nfc_device_load_data(FileWorker* file_worker, string_t path, NfcDevice* dev) {
string_t temp_string;
string_init(temp_string);
bool parsed = false;
do {
// Open key file
if(!file_worker_open(file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
// Check existance of shadow file
size_t ext_start = string_search_str(path, nfc_app_extension);
string_set_n(temp_string, path, 0, ext_start);
string_cat_printf(temp_string, "%s", nfc_app_shadow_extension);
if(!file_worker_is_file_exist(
file_worker, string_get_cstr(temp_string), &dev->shadow_file_exist)) {
break;
}
// Open shadow file if it exists. If not - open original
if(dev->shadow_file_exist) {
if(!file_worker_open(
file_worker, string_get_cstr(temp_string), FSAM_READ, FSOM_OPEN_EXISTING)) {
break;
}
} else {
if(!file_worker_open(
file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
break;
}
}
// Read and parse format from 1st line
if(!file_worker_read_until(file_worker, temp_string, '\n')) {
break;
@ -427,13 +458,61 @@ void nfc_device_clear(NfcDevice* dev) {
bool nfc_device_delete(NfcDevice* dev) {
furi_assert(dev);
bool result = false;
bool result = true;
FileWorker* file_worker = file_worker_alloc(false);
string_t file_path;
string_init_printf(file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension);
result = file_worker_remove(file_worker, string_get_cstr(file_path));
do {
// Delete original file
string_init_printf(file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension);
if(!file_worker_remove(file_worker, string_get_cstr(file_path))) {
result = false;
break;
}
// Delete shadow file if it exists
if(dev->shadow_file_exist) {
string_clean(file_path);
string_printf(
file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension);
if(!file_worker_remove(file_worker, string_get_cstr(file_path))) {
result = false;
break;
}
}
} while(0);
string_clear(file_path);
file_worker_close(file_worker);
file_worker_free(file_worker);
return result;
}
bool nfc_device_restore(NfcDevice* dev) {
furi_assert(dev);
furi_assert(dev->shadow_file_exist);
bool result = true;
FileWorker* file_worker = file_worker_alloc(false);
string_t path;
do {
string_init_printf(
path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension);
if(!file_worker_remove(file_worker, string_get_cstr(path))) {
result = false;
break;
}
dev->shadow_file_exist = false;
string_clean(path);
string_printf(path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension);
if(!nfc_device_load_data(file_worker, path, dev)) {
result = false;
break;
}
} while(0);
string_clear(path);
file_worker_close(file_worker);
file_worker_free(file_worker);
return result;
}

View file

@ -59,12 +59,15 @@ typedef struct {
char dev_name[NFC_DEV_NAME_MAX_LEN];
char file_name[NFC_FILE_NAME_MAX_LEN];
NfcDeviceSaveFormat format;
bool shadow_file_exist;
} NfcDevice;
void nfc_device_set_name(NfcDevice* dev, const char* name);
bool nfc_device_save(NfcDevice* dev, const char* dev_name);
bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name);
bool nfc_device_load(NfcDevice* dev, const char* file_path);
bool nfc_file_select(NfcDevice* dev);
@ -72,3 +75,5 @@ bool nfc_file_select(NfcDevice* dev);
void nfc_device_clear(NfcDevice* dev);
bool nfc_device_delete(NfcDevice* dev);
bool nfc_device_restore(NfcDevice* dev);

View file

@ -143,7 +143,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) {
void nfc_worker_emulate(NfcWorker* nfc_worker) {
NfcDeviceCommomData* data = &nfc_worker->dev_data->nfc_data;
while(nfc_worker->state == NfcWorkerStateEmulate) {
if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, 100)) {
if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) {
FURI_LOG_I(NFC_WORKER_TAG, "Reader detected");
}
osDelay(10);
@ -406,7 +406,7 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
0x00, 0x00};
while(nfc_worker->state == NfcWorkerStateEmulateApdu) {
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, 300)) {
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) {
FURI_LOG_I(NFC_WORKER_TAG, "POS terminal detected");
// Read data from POS terminal
err = furi_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false);
@ -608,33 +608,52 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
uint8_t* rx_buff;
uint16_t* rx_len;
NfcDeviceData* data = nfc_worker->dev_data;
MifareUlDevice mf_ul_emulate;
// Setup emulation parameters from mifare ultralight data structure
mf_ul_prepare_emulation(&mf_ul_emulate, &data->mf_ul_data);
while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
if(furi_hal_nfc_listen(
data->nfc_data.uid,
data->nfc_data.uid_len,
data->nfc_data.atqa,
data->nfc_data.sak,
1000)) {
FURI_LOG_I(NFC_WORKER_TAG, "Hello my dudes");
// Prepare version answer
tx_len = sizeof(data->mf_ul_data.version);
memcpy(tx_buff, &data->mf_ul_data.version, tx_len);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err == ERR_NONE) {
FURI_LOG_I(NFC_WORKER_TAG, "Received 1st message:");
for(uint16_t i = 0; i < *rx_len; i++) {
printf("%02X ", rx_buff[i]);
true,
200)) {
FURI_LOG_D(NFC_WORKER_TAG, "Anticollision passed");
if(furi_hal_nfc_get_first_frame(&rx_buff, &rx_len)) {
// Data exchange loop
while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
tx_len = mf_ul_prepare_emulation_response(
rx_buff, *rx_len, tx_buff, &mf_ul_emulate);
if(tx_len > 0) {
err =
furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err == ERR_NONE) {
continue;
} else {
FURI_LOG_E(NFC_WORKER_TAG, "Communication error: %d", err);
break;
}
} else {
FURI_LOG_W(NFC_WORKER_TAG, "Not valid command: %02X", rx_buff[0]);
furi_hal_nfc_deactivate();
break;
}
}
printf("\r\n");
} else {
FURI_LOG_E(NFC_WORKER_TAG, "Error in 1st data exchange: select PPSE");
FURI_LOG_W(NFC_WORKER_TAG, "Error in 1st data exchange");
furi_hal_nfc_deactivate();
continue;
}
}
FURI_LOG_W(NFC_WORKER_TAG, "Hello my dudes");
osDelay(10);
// Check if data was modified
if(mf_ul_emulate.data_changed) {
nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data;
if(nfc_worker->callback) {
nfc_worker->callback(nfc_worker->context);
}
}
FURI_LOG_W(NFC_WORKER_TAG, "Can't find reader");
osThreadYield();
}
}

View file

@ -26,3 +26,4 @@ ADD_SCENE(nfc, run_emv_app_confirm, RunEmvAppConfirm)
ADD_SCENE(nfc, read_emv_data, ReadEmvData)
ADD_SCENE(nfc, read_emv_data_success, ReadEmvDataSuccess)
ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence)
ADD_SCENE(nfc, restore_original, RestoreOriginal)

View file

@ -1,38 +1,33 @@
#include "../nfc_i.h"
#define NFC_MF_UL_DATA_NOT_CHANGED (0UL)
#define NFC_MF_UL_DATA_CHANGED (1UL)
void nfc_emulate_mifare_ul_worker_callback(void* context) {
Nfc* nfc = (Nfc*)context;
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED);
}
const void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
// Setup view
Popup* popup = nfc->popup;
NfcDeviceCommomData* data = &nfc->dev.dev_data.nfc_data;
if(strcmp(nfc->dev.dev_name, "")) {
nfc_text_store_set(nfc, "%s", nfc->dev.dev_name);
} else if(data->uid_len == 4) {
nfc_text_store_set(
nfc, "%02X %02X %02X %02X", data->uid[0], data->uid[1], data->uid[2], data->uid[3]);
} else if(data->uid_len == 7) {
nfc_text_store_set(
nfc,
"%02X %02X %02X %02X\n%02X %02X %02X",
data->uid[0],
data->uid[1],
data->uid[2],
data->uid[3],
data->uid[4],
data->uid[5],
data->uid[6]);
}
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
popup_set_header(popup, "Emulating Mf Ul", 56, 31, AlignLeft, AlignTop);
popup_set_text(popup, nfc->text_store, 56, 43, AlignLeft, AlignTop);
popup_set_header(popup, "Emulating\nMf Ultralight", 56, 31, AlignLeft, AlignTop);
// Setup and start worker
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
nfc_worker_start(nfc->worker, NfcWorkerStateEmulateMifareUl, &nfc->dev.dev_data, NULL, nfc);
nfc_worker_start(
nfc->worker,
NfcWorkerStateEmulateMifareUl,
&nfc->dev.dev_data,
nfc_emulate_mifare_ul_worker_callback,
nfc);
}
const bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) {
@ -42,6 +37,17 @@ const bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent
if(event.type == SceneManagerEventTypeTick) {
notification_message(nfc->notifications, &sequence_blink_blue_10);
consumed = true;
} else if(event.type == SceneManagerEventTypeBack) {
// Stop worker
nfc_worker_stop(nfc->worker);
// Check if data changed and save in shadow file
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateMifareUl) ==
NFC_MF_UL_DATA_CHANGED) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_NOT_CHANGED);
nfc_device_save_shadow(&nfc->dev, nfc->dev.dev_name);
}
consumed = false;
}
return consumed;
}
@ -49,9 +55,6 @@ const bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent
const void nfc_scene_emulate_mifare_ul_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
// Stop worker
nfc_worker_stop(nfc->worker);
// Clear view
Popup* popup = nfc->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);

View file

@ -38,7 +38,7 @@ const bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent ev
} else if(event.event == SubmenuIndexEmulate) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate);
scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented);
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
return true;
}
} else if(event.type == SceneManagerEventTypeBack) {

View file

@ -0,0 +1,48 @@
#include "../nfc_i.h"
#define SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT (0UL)
void nfc_scene_restore_original_popup_callback(void* context) {
Nfc* nfc = (Nfc*)context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT);
}
const void nfc_scene_restore_original_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
// Setup view
Popup* popup = nfc->popup;
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
popup_set_header(popup, "Original file\nrestored", 13, 22, AlignLeft, AlignBottom);
popup_set_timeout(popup, 1500);
popup_set_context(popup, nfc);
popup_set_callback(popup, nfc_scene_restore_original_popup_callback);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
}
const bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
}
}
return consumed;
}
const void nfc_scene_restore_original_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
// Clear view
Popup* popup = nfc->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_set_callback(popup, NULL);
popup_set_context(popup, NULL);
popup_set_timeout(popup, 0);
popup_disable_timeout(popup);
}

View file

@ -5,6 +5,7 @@ enum SubmenuIndex {
SubmenuIndexEdit,
SubmenuIndexDelete,
SubmenuIndexInfo,
SubmenuIndexRestoreOriginal,
};
void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) {
@ -29,36 +30,52 @@ const void nfc_scene_saved_menu_on_enter(void* context) {
submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc);
submenu_set_selected_item(
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu));
if(nfc->dev.shadow_file_exist) {
submenu_add_item(
submenu,
"Restore original",
SubmenuIndexRestoreOriginal,
nfc_scene_saved_menu_submenu_callback,
nfc);
}
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
}
const bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event);
if(event.event == SubmenuIndexEmulate) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexEmulate);
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
return true;
if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
}
consumed = true;
} else if(event.event == SubmenuIndexEdit) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexEdit);
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid);
return true;
consumed = true;
} else if(event.event == SubmenuIndexDelete) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexDelete);
scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete);
return true;
consumed = true;
} else if(event.event == SubmenuIndexInfo) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, SubmenuIndexInfo);
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo);
return true;
consumed = true;
} else if(event.event == SubmenuIndexRestoreOriginal) {
if(!nfc_device_restore(&nfc->dev)) {
scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart);
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginal);
}
consumed = true;
}
}
return false;
return consumed;
}
const void nfc_scene_saved_menu_on_exit(void* context) {

View file

@ -86,9 +86,8 @@ bool furi_hal_nfc_detect(rfalNfcDevice **dev_list, uint8_t* dev_cnt, uint32_t ti
return true;
}
bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak, uint32_t timeout) {
bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak, bool activate_after_sak, uint32_t timeout) {
rfalNfcState state = rfalNfcGetState();
if(state == RFAL_NFC_STATE_NOTINIT) {
rfalNfcInitialize();
} else if(state >= RFAL_NFC_STATE_ACTIVATED) {
@ -107,6 +106,7 @@ bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t s
.maxBR = RFAL_BR_KEEP,
.GBLen = RFAL_NFCDEP_GB_MAX_LEN,
.notifyCb = NULL,
.activate_after_sak = activate_after_sak,
};
params.lmConfigPA.nfcidLen = uid_len;
memcpy(params.lmConfigPA.nfcid, uid, uid_len);
@ -119,7 +119,6 @@ bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t s
while(state != RFAL_NFC_STATE_ACTIVATED) {
rfalNfcWorker();
state = rfalNfcGetState();
FURI_LOG_D("HAL NFC", "Current state %d", state);
if(DWT->CYCCNT - start > timeout * clocks_in_ms) {
rfalNfcDeactivate(true);
return false;
@ -129,6 +128,11 @@ bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t s
return true;
}
bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) {
ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0);
return ret == ERR_NONE;
}
ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t** rx_buff, uint16_t** rx_len, bool deactivate) {
furi_assert(rx_buff);
furi_assert(rx_len);
@ -144,7 +148,6 @@ ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t
rfalNfcWorker();
state = rfalNfcGetState();
ret = rfalNfcDataExchangeGetStatus();
FURI_LOG_D("HAL NFC", "Nfc st: %d Data st: %d", state, ret);
if(ret > ERR_SLEEP_REQ) {
return ret;
}

View file

@ -49,7 +49,12 @@ bool furi_hal_nfc_detect(rfalNfcDevice** dev_list, uint8_t* dev_cnt, uint32_t ti
/**
* NFC listen
*/
bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak, uint32_t timeout);
bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak, bool activate_after_sak, uint32_t timeout);
/**
* Get first command from reader after activation in emulation mode
*/
bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len);
/**
* NFC data exchange

View file

@ -213,6 +213,8 @@ typedef struct{
bool wakeupEnabled; /*!< Enable Wake-Up mode before polling */
bool wakeupConfigDefault; /*!< Wake-Up mode default configuration */
rfalWakeUpConfig wakeupConfig; /*!< Wake-Up mode configuration */
bool activate_after_sak; // Set device to Active mode after SAK responce
}rfalNfcDiscoverParam;

View file

@ -575,6 +575,7 @@ ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_
*rvdLen = (uint16_t*)&gNfcDev.rxLen;
*rxData = (uint8_t*)( (gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) ? gNfcDev.rxBuf.isoDepBuf.apdu :
((gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_NFCDEP) ? gNfcDev.rxBuf.nfcDepBuf.pdu : gNfcDev.rxBuf.rfBuf));
gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE_DONE;
return ERR_NONE;
}
@ -1579,6 +1580,7 @@ static ReturnCode rfalNfcListenActivation( void )
lmSt = rfalListenGetState( &isDataRcvd, &bitRate );
switch(lmSt)
{
@ -1595,6 +1597,12 @@ static ReturnCode rfalNfcListenActivation( void )
/* Set the Listen Mode in Sleep state */
EXIT_ON_ERR( ret, rfalListenSleepStart( RFAL_LM_STATE_SLEEP_A, gNfcDev.rxBuf.rfBuf, sizeof(gNfcDev.rxBuf.rfBuf), &gNfcDev.rxLen ) );
}
else if(gNfcDev.disc.activate_after_sak) {
gNfcDev.devList->type = RFAL_NFC_POLL_TYPE_NFCA;
rfalListenSetState(RFAL_LM_STATE_ACTIVE_A);
return ERR_NONE;
}
#if RFAL_FEATURE_ISO_DEP && RFAL_FEATURE_ISO_DEP_LISTEN
/* Check if received data is a valid RATS */

View file

@ -137,3 +137,94 @@ uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data) {
dest[5] = (uint8_t) data;
return 6;
}
void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data) {
mf_ul_emulate->data = *data;
mf_ul_emulate->data_changed = false;
if(data->version.storage_size == 0) {
mf_ul_emulate->type = MfUltralightTypeUnknown;
mf_ul_emulate->support_fast_read = false;
} else if(data->version.storage_size == 0x0B) {
mf_ul_emulate->type = MfUltralightTypeUL11;
mf_ul_emulate->support_fast_read = true;
} else if(data->version.storage_size == 0x0E) {
mf_ul_emulate->type = MfUltralightTypeUL21;
mf_ul_emulate->support_fast_read = true;
}
}
uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uint8_t* buff_tx, MifareUlDevice* mf_ul_emulate) {
uint8_t cmd = buff_rx[0];
uint16_t page_num = mf_ul_emulate->data.data_size / 4;
uint16_t tx_len = 0;
if(cmd == MF_UL_GET_VERSION_CMD) {
if(mf_ul_emulate->type != MfUltralightTypeUnknown) {
tx_len = sizeof(mf_ul_emulate->data.version);
memcpy(buff_tx, &mf_ul_emulate->data.version, tx_len);
}
} else if(cmd == MF_UL_READ_CMD) {
uint8_t start_page = buff_rx[1];
if(start_page < page_num) {
tx_len = 16;
if(start_page + 4 > page_num) {
// Handle roll-over mechanism
uint8_t end_pages_num = page_num - start_page;
memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], end_pages_num * 4);
memcpy(&buff_tx[end_pages_num * 4], mf_ul_emulate->data.data, (4 - end_pages_num) * 4);
} else {
memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_len);
}
}
} else if(cmd == MF_UL_FAST_READ_CMD) {
if(mf_ul_emulate->support_fast_read) {
uint8_t start_page = buff_rx[1];
uint8_t end_page = buff_rx[2];
if((start_page < page_num) &&
(end_page < page_num) && (start_page < end_page)) {
tx_len = (end_page - start_page) * 4;
memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_len);
}
}
} else if(cmd == MF_UL_WRITE) {
uint8_t write_page = buff_rx[1];
if((write_page > 1) && (write_page < page_num - 2)) {
memcpy(&mf_ul_emulate->data.data[write_page * 4], &buff_rx[2], 4);
mf_ul_emulate->data_changed = true;
// TODO make 4-bit ACK
buff_tx[0] = 0x0A;
tx_len = 1;
}
} else if(cmd == MF_UL_READ_CNT) {
uint8_t cnt_num = buff_rx[1];
if(cnt_num < 3) {
buff_tx[0] = mf_ul_emulate->data.counter[cnt_num] >> 16;
buff_tx[1] = mf_ul_emulate->data.counter[cnt_num] >> 8;
buff_tx[2] = mf_ul_emulate->data.counter[cnt_num];
tx_len = 3;
}
} else if(cmd == MF_UL_INC_CNT) {
uint8_t cnt_num = buff_rx[1];
uint32_t inc = (buff_rx[2] | (buff_rx[3] << 8) | (buff_rx[4] << 16));
if((cnt_num < 3) && (mf_ul_emulate->data.counter[cnt_num] + inc < 0x00FFFFFF)) {
mf_ul_emulate->data.counter[cnt_num] += inc;
mf_ul_emulate->data_changed = true;
// TODO make 4-bit ACK
buff_tx[0] = 0x0A;
tx_len = 1;
}
} else if(cmd == MF_UL_READ_SIG) {
// Check 2nd byte = 0x00 - RFU
if(buff_rx[1] == 0x00) {
tx_len = sizeof(mf_ul_emulate->data.signature);
memcpy(buff_tx, mf_ul_emulate->data.signature, tx_len);
}
} else if(cmd == MF_UL_CHECK_TEARING) {
uint8_t cnt_num = buff_rx[1];
if(cnt_num < 3) {
buff_tx[0] = mf_ul_emulate->data.tearing[cnt_num];
tx_len = 1;
}
}
return tx_len;
}

View file

@ -65,6 +65,7 @@ typedef struct {
uint8_t pages_to_read;
uint8_t pages_readed;
bool support_fast_read;
bool data_changed;
MifareUlData data;
} MifareUlDevice;
@ -93,3 +94,5 @@ void mf_ul_parse_fast_read_response(uint8_t* buff, uint8_t start_page, uint8_t e
uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data);
void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data);
uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uint8_t* buff_tx, MifareUlDevice* mf_ul_emulate);