seader_worker.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #include "seader_worker_i.h"
  2. #include <flipper_format/flipper_format.h>
  3. #include <lib/lfrfid/tools/bit_lib.h>
  4. #define TAG "SeaderWorker"
  5. #define APDU_HEADER_LEN 5
  6. #define ASN1_PREFIX 6
  7. #define ASN1_DEBUG true
  8. #define RFAL_PICOPASS_TXRX_FLAGS \
  9. (FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | \
  10. FURI_HAL_NFC_LL_TXRX_FLAGS_PAR_RX_REMV | FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP)
  11. // TODO: const
  12. uint8_t GET_RESPONSE[] = {0x00, 0xc0, 0x00, 0x00, 0xff};
  13. char display[SEADER_UART_RX_BUF_SIZE * 2 + 1] = {0};
  14. // Forward declaration
  15. void seader_send_card_detected(SeaderUartBridge* seader_uart, CardDetails_t* cardDetails);
  16. /***************************** Seader Worker API *******************************/
  17. SeaderWorker* seader_worker_alloc() {
  18. SeaderWorker* seader_worker = malloc(sizeof(SeaderWorker));
  19. // Worker thread attributes
  20. seader_worker->thread =
  21. furi_thread_alloc_ex("SeaderWorker", 8192, seader_worker_task, seader_worker);
  22. seader_worker->messages = furi_message_queue_alloc(3, sizeof(SeaderAPDU));
  23. seader_worker->mq_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  24. seader_worker->callback = NULL;
  25. seader_worker->context = NULL;
  26. seader_worker->storage = furi_record_open(RECORD_STORAGE);
  27. memset(seader_worker->sam_version, 0, sizeof(seader_worker->sam_version));
  28. seader_worker_change_state(seader_worker, SeaderWorkerStateReady);
  29. return seader_worker;
  30. }
  31. void seader_worker_free(SeaderWorker* seader_worker) {
  32. furi_assert(seader_worker);
  33. furi_thread_free(seader_worker->thread);
  34. furi_message_queue_free(seader_worker->messages);
  35. furi_mutex_free(seader_worker->mq_mutex);
  36. furi_record_close(RECORD_STORAGE);
  37. free(seader_worker);
  38. }
  39. SeaderWorkerState seader_worker_get_state(SeaderWorker* seader_worker) {
  40. return seader_worker->state;
  41. }
  42. void seader_worker_start(
  43. SeaderWorker* seader_worker,
  44. SeaderWorkerState state,
  45. SeaderUartBridge* uart,
  46. SeaderWorkerCallback callback,
  47. void* context) {
  48. furi_assert(seader_worker);
  49. furi_assert(uart);
  50. seader_worker->stage = SeaderPollerEventTypeCardDetect;
  51. seader_worker->callback = callback;
  52. seader_worker->context = context;
  53. seader_worker->uart = uart;
  54. seader_worker_change_state(seader_worker, state);
  55. furi_thread_start(seader_worker->thread);
  56. }
  57. void seader_worker_stop(SeaderWorker* seader_worker) {
  58. furi_assert(seader_worker);
  59. if(seader_worker->state == SeaderWorkerStateBroken ||
  60. seader_worker->state == SeaderWorkerStateReady) {
  61. return;
  62. }
  63. seader_worker_change_state(seader_worker, SeaderWorkerStateStop);
  64. furi_thread_join(seader_worker->thread);
  65. }
  66. void seader_worker_change_state(SeaderWorker* seader_worker, SeaderWorkerState state) {
  67. seader_worker->state = state;
  68. }
  69. /***************************** Seader Worker Thread *******************************/
  70. bool seader_process_success_response(Seader* seader, uint8_t* apdu, size_t len) {
  71. SeaderWorker* seader_worker = seader->worker;
  72. if(seader_process_success_response_i(seader, apdu, len, false, NULL)) {
  73. // no-op, message was processed
  74. } else {
  75. FURI_LOG_I(TAG, "Queue New SAM Message, %d bytes", len);
  76. uint32_t space = furi_message_queue_get_space(seader_worker->messages);
  77. if(space > 0) {
  78. SeaderAPDU seaderApdu = {};
  79. seaderApdu.len = len;
  80. memcpy(seaderApdu.buf, apdu, len);
  81. if(furi_mutex_acquire(seader_worker->mq_mutex, FuriWaitForever) == FuriStatusOk) {
  82. furi_message_queue_put(seader_worker->messages, &seaderApdu, FuriWaitForever);
  83. furi_mutex_release(seader_worker->mq_mutex);
  84. }
  85. }
  86. }
  87. return true;
  88. }
  89. bool seader_process_apdu(Seader* seader, uint8_t* apdu, size_t len) {
  90. SeaderWorker* seader_worker = seader->worker;
  91. SeaderUartBridge* seader_uart = seader_worker->uart;
  92. if(len < 2) {
  93. return false;
  94. }
  95. memset(display, 0, sizeof(display));
  96. for(uint8_t i = 0; i < len; i++) {
  97. snprintf(display + (i * 2), sizeof(display), "%02x", apdu[i]);
  98. }
  99. // FURI_LOG_I(TAG, "APDU: %s", display);
  100. uint8_t SW1 = apdu[len - 2];
  101. uint8_t SW2 = apdu[len - 1];
  102. switch(SW1) {
  103. case 0x61:
  104. // FURI_LOG_I(TAG, "Request %d bytes", SW2);
  105. GET_RESPONSE[4] = SW2;
  106. seader_ccid_XfrBlock(seader_uart, GET_RESPONSE, sizeof(GET_RESPONSE));
  107. return true;
  108. break;
  109. case 0x90:
  110. if(SW2 == 0x00) {
  111. if(len > 2) {
  112. return seader_process_success_response(seader, apdu, len - 2);
  113. }
  114. }
  115. break;
  116. }
  117. return false;
  118. }
  119. void seader_worker_process_sam_message(Seader* seader, CCID_Message* message) {
  120. // TODO: inline seader_process_apdu
  121. seader_process_apdu(seader, message->payload, message->dwLength);
  122. }
  123. int32_t seader_worker_task(void* context) {
  124. SeaderWorker* seader_worker = context;
  125. SeaderUartBridge* seader_uart = seader_worker->uart;
  126. if(seader_worker->state == SeaderWorkerStateCheckSam) {
  127. FURI_LOG_D(TAG, "Check for SAM");
  128. seader_ccid_check_for_sam(seader_uart);
  129. }
  130. seader_worker_change_state(seader_worker, SeaderWorkerStateReady);
  131. return 0;
  132. }
  133. void seader_worker_poller_conversation(Seader* seader, SeaderPollerContainer* spc) {
  134. SeaderWorker* seader_worker = seader->worker;
  135. if(furi_mutex_acquire(seader_worker->mq_mutex, 0) == FuriStatusOk) {
  136. furi_thread_set_current_priority(FuriThreadPriorityHighest);
  137. uint32_t count = furi_message_queue_get_count(seader_worker->messages);
  138. if(count > 0) {
  139. FURI_LOG_D(TAG, "MessageQueue: %ld messages", count);
  140. SeaderAPDU seaderApdu = {};
  141. FuriStatus status =
  142. furi_message_queue_get(seader_worker->messages, &seaderApdu, FuriWaitForever);
  143. if(status != FuriStatusOk) {
  144. FURI_LOG_W(TAG, "furi_message_queue_get fail %d", status);
  145. seader_worker->stage = SeaderPollerEventTypeComplete;
  146. view_dispatcher_send_custom_event(
  147. seader->view_dispatcher, SeaderCustomEventWorkerExit);
  148. }
  149. if(seader_process_success_response_i(
  150. seader, seaderApdu.buf, seaderApdu.len, true, spc)) {
  151. // no-op
  152. } else {
  153. FURI_LOG_I(TAG, "Response false");
  154. seader_worker->stage = SeaderPollerEventTypeComplete;
  155. }
  156. }
  157. furi_mutex_release(seader_worker->mq_mutex);
  158. } else {
  159. furi_thread_set_current_priority(FuriThreadPriorityLowest);
  160. }
  161. }
  162. NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void* context) {
  163. furi_assert(event.protocol == NfcProtocolIso14443_4a);
  164. NfcCommand ret = NfcCommandContinue;
  165. Seader* seader = context;
  166. SeaderWorker* seader_worker = seader->worker;
  167. const Iso14443_4aPollerEvent* iso14443_4a_event = event.event_data;
  168. SeaderPollerContainer spc = {.iso14443_4a_poller = event.instance};
  169. if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
  170. if(seader_worker->stage == SeaderPollerEventTypeCardDetect) {
  171. nfc_device_set_data(
  172. seader->nfc_device, NfcProtocolIso14443_4a, nfc_poller_get_data(seader->poller));
  173. size_t uid_len;
  174. const uint8_t* uid = nfc_device_get_uid(seader->nfc_device, &uid_len);
  175. const Iso14443_3aData* iso14443_3a_data =
  176. nfc_device_get_data(seader->nfc_device, NfcProtocolIso14443_3a);
  177. uint8_t sak = iso14443_3a_get_sak(iso14443_3a_data);
  178. seader_worker_card_detect(
  179. seader, sak, (uint8_t*)iso14443_3a_data->atqa, uid, uid_len, NULL, 0);
  180. // nfc_set_fdt_poll_fc(event.instance, SEADER_POLLER_MAX_FWT);
  181. furi_thread_set_current_priority(FuriThreadPriorityLowest);
  182. seader_worker->stage = SeaderPollerEventTypeConversation;
  183. } else if(seader_worker->stage == SeaderPollerEventTypeConversation) {
  184. seader_worker_poller_conversation(seader, &spc);
  185. } else if(seader_worker->stage == SeaderPollerEventTypeComplete) {
  186. ret = NfcCommandStop;
  187. }
  188. }
  189. return ret;
  190. }
  191. NfcCommand seader_worker_poller_callback_picopass(PicopassPollerEvent event, void* context) {
  192. furi_assert(context);
  193. NfcCommand ret = NfcCommandContinue;
  194. Seader* seader = context;
  195. SeaderWorker* seader_worker = seader->worker;
  196. // I know this is is passing the same thing that is on seader all the way down, but I prefer the symmetry between the 15a and iso15 stuff
  197. PicopassPoller* instance = seader->picopass_poller;
  198. SeaderPollerContainer spc = {.picopass_poller = instance};
  199. if(event.type == PicopassPollerEventTypeCardDetected) {
  200. seader_worker->stage = SeaderPollerEventTypeCardDetect;
  201. } else if(event.type == PicopassPollerEventTypeSuccess) {
  202. if(seader_worker->stage == SeaderPollerEventTypeCardDetect) {
  203. uint8_t* csn = picopass_poller_get_csn(instance);
  204. seader_worker_card_detect(seader, 0, NULL, csn, sizeof(PicopassSerialNum), NULL, 0);
  205. furi_thread_set_current_priority(FuriThreadPriorityLowest);
  206. seader_worker->stage = SeaderPollerEventTypeConversation;
  207. } else if(seader_worker->stage == SeaderPollerEventTypeConversation) {
  208. seader_worker_poller_conversation(seader, &spc);
  209. } else if(seader_worker->stage == SeaderPollerEventTypeComplete) {
  210. ret = NfcCommandStop;
  211. }
  212. } else if(event.type == PicopassPollerEventTypeFail) {
  213. ret = NfcCommandStop;
  214. FURI_LOG_W(TAG, "PicopassPollerEventTypeFail");
  215. } else {
  216. FURI_LOG_D(TAG, "picopass event type %x", event.type);
  217. }
  218. return ret;
  219. }