Skip to content

Commit 460ace1

Browse files
committed
MFC support
1 parent 30f4556 commit 460ace1

7 files changed

+182
-14
lines changed

sam_api.c

+74-10
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,56 @@ void seader_iso14443a_transmit(
728728
bit_buffer_free(rx_buffer);
729729
}
730730

731+
/* Assumes this is called in the context of the NFC API callback */
732+
#define MF_CLASSIC_FWT_FC (60000)
733+
void seader_mfc_transmit(
734+
Seader* seader,
735+
MfClassicPoller* mfc_poller,
736+
uint8_t* buffer,
737+
size_t len,
738+
uint16_t timeout,
739+
uint8_t format[3]) {
740+
UNUSED(timeout);
741+
742+
furi_assert(seader);
743+
furi_assert(buffer);
744+
furi_assert(mfc_poller);
745+
SeaderWorker* seader_worker = seader->worker;
746+
SeaderUartBridge* seader_uart = seader_worker->uart;
747+
748+
BitBuffer* tx_buffer = bit_buffer_alloc(len);
749+
BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
750+
751+
do {
752+
bit_buffer_append_bytes(tx_buffer, buffer, len);
753+
if(format[0] == 0x00 && format[1] == 0xC0 && format[2] == 0x00) {
754+
//iso14443_3a_poller_standard_frame_exchange
755+
} else if(
756+
(format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x40) ||
757+
(format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x24) ||
758+
(format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x44)) {
759+
/*
760+
Iso14443_3aPoller* iso14443_3a_poller = (MfClassicPoller)mfc_poller->iso14443_3a_poller;
761+
Iso14443_3aError error = iso14443_3a_poller_txrx_custom_parity(iso14443_3a_poller,tx_buffer, rx_buffer, MF_CLASSIC_FWT_FC);
762+
if(error == Iso14443_3aErrorWrongCrc) {
763+
if(bit_buffer_get_size_bytes(rx_buffer) != sizeof(MfClassicNt)) {
764+
FURI_LOG_W(TAG, "iso14443_3a_poller_txrx_custom_parity error %d", error);
765+
seader_worker->stage = SeaderPollerEventTypeFail;
766+
}
767+
}
768+
*/
769+
}
770+
771+
seader_send_nfc_rx(
772+
seader_uart,
773+
(uint8_t*)bit_buffer_get_data(rx_buffer),
774+
bit_buffer_get_size_bytes(rx_buffer));
775+
776+
} while(false);
777+
bit_buffer_free(tx_buffer);
778+
bit_buffer_free(rx_buffer);
779+
}
780+
731781
void seader_parse_nfc_command_transmit(
732782
Seader* seader,
733783
NFCSend_t* nfcSend,
@@ -757,13 +807,23 @@ void seader_parse_nfc_command_transmit(
757807
seader_iso15693_transmit(
758808
seader, spc->picopass_poller, nfcSend->data.buf, nfcSend->data.size);
759809
} else if(frameProtocol == FrameProtocol_nfc) {
760-
seader_iso14443a_transmit(
761-
seader,
762-
spc->iso14443_4a_poller,
763-
nfcSend->data.buf,
764-
nfcSend->data.size,
765-
(uint16_t)timeOut,
766-
nfcSend->format->buf);
810+
if(spc->iso14443_4a_poller) {
811+
seader_iso14443a_transmit(
812+
seader,
813+
spc->iso14443_4a_poller,
814+
nfcSend->data.buf,
815+
nfcSend->data.size,
816+
(uint16_t)timeOut,
817+
nfcSend->format->buf);
818+
} else if(spc->mfc_poller) {
819+
seader_mfc_transmit(
820+
seader,
821+
spc->mfc_poller,
822+
nfcSend->data.buf,
823+
nfcSend->data.size,
824+
(uint16_t)timeOut,
825+
nfcSend->format->buf);
826+
}
767827
} else {
768828
FURI_LOG_W(TAG, "unknown frame protocol %lx", frameProtocol);
769829
}
@@ -911,18 +971,22 @@ NfcCommand seader_worker_card_detect(
911971
OCTET_STRING_t atqa_string = {.buf = atqa, .size = 2};
912972
uint8_t protocol_bytes[] = {0x00, 0x00};
913973

914-
if(sak == 0 && atqa == NULL) {
974+
if(sak == 0 && atqa == NULL) { // picopass
915975
protocol_bytes[1] = FrameProtocol_iclass;
916976
OCTET_STRING_fromBuf(
917977
&cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes));
918978
memcpy(credential->diversifier, uid, uid_len);
919979
credential->diversifier_len = uid_len;
920980
credential->isDesfire = false;
921-
} else {
981+
} else if(atqa == 0) { // MFC
982+
protocol_bytes[1] = FrameProtocol_nfc;
983+
OCTET_STRING_fromBuf(
984+
&cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes));
985+
cardDetails->sak = &sak_string;
986+
} else { // type 4
922987
protocol_bytes[1] = FrameProtocol_nfc;
923988
OCTET_STRING_fromBuf(
924989
&cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes));
925-
926990
cardDetails->sak = &sak_string;
927991
cardDetails->atqa = &atqa_string;
928992
credential->isDesfire = seader_mf_df_check_card_type(atqa[0], atqa[1], sak);

scenes/seader_scene_config.h

+1
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ ADD_SCENE(seader, credential_info, CredentialInfo)
1616
ADD_SCENE(seader, sam_info, SamInfo)
1717
ADD_SCENE(seader, virtual_credential, VirtualCredential)
1818
ADD_SCENE(seader, formats, Formats)
19+
ADD_SCENE(seader, read_mfc, ReadMfc)

scenes/seader_scene_read_mfc.c

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#include "../seader_i.h"
2+
#include <dolphin/dolphin.h>
3+
4+
void seader_scene_read_mfc_on_enter(void* context) {
5+
Seader* seader = context;
6+
dolphin_deed(DolphinDeedNfcRead);
7+
8+
// Setup view
9+
Popup* popup = seader->popup;
10+
popup_set_header(popup, "Detecting\nMFC\ncard", 68, 30, AlignLeft, AlignTop);
11+
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
12+
13+
// Start worker
14+
view_dispatcher_switch_to_view(seader->view_dispatcher, SeaderViewPopup);
15+
16+
seader->poller = nfc_poller_alloc(seader->nfc, NfcProtocolMfClassic);
17+
18+
seader->worker->stage = SeaderPollerEventTypeCardDetect;
19+
seader_credential_clear(seader->credential);
20+
seader->credential->type = SeaderCredentialTypeMifareClassic;
21+
nfc_poller_start(seader->poller, seader_worker_poller_callback_mfc, seader);
22+
23+
seader_blink_start(seader);
24+
}
25+
26+
bool seader_scene_read_mfc_on_event(void* context, SceneManagerEvent event) {
27+
Seader* seader = context;
28+
bool consumed = false;
29+
30+
if(event.type == SceneManagerEventTypeCustom) {
31+
if(event.event == SeaderCustomEventWorkerExit) {
32+
seader->credential->type = SeaderCredentialTypeMifareClassic;
33+
scene_manager_next_scene(seader->scene_manager, SeaderSceneReadCardSuccess);
34+
consumed = true;
35+
} else if(event.event == SeaderCustomEventPollerSuccess) {
36+
seader->credential->type = SeaderCredentialTypeMifareClassic;
37+
scene_manager_next_scene(seader->scene_manager, SeaderSceneReadCardSuccess);
38+
consumed = true;
39+
}
40+
} else if(event.type == SceneManagerEventTypeBack) {
41+
scene_manager_search_and_switch_to_previous_scene(
42+
seader->scene_manager, SeaderSceneSamPresent);
43+
consumed = true;
44+
}
45+
46+
return consumed;
47+
}
48+
49+
void seader_scene_read_mfc_on_exit(void* context) {
50+
Seader* seader = context;
51+
52+
if(seader->poller) {
53+
nfc_poller_stop(seader->poller);
54+
nfc_poller_free(seader->poller);
55+
}
56+
57+
// Clear view
58+
popup_reset(seader->popup);
59+
60+
seader_blink_stop(seader);
61+
}

scenes/seader_scene_sam_present.c

+12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
enum SubmenuIndex {
33
SubmenuIndexReadPicopass,
44
SubmenuIndexRead14a,
5+
SubmenuIndexReadMfc,
56
SubmenuIndexSaved,
67
SubmenuIndexSamInfo,
78
SubmenuIndexFwVersion,
@@ -33,6 +34,12 @@ void seader_scene_sam_present_on_update(void* context) {
3334
SubmenuIndexRead14a,
3435
seader_scene_sam_present_submenu_callback,
3536
seader);
37+
submenu_add_item(
38+
submenu,
39+
"Read MFC",
40+
SubmenuIndexReadMfc,
41+
seader_scene_sam_present_submenu_callback,
42+
seader);
3643
submenu_add_item(
3744
submenu, "Saved", SubmenuIndexSaved, seader_scene_sam_present_submenu_callback, seader);
3845

@@ -75,6 +82,11 @@ bool seader_scene_sam_present_on_event(void* context, SceneManagerEvent event) {
7582
seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexRead14a);
7683
scene_manager_next_scene(seader->scene_manager, SeaderSceneRead14a);
7784
consumed = true;
85+
} else if(event.event == SubmenuIndexReadMfc) {
86+
scene_manager_set_scene_state(
87+
seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexReadMfc);
88+
scene_manager_next_scene(seader->scene_manager, SeaderSceneReadMfc);
89+
consumed = true;
7890
} else if(event.event == SubmenuIndexSamInfo) {
7991
scene_manager_set_scene_state(
8092
seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexSamInfo);

seader_i.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@
2424
#include <input/input.h>
2525

2626
#include <lib/nfc/nfc.h>
27-
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a.h>
28-
2927
#include <nfc/nfc_poller.h>
30-
3128
#include <nfc/nfc_device.h>
3229
#include <nfc/helpers/nfc_data_generator.h>
3330

@@ -124,6 +121,7 @@ struct Seader {
124121

125122
struct SeaderPollerContainer {
126123
Iso14443_4aPoller* iso14443_4a_poller;
124+
MfClassicPoller* mfc_poller;
127125
PicopassPoller* picopass_poller;
128126
};
129127

seader_worker.c

+31
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,37 @@ NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void
307307
return ret;
308308
}
309309

310+
NfcCommand seader_worker_poller_callback_mfc(NfcGenericEvent event, void* context) {
311+
furi_assert(event.protocol == NfcProtocolMfClassic);
312+
NfcCommand ret = NfcCommandContinue;
313+
314+
Seader* seader = context;
315+
SeaderWorker* seader_worker = seader->worker;
316+
317+
MfClassicPollerEvent* mfc_event = event.event_data;
318+
SeaderPollerContainer spc = {.mfc_poller = event.instance};
319+
320+
if(mfc_event->type == MfClassicPollerEventTypeSuccess) {
321+
if(seader_worker->stage == SeaderPollerEventTypeCardDetect) {
322+
const MfClassicData* mfc_data = nfc_poller_get_data(seader->poller);
323+
uint8_t sak = iso14443_3a_get_sak(mfc_data->iso14443_3a_data);
324+
size_t uid_len = 0;
325+
const uint8_t* uid = mf_classic_get_uid(mfc_data, &uid_len);
326+
seader_worker_card_detect(seader, sak, NULL, uid, uid_len, NULL, 0);
327+
furi_thread_set_current_priority(FuriThreadPriorityLowest);
328+
seader_worker->stage = SeaderPollerEventTypeConversation;
329+
} else if(seader_worker->stage == SeaderPollerEventTypeConversation) {
330+
seader_worker_poller_conversation(seader, &spc);
331+
} else if(seader_worker->stage == SeaderPollerEventTypeComplete) {
332+
ret = NfcCommandStop;
333+
}
334+
} else if(mfc_event->type == MfClassicPollerEventTypeFail) {
335+
ret = NfcCommandStop;
336+
}
337+
338+
return ret;
339+
}
340+
310341
NfcCommand seader_worker_poller_callback_picopass(PicopassPollerEvent event, void* context) {
311342
furi_assert(context);
312343
NfcCommand ret = NfcCommandContinue;

seader_worker.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h>
4+
#include <lib/nfc/protocols/mf_classic/mf_classic_poller.h>
45

56
#include "sam_api.h"
67
#include "seader_credential.h"
@@ -65,5 +66,5 @@ bool seader_worker_process_sam_message(Seader* seader, CCID_Message* message);
6566
void seader_worker_send_version(Seader* seader);
6667

6768
NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void* context);
68-
69+
NfcCommand seader_worker_poller_callback_mfc(NfcGenericEvent event, void* context);
6970
NfcCommand seader_worker_poller_callback_picopass(PicopassPollerEvent event, void* context);

0 commit comments

Comments
 (0)