nfc_debug_pcap.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #include "nfc_debug_pcap.h"
  2. #include <furi_hal_rtc.h>
  3. #include <stream_buffer.h>
  4. #define TAG "NfcDebugPcap"
  5. #define PCAP_MAGIC 0xa1b2c3d4
  6. #define PCAP_MAJOR 2
  7. #define PCAP_MINOR 4
  8. #define DLT_ISO_14443 264
  9. #define DATA_PICC_TO_PCD 0xFF
  10. #define DATA_PCD_TO_PICC 0xFE
  11. #define DATA_PICC_TO_PCD_CRC_DROPPED 0xFB
  12. #define DATA_PCD_TO_PICC_CRC_DROPPED 0xFA
  13. #define NFC_DEBUG_PCAP_FILENAME EXT_PATH("nfc/debug.pcap")
  14. #define NFC_DEBUG_PCAP_BUFFER_SIZE 64
  15. struct NfcDebugPcapWorker {
  16. bool alive;
  17. Storage* storage;
  18. File* file;
  19. StreamBufferHandle_t stream;
  20. FuriThread* thread;
  21. };
  22. static File* nfc_debug_pcap_open(Storage* storage) {
  23. File* file = storage_file_alloc(storage);
  24. if(!storage_file_open(file, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) {
  25. storage_file_free(file);
  26. return NULL;
  27. }
  28. if(!storage_file_tell(file)) {
  29. struct {
  30. uint32_t magic;
  31. uint16_t major, minor;
  32. uint32_t reserved[2];
  33. uint32_t snaplen;
  34. uint32_t link_type;
  35. } __attribute__((__packed__)) pcap_hdr = {
  36. .magic = PCAP_MAGIC,
  37. .major = PCAP_MAJOR,
  38. .minor = PCAP_MINOR,
  39. .snaplen = FURI_HAL_NFC_DATA_BUFF_SIZE,
  40. .link_type = DLT_ISO_14443,
  41. };
  42. if(storage_file_write(file, &pcap_hdr, sizeof(pcap_hdr)) != sizeof(pcap_hdr)) {
  43. FURI_LOG_E(TAG, "Failed to write pcap header");
  44. }
  45. }
  46. return file;
  47. }
  48. static void
  49. nfc_debug_pcap_write(NfcDebugPcapWorker* instance, uint8_t event, uint8_t* data, uint16_t len) {
  50. FuriHalRtcDateTime datetime;
  51. furi_hal_rtc_get_datetime(&datetime);
  52. struct {
  53. // https://wiki.wireshark.org/Development/LibpcapFileFormat#record-packet-header
  54. uint32_t ts_sec;
  55. uint32_t ts_usec;
  56. uint32_t incl_len;
  57. uint32_t orig_len;
  58. // https://www.kaiser.cx/posts/pcap-iso14443/#_packet_data
  59. uint8_t version;
  60. uint8_t event;
  61. uint16_t len;
  62. } __attribute__((__packed__)) pkt_hdr = {
  63. .ts_sec = furi_hal_rtc_datetime_to_timestamp(&datetime),
  64. .ts_usec = 0,
  65. .incl_len = len + 4,
  66. .orig_len = len + 4,
  67. .version = 0,
  68. .event = event,
  69. .len = len << 8 | len >> 8,
  70. };
  71. xStreamBufferSend(instance->stream, &pkt_hdr, sizeof(pkt_hdr), FuriWaitForever);
  72. xStreamBufferSend(instance->stream, data, len, FuriWaitForever);
  73. }
  74. static void
  75. nfc_debug_pcap_write_tx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
  76. NfcDebugPcapWorker* instance = context;
  77. uint8_t event = crc_dropped ? DATA_PCD_TO_PICC_CRC_DROPPED : DATA_PCD_TO_PICC;
  78. nfc_debug_pcap_write(instance, event, data, bits / 8);
  79. }
  80. static void
  81. nfc_debug_pcap_write_rx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
  82. NfcDebugPcapWorker* instance = context;
  83. uint8_t event = crc_dropped ? DATA_PICC_TO_PCD_CRC_DROPPED : DATA_PICC_TO_PCD;
  84. nfc_debug_pcap_write(instance, event, data, bits / 8);
  85. }
  86. int32_t nfc_debug_pcap_thread(void* context) {
  87. NfcDebugPcapWorker* instance = context;
  88. uint8_t buffer[NFC_DEBUG_PCAP_BUFFER_SIZE];
  89. while(instance->alive) {
  90. size_t ret =
  91. xStreamBufferReceive(instance->stream, buffer, NFC_DEBUG_PCAP_BUFFER_SIZE, 50);
  92. if(storage_file_write(instance->file, buffer, ret) != ret) {
  93. FURI_LOG_E(TAG, "Failed to write pcap data");
  94. }
  95. }
  96. return 0;
  97. }
  98. NfcDebugPcapWorker* nfc_debug_pcap_alloc(Storage* storage) {
  99. NfcDebugPcapWorker* instance = malloc(sizeof(NfcDebugPcapWorker));
  100. instance->alive = true;
  101. instance->storage = storage;
  102. instance->file = nfc_debug_pcap_open(storage);
  103. instance->stream = xStreamBufferCreate(4096, 1);
  104. instance->thread = furi_thread_alloc();
  105. furi_thread_set_name(instance->thread, "PcapWorker");
  106. furi_thread_set_stack_size(instance->thread, 1024);
  107. furi_thread_set_callback(instance->thread, nfc_debug_pcap_thread);
  108. furi_thread_set_context(instance->thread, instance);
  109. furi_thread_start(instance->thread);
  110. return instance;
  111. }
  112. void nfc_debug_pcap_free(NfcDebugPcapWorker* instance) {
  113. furi_assert(instance);
  114. instance->alive = false;
  115. furi_thread_join(instance->thread);
  116. furi_thread_free(instance->thread);
  117. vStreamBufferDelete(instance->stream);
  118. if(instance->file) storage_file_free(instance->file);
  119. instance->storage = NULL;
  120. free(instance);
  121. }
  122. void nfc_debug_pcap_prepare_tx_rx(
  123. NfcDebugPcapWorker* instance,
  124. FuriHalNfcTxRxContext* tx_rx,
  125. bool is_picc) {
  126. if(!instance || !instance->file) return;
  127. if(is_picc) {
  128. tx_rx->sniff_tx = nfc_debug_pcap_write_rx;
  129. tx_rx->sniff_rx = nfc_debug_pcap_write_tx;
  130. } else {
  131. tx_rx->sniff_tx = nfc_debug_pcap_write_tx;
  132. tx_rx->sniff_rx = nfc_debug_pcap_write_rx;
  133. }
  134. tx_rx->sniff_context = instance;
  135. }