Eric Betts 1 год назад
Родитель
Сommit
460ace1be3
7 измененных файлов с 182 добавлено и 14 удалено
  1. 74 10
      sam_api.c
  2. 1 0
      scenes/seader_scene_config.h
  3. 61 0
      scenes/seader_scene_read_mfc.c
  4. 12 0
      scenes/seader_scene_sam_present.c
  5. 1 3
      seader_i.h
  6. 31 0
      seader_worker.c
  7. 2 1
      seader_worker.h

+ 74 - 10
sam_api.c

@@ -728,6 +728,56 @@ void seader_iso14443a_transmit(
     bit_buffer_free(rx_buffer);
 }
 
+/* Assumes this is called in the context of the NFC API callback */
+#define MF_CLASSIC_FWT_FC (60000)
+void seader_mfc_transmit(
+    Seader* seader,
+    MfClassicPoller* mfc_poller,
+    uint8_t* buffer,
+    size_t len,
+    uint16_t timeout,
+    uint8_t format[3]) {
+    UNUSED(timeout);
+
+    furi_assert(seader);
+    furi_assert(buffer);
+    furi_assert(mfc_poller);
+    SeaderWorker* seader_worker = seader->worker;
+    SeaderUartBridge* seader_uart = seader_worker->uart;
+
+    BitBuffer* tx_buffer = bit_buffer_alloc(len);
+    BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
+
+    do {
+        bit_buffer_append_bytes(tx_buffer, buffer, len);
+        if(format[0] == 0x00 && format[1] == 0xC0 && format[2] == 0x00) {
+            //iso14443_3a_poller_standard_frame_exchange
+        } else if(
+            (format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x40) ||
+            (format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x24) ||
+            (format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x44)) {
+            /*
+            Iso14443_3aPoller* iso14443_3a_poller = (MfClassicPoller)mfc_poller->iso14443_3a_poller;
+            Iso14443_3aError error = iso14443_3a_poller_txrx_custom_parity(iso14443_3a_poller,tx_buffer, rx_buffer, MF_CLASSIC_FWT_FC);
+              if(error == Iso14443_3aErrorWrongCrc) {
+                  if(bit_buffer_get_size_bytes(rx_buffer) != sizeof(MfClassicNt)) {
+                      FURI_LOG_W(TAG, "iso14443_3a_poller_txrx_custom_parity error %d", error);
+                      seader_worker->stage = SeaderPollerEventTypeFail;
+                  }
+              }
+          */
+        }
+
+        seader_send_nfc_rx(
+            seader_uart,
+            (uint8_t*)bit_buffer_get_data(rx_buffer),
+            bit_buffer_get_size_bytes(rx_buffer));
+
+    } while(false);
+    bit_buffer_free(tx_buffer);
+    bit_buffer_free(rx_buffer);
+}
+
 void seader_parse_nfc_command_transmit(
     Seader* seader,
     NFCSend_t* nfcSend,
@@ -757,13 +807,23 @@ void seader_parse_nfc_command_transmit(
         seader_iso15693_transmit(
             seader, spc->picopass_poller, nfcSend->data.buf, nfcSend->data.size);
     } else if(frameProtocol == FrameProtocol_nfc) {
-        seader_iso14443a_transmit(
-            seader,
-            spc->iso14443_4a_poller,
-            nfcSend->data.buf,
-            nfcSend->data.size,
-            (uint16_t)timeOut,
-            nfcSend->format->buf);
+        if(spc->iso14443_4a_poller) {
+            seader_iso14443a_transmit(
+                seader,
+                spc->iso14443_4a_poller,
+                nfcSend->data.buf,
+                nfcSend->data.size,
+                (uint16_t)timeOut,
+                nfcSend->format->buf);
+        } else if(spc->mfc_poller) {
+            seader_mfc_transmit(
+                seader,
+                spc->mfc_poller,
+                nfcSend->data.buf,
+                nfcSend->data.size,
+                (uint16_t)timeOut,
+                nfcSend->format->buf);
+        }
     } else {
         FURI_LOG_W(TAG, "unknown frame protocol %lx", frameProtocol);
     }
@@ -911,18 +971,22 @@ NfcCommand seader_worker_card_detect(
     OCTET_STRING_t atqa_string = {.buf = atqa, .size = 2};
     uint8_t protocol_bytes[] = {0x00, 0x00};
 
-    if(sak == 0 && atqa == NULL) {
+    if(sak == 0 && atqa == NULL) { // picopass
         protocol_bytes[1] = FrameProtocol_iclass;
         OCTET_STRING_fromBuf(
             &cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes));
         memcpy(credential->diversifier, uid, uid_len);
         credential->diversifier_len = uid_len;
         credential->isDesfire = false;
-    } else {
+    } else if(atqa == 0) { // MFC
+        protocol_bytes[1] = FrameProtocol_nfc;
+        OCTET_STRING_fromBuf(
+            &cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes));
+        cardDetails->sak = &sak_string;
+    } else { // type 4
         protocol_bytes[1] = FrameProtocol_nfc;
         OCTET_STRING_fromBuf(
             &cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes));
-
         cardDetails->sak = &sak_string;
         cardDetails->atqa = &atqa_string;
         credential->isDesfire = seader_mf_df_check_card_type(atqa[0], atqa[1], sak);

+ 1 - 0
scenes/seader_scene_config.h

@@ -16,3 +16,4 @@ ADD_SCENE(seader, credential_info, CredentialInfo)
 ADD_SCENE(seader, sam_info, SamInfo)
 ADD_SCENE(seader, virtual_credential, VirtualCredential)
 ADD_SCENE(seader, formats, Formats)
+ADD_SCENE(seader, read_mfc, ReadMfc)

+ 61 - 0
scenes/seader_scene_read_mfc.c

@@ -0,0 +1,61 @@
+#include "../seader_i.h"
+#include <dolphin/dolphin.h>
+
+void seader_scene_read_mfc_on_enter(void* context) {
+    Seader* seader = context;
+    dolphin_deed(DolphinDeedNfcRead);
+
+    // Setup view
+    Popup* popup = seader->popup;
+    popup_set_header(popup, "Detecting\nMFC\ncard", 68, 30, AlignLeft, AlignTop);
+    popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
+
+    // Start worker
+    view_dispatcher_switch_to_view(seader->view_dispatcher, SeaderViewPopup);
+
+    seader->poller = nfc_poller_alloc(seader->nfc, NfcProtocolMfClassic);
+
+    seader->worker->stage = SeaderPollerEventTypeCardDetect;
+    seader_credential_clear(seader->credential);
+    seader->credential->type = SeaderCredentialTypeMifareClassic;
+    nfc_poller_start(seader->poller, seader_worker_poller_callback_mfc, seader);
+
+    seader_blink_start(seader);
+}
+
+bool seader_scene_read_mfc_on_event(void* context, SceneManagerEvent event) {
+    Seader* seader = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == SeaderCustomEventWorkerExit) {
+            seader->credential->type = SeaderCredentialTypeMifareClassic;
+            scene_manager_next_scene(seader->scene_manager, SeaderSceneReadCardSuccess);
+            consumed = true;
+        } else if(event.event == SeaderCustomEventPollerSuccess) {
+            seader->credential->type = SeaderCredentialTypeMifareClassic;
+            scene_manager_next_scene(seader->scene_manager, SeaderSceneReadCardSuccess);
+            consumed = true;
+        }
+    } else if(event.type == SceneManagerEventTypeBack) {
+        scene_manager_search_and_switch_to_previous_scene(
+            seader->scene_manager, SeaderSceneSamPresent);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void seader_scene_read_mfc_on_exit(void* context) {
+    Seader* seader = context;
+
+    if(seader->poller) {
+        nfc_poller_stop(seader->poller);
+        nfc_poller_free(seader->poller);
+    }
+
+    // Clear view
+    popup_reset(seader->popup);
+
+    seader_blink_stop(seader);
+}

+ 12 - 0
scenes/seader_scene_sam_present.c

@@ -2,6 +2,7 @@
 enum SubmenuIndex {
     SubmenuIndexReadPicopass,
     SubmenuIndexRead14a,
+    SubmenuIndexReadMfc,
     SubmenuIndexSaved,
     SubmenuIndexSamInfo,
     SubmenuIndexFwVersion,
@@ -33,6 +34,12 @@ void seader_scene_sam_present_on_update(void* context) {
         SubmenuIndexRead14a,
         seader_scene_sam_present_submenu_callback,
         seader);
+    submenu_add_item(
+        submenu,
+        "Read MFC",
+        SubmenuIndexReadMfc,
+        seader_scene_sam_present_submenu_callback,
+        seader);
     submenu_add_item(
         submenu, "Saved", SubmenuIndexSaved, seader_scene_sam_present_submenu_callback, seader);
 
@@ -75,6 +82,11 @@ bool seader_scene_sam_present_on_event(void* context, SceneManagerEvent event) {
                 seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexRead14a);
             scene_manager_next_scene(seader->scene_manager, SeaderSceneRead14a);
             consumed = true;
+        } else if(event.event == SubmenuIndexReadMfc) {
+            scene_manager_set_scene_state(
+                seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexReadMfc);
+            scene_manager_next_scene(seader->scene_manager, SeaderSceneReadMfc);
+            consumed = true;
         } else if(event.event == SubmenuIndexSamInfo) {
             scene_manager_set_scene_state(
                 seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexSamInfo);

+ 1 - 3
seader_i.h

@@ -24,10 +24,7 @@
 #include <input/input.h>
 
 #include <lib/nfc/nfc.h>
-#include <lib/nfc/protocols/iso14443_3a/iso14443_3a.h>
-
 #include <nfc/nfc_poller.h>
-
 #include <nfc/nfc_device.h>
 #include <nfc/helpers/nfc_data_generator.h>
 
@@ -124,6 +121,7 @@ struct Seader {
 
 struct SeaderPollerContainer {
     Iso14443_4aPoller* iso14443_4a_poller;
+    MfClassicPoller* mfc_poller;
     PicopassPoller* picopass_poller;
 };
 

+ 31 - 0
seader_worker.c

@@ -307,6 +307,37 @@ NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void
     return ret;
 }
 
+NfcCommand seader_worker_poller_callback_mfc(NfcGenericEvent event, void* context) {
+    furi_assert(event.protocol == NfcProtocolMfClassic);
+    NfcCommand ret = NfcCommandContinue;
+
+    Seader* seader = context;
+    SeaderWorker* seader_worker = seader->worker;
+
+    MfClassicPollerEvent* mfc_event = event.event_data;
+    SeaderPollerContainer spc = {.mfc_poller = event.instance};
+
+    if(mfc_event->type == MfClassicPollerEventTypeSuccess) {
+        if(seader_worker->stage == SeaderPollerEventTypeCardDetect) {
+            const MfClassicData* mfc_data = nfc_poller_get_data(seader->poller);
+            uint8_t sak = iso14443_3a_get_sak(mfc_data->iso14443_3a_data);
+            size_t uid_len = 0;
+            const uint8_t* uid = mf_classic_get_uid(mfc_data, &uid_len);
+            seader_worker_card_detect(seader, sak, NULL, uid, uid_len, NULL, 0);
+            furi_thread_set_current_priority(FuriThreadPriorityLowest);
+            seader_worker->stage = SeaderPollerEventTypeConversation;
+        } else if(seader_worker->stage == SeaderPollerEventTypeConversation) {
+            seader_worker_poller_conversation(seader, &spc);
+        } else if(seader_worker->stage == SeaderPollerEventTypeComplete) {
+            ret = NfcCommandStop;
+        }
+    } else if(mfc_event->type == MfClassicPollerEventTypeFail) {
+        ret = NfcCommandStop;
+    }
+
+    return ret;
+}
+
 NfcCommand seader_worker_poller_callback_picopass(PicopassPollerEvent event, void* context) {
     furi_assert(context);
     NfcCommand ret = NfcCommandContinue;

+ 2 - 1
seader_worker.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h>
+#include <lib/nfc/protocols/mf_classic/mf_classic_poller.h>
 
 #include "sam_api.h"
 #include "seader_credential.h"
@@ -65,5 +66,5 @@ bool seader_worker_process_sam_message(Seader* seader, CCID_Message* message);
 void seader_worker_send_version(Seader* seader);
 
 NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void* context);
-
+NfcCommand seader_worker_poller_callback_mfc(NfcGenericEvent event, void* context);
 NfcCommand seader_worker_poller_callback_picopass(PicopassPollerEvent event, void* context);