gen2_poller.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. #include "gen2_poller_i.h"
  2. #include <nfc/helpers/nfc_data_generator.h>
  3. #include <furi/furi.h>
  4. #define GEN2_POLLER_THREAD_FLAG_DETECTED (1U << 0)
  5. #define TAG "GEN2"
  6. typedef NfcCommand (*Gen2PollerStateHandler)(Gen2Poller* instance);
  7. typedef struct {
  8. NfcPoller* poller;
  9. BitBuffer* tx_buffer;
  10. BitBuffer* rx_buffer;
  11. FuriThreadId thread_id;
  12. bool detected;
  13. Gen2PollerError error;
  14. } Gen2PollerDetectContext;
  15. // Array of known Gen2 ATS responses
  16. // 0978009102DABC1910F005 - flavour 2
  17. // 0978009102DABC1910F005 - flavour 4
  18. // 0D780071028849A13020150608563D - flavour 6
  19. // Other flavours can't be detected other than by just trying to write to block 0
  20. const uint8_t GEN2_ATS[3][16] = {
  21. {0x09, 0x78, 0x00, 0x91, 0x02, 0xDA, 0xBC, 0x19, 0x10, 0xF0, 0x05},
  22. {0x09, 0x78, 0x00, 0x91, 0x02, 0xDA, 0xBC, 0x19, 0x10, 0xF0, 0x05},
  23. {0x0D, 0x78, 0x00, 0x71, 0x02, 0x88, 0x49, 0xA1, 0x30, 0x20, 0x15, 0x06, 0x08, 0x56, 0x3D}};
  24. static MfClassicBlock gen2_poller_default_block_0 = {
  25. .data =
  26. {0x00,
  27. 0x01,
  28. 0x02,
  29. 0x03,
  30. 0x00, // BCC - IMPORTANT
  31. 0x08, // SAK
  32. 0x04, // ATQA0
  33. 0x00, // ATQA1
  34. 0x00,
  35. 0x00,
  36. 0x00,
  37. 0x00,
  38. 0x00,
  39. 0x00,
  40. 0x00,
  41. 0x00},
  42. };
  43. static MfClassicBlock gen2_poller_default_empty_block = {
  44. .data =
  45. {0x00,
  46. 0x00,
  47. 0x00,
  48. 0x00,
  49. 0x00,
  50. 0x00,
  51. 0x00,
  52. 0x00,
  53. 0x00,
  54. 0x00,
  55. 0x00,
  56. 0x00,
  57. 0x00,
  58. 0x00,
  59. 0x00,
  60. 0x00},
  61. };
  62. static MfClassicBlock gen2_poller_default_sector_trailer_block = {
  63. .data =
  64. {0xFF,
  65. 0xFF,
  66. 0xFF,
  67. 0xFF,
  68. 0xFF,
  69. 0xFF,
  70. 0xFF,
  71. 0x07,
  72. 0x80,
  73. 0x69,
  74. 0xFF,
  75. 0xFF,
  76. 0xFF,
  77. 0xFF,
  78. 0xFF,
  79. 0xFF},
  80. };
  81. Gen2Poller* gen2_poller_alloc(Nfc* nfc) {
  82. Gen2Poller* instance = malloc(sizeof(Gen2Poller));
  83. instance->poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a);
  84. instance->data = mf_classic_alloc();
  85. instance->crypto = crypto1_alloc();
  86. instance->tx_plain_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE);
  87. instance->tx_encrypted_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE);
  88. instance->rx_plain_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE);
  89. instance->rx_encrypted_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE);
  90. instance->card_state = Gen2CardStateLost;
  91. instance->gen2_event.data = &instance->gen2_event_data;
  92. instance->mode_ctx.write_ctx.mfc_data_source = malloc(sizeof(MfClassicData));
  93. instance->mode_ctx.write_ctx.mfc_data_target = malloc(sizeof(MfClassicData));
  94. instance->mode_ctx.write_ctx.need_halt_before_write = true;
  95. return instance;
  96. }
  97. void gen2_poller_free(Gen2Poller* instance) {
  98. furi_assert(instance);
  99. furi_assert(instance->data);
  100. furi_assert(instance->crypto);
  101. furi_assert(instance->tx_plain_buffer);
  102. furi_assert(instance->rx_plain_buffer);
  103. furi_assert(instance->tx_encrypted_buffer);
  104. furi_assert(instance->rx_encrypted_buffer);
  105. nfc_poller_free(instance->poller);
  106. mf_classic_free(instance->data);
  107. crypto1_free(instance->crypto);
  108. bit_buffer_free(instance->tx_plain_buffer);
  109. bit_buffer_free(instance->rx_plain_buffer);
  110. bit_buffer_free(instance->tx_encrypted_buffer);
  111. bit_buffer_free(instance->rx_encrypted_buffer);
  112. free(instance->mode_ctx.write_ctx.mfc_data_source);
  113. free(instance->mode_ctx.write_ctx.mfc_data_target);
  114. free(instance);
  115. }
  116. NfcCommand gen2_poller_detect_callback(NfcGenericEvent event, void* context) {
  117. furi_assert(context);
  118. furi_assert(event.protocol == NfcProtocolIso14443_3a);
  119. furi_assert(event.event_data);
  120. furi_assert(event.instance);
  121. NfcCommand command = NfcCommandStop;
  122. Gen2PollerDetectContext* detect_ctx = context;
  123. Iso14443_3aPoller* iso3_poller = event.instance;
  124. Iso14443_3aPollerEvent* iso3_event = event.event_data;
  125. detect_ctx->error = Gen2PollerErrorTimeout;
  126. bit_buffer_reset(detect_ctx->tx_buffer);
  127. bit_buffer_append_byte(detect_ctx->tx_buffer, GEN2_CMD_READ_ATS);
  128. bit_buffer_append_byte(detect_ctx->tx_buffer, GEN2_FSDI_256 << 4);
  129. if(iso3_event->type == Iso14443_3aPollerEventTypeReady) {
  130. do {
  131. const Iso14443_3aError iso14443_3a_error = iso14443_3a_poller_send_standard_frame(
  132. iso3_poller, detect_ctx->tx_buffer, detect_ctx->rx_buffer, GEN2_POLLER_MAX_FWT);
  133. if(iso14443_3a_error != Iso14443_3aErrorNone &&
  134. iso14443_3a_error != Iso14443_3aErrorWrongCrc) {
  135. FURI_LOG_E(TAG, "ATS request failed");
  136. detect_ctx->error = Gen2PollerErrorProtocol;
  137. break;
  138. } else {
  139. FURI_LOG_D(TAG, "ATS request succeeded:");
  140. // Check against known ATS responses
  141. for(size_t i = 0; i < COUNT_OF(GEN2_ATS); i++) {
  142. if(memcmp(
  143. bit_buffer_get_data(detect_ctx->rx_buffer),
  144. GEN2_ATS[i],
  145. sizeof(GEN2_ATS[i])) == 0) {
  146. detect_ctx->error = Gen2PollerErrorNone;
  147. break;
  148. }
  149. }
  150. }
  151. } while(false);
  152. } else if(iso3_event->type == Iso14443_3aPollerEventTypeError) {
  153. detect_ctx->error = Gen2PollerErrorTimeout;
  154. }
  155. furi_thread_flags_set(detect_ctx->thread_id, GEN2_POLLER_THREAD_FLAG_DETECTED);
  156. return command;
  157. }
  158. Gen2PollerError gen2_poller_detect(Nfc* nfc) {
  159. furi_assert(nfc);
  160. Gen2PollerDetectContext detect_ctx = {
  161. .poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a),
  162. .tx_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE),
  163. .rx_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE),
  164. .thread_id = furi_thread_get_current_id(),
  165. .detected = false,
  166. .error = Gen2PollerErrorNone,
  167. };
  168. nfc_poller_start(detect_ctx.poller, gen2_poller_detect_callback, &detect_ctx);
  169. uint32_t flags =
  170. furi_thread_flags_wait(GEN2_POLLER_THREAD_FLAG_DETECTED, FuriFlagWaitAny, FuriWaitForever);
  171. if(flags & GEN2_POLLER_THREAD_FLAG_DETECTED) {
  172. furi_thread_flags_clear(GEN2_POLLER_THREAD_FLAG_DETECTED);
  173. }
  174. nfc_poller_stop(detect_ctx.poller);
  175. bit_buffer_free(detect_ctx.tx_buffer);
  176. bit_buffer_free(detect_ctx.rx_buffer);
  177. nfc_poller_free(detect_ctx.poller);
  178. return detect_ctx.error;
  179. }
  180. NfcCommand gen2_poller_idle_handler(Gen2Poller* instance) {
  181. furi_assert(instance);
  182. NfcCommand command = NfcCommandContinue;
  183. instance->mode_ctx.write_ctx.current_block = 0;
  184. instance->gen2_event.type = Gen2PollerEventTypeDetected;
  185. command = instance->callback(instance->gen2_event, instance->context);
  186. instance->state = Gen2PollerStateRequestMode;
  187. return command;
  188. }
  189. NfcCommand gen2_poller_request_mode_handler(Gen2Poller* instance) {
  190. furi_assert(instance);
  191. NfcCommand command = NfcCommandContinue;
  192. instance->gen2_event.type = Gen2PollerEventTypeRequestMode;
  193. command = instance->callback(instance->gen2_event, instance->context);
  194. instance->mode = instance->gen2_event_data.poller_mode.mode;
  195. if(instance->gen2_event_data.poller_mode.mode == Gen2PollerModeWipe) {
  196. instance->state = Gen2PollerStateWriteTargetDataRequest;
  197. } else {
  198. instance->state = Gen2PollerStateWriteSourceDataRequest;
  199. }
  200. return command;
  201. }
  202. NfcCommand gen2_poller_write_source_data_request_handler(Gen2Poller* instance) {
  203. NfcCommand command = NfcCommandContinue;
  204. instance->gen2_event.type = Gen2PollerEventTypeRequestDataToWrite;
  205. command = instance->callback(instance->gen2_event, instance->context);
  206. memcpy(
  207. instance->mode_ctx.write_ctx.mfc_data_source,
  208. instance->gen2_event_data.data_to_write.mfc_data,
  209. sizeof(MfClassicData));
  210. instance->state = Gen2PollerStateWriteTargetDataRequest;
  211. return command;
  212. }
  213. NfcCommand gen2_poller_write_target_data_request_handler(Gen2Poller* instance) {
  214. NfcCommand command = NfcCommandContinue;
  215. instance->gen2_event.type = Gen2PollerEventTypeRequestTargetData;
  216. command = instance->callback(instance->gen2_event, instance->context);
  217. memcpy(
  218. instance->mode_ctx.write_ctx.mfc_data_target,
  219. instance->gen2_event_data.target_data.mfc_data,
  220. sizeof(MfClassicData));
  221. if(instance->mode == Gen2PollerModeWipe) {
  222. instance->state = Gen2PollerStateWipe;
  223. } else {
  224. instance->state = Gen2PollerStateWrite;
  225. }
  226. return command;
  227. }
  228. Gen2PollerError gen2_poller_write_block_handler(
  229. Gen2Poller* instance,
  230. uint8_t block_num,
  231. MfClassicBlock* block) {
  232. furi_assert(instance);
  233. Gen2PollerError error = Gen2PollerErrorNone;
  234. Gen2PollerWriteContext* write_ctx = &instance->mode_ctx.write_ctx;
  235. MfClassicKey auth_key = write_ctx->auth_key;
  236. do {
  237. // Compare the target and source data
  238. if(memcmp(block->data, write_ctx->mfc_data_target->block[block_num].data, 16) == 0) {
  239. FURI_LOG_D(TAG, "Block %d is the same, skipping", block_num);
  240. break;
  241. }
  242. // Reauth if necessary
  243. if(write_ctx->need_halt_before_write) {
  244. FURI_LOG_D(TAG, "Auth before writing block %d", write_ctx->current_block);
  245. error = gen2_poller_auth(
  246. instance, write_ctx->current_block, &auth_key, write_ctx->write_key, NULL);
  247. if(error != Gen2PollerErrorNone) {
  248. FURI_LOG_D(
  249. TAG, "Failed to auth to block %d for writing", write_ctx->current_block);
  250. break;
  251. }
  252. }
  253. // Write the block
  254. error = gen2_poller_write_block(instance, write_ctx->current_block, block);
  255. if(error != Gen2PollerErrorNone) {
  256. FURI_LOG_D(TAG, "Failed to write block %d", write_ctx->current_block);
  257. break;
  258. }
  259. } while(false);
  260. FURI_LOG_D(TAG, "Block %d finished, halting", write_ctx->current_block);
  261. gen2_poller_halt(instance);
  262. return error;
  263. }
  264. NfcCommand gen2_poller_wipe_handler(Gen2Poller* instance) {
  265. NfcCommand command = NfcCommandContinue;
  266. Gen2PollerError error = Gen2PollerErrorNone;
  267. Gen2PollerWriteContext* write_ctx = &instance->mode_ctx.write_ctx;
  268. uint8_t block_num = write_ctx->current_block;
  269. do {
  270. // Check whether the ACs for that block are known in target data
  271. if(!mf_classic_is_block_read(
  272. write_ctx->mfc_data_target,
  273. mf_classic_get_sector_trailer_num_by_block(block_num))) {
  274. FURI_LOG_E(TAG, "Sector trailer for block %d not present in target data", block_num);
  275. break;
  276. }
  277. // Check whether ACs need to be reset and whether they can be reset
  278. if(!gen2_poller_can_write_block(write_ctx->mfc_data_target, block_num)) {
  279. if(!gen2_can_reset_access_conditions(write_ctx->mfc_data_target, block_num)) {
  280. FURI_LOG_E(TAG, "Block %d cannot be written", block_num);
  281. break;
  282. } else {
  283. FURI_LOG_D(TAG, "Resetting ACs for block %d", block_num);
  284. // Generate a block with old keys and default ACs (0xFF, 0x07, 0x80)
  285. MfClassicBlock block;
  286. memset(&block, 0, sizeof(block));
  287. memcpy(block.data, write_ctx->mfc_data_target->block[block_num].data, 16);
  288. memcpy(block.data + 6, "\xFF\x07\x80", 3);
  289. error = gen2_poller_write_block_handler(instance, block_num, &block);
  290. if(error != Gen2PollerErrorNone) {
  291. FURI_LOG_E(TAG, "Failed to reset ACs for block %d", block_num);
  292. break;
  293. } else {
  294. FURI_LOG_D(TAG, "ACs for block %d reset", block_num);
  295. memcpy(write_ctx->mfc_data_target->block[block_num].data, block.data, 16);
  296. }
  297. }
  298. }
  299. // Figure out which key to use for writing
  300. write_ctx->write_key =
  301. gen2_poller_get_key_type_to_write(write_ctx->mfc_data_target, block_num);
  302. // Get the key to use for writing from the target data
  303. MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(
  304. write_ctx->mfc_data_target, mf_classic_get_sector_by_block(block_num));
  305. if(write_ctx->write_key == MfClassicKeyTypeA) {
  306. write_ctx->auth_key = sec_tr->key_a;
  307. } else {
  308. write_ctx->auth_key = sec_tr->key_b;
  309. }
  310. // Write the default block depending on the block type
  311. if(block_num == 0) {
  312. error =
  313. gen2_poller_write_block_handler(instance, block_num, &gen2_poller_default_block_0);
  314. } else if(mf_classic_is_sector_trailer(block_num)) {
  315. error = gen2_poller_write_block_handler(
  316. instance, block_num, &gen2_poller_default_sector_trailer_block);
  317. } else {
  318. error = gen2_poller_write_block_handler(
  319. instance, block_num, &gen2_poller_default_empty_block);
  320. }
  321. if(error != Gen2PollerErrorNone) {
  322. FURI_LOG_E(TAG, "Couldn't write block %d", block_num);
  323. }
  324. } while(false);
  325. write_ctx->current_block++;
  326. if(error != Gen2PollerErrorNone) {
  327. FURI_LOG_D(TAG, "Error occurred: %d", error);
  328. } else if(
  329. write_ctx->current_block ==
  330. mf_classic_get_total_block_num(write_ctx->mfc_data_target->type)) {
  331. instance->state = Gen2PollerStateSuccess;
  332. }
  333. return command;
  334. }
  335. NfcCommand gen2_poller_write_handler(Gen2Poller* instance) {
  336. NfcCommand command = NfcCommandContinue;
  337. Gen2PollerError error = Gen2PollerErrorNone;
  338. Gen2PollerWriteContext* write_ctx = &instance->mode_ctx.write_ctx;
  339. uint8_t block_num = write_ctx->current_block;
  340. do {
  341. // Check whether the block is present in the source data
  342. if(!mf_classic_is_block_read(write_ctx->mfc_data_source, block_num)) {
  343. // FURI_LOG_E(TAG, "Block %d not present in source data", block_num);
  344. break;
  345. }
  346. // Check whether the ACs for that block are known in target data
  347. if(!mf_classic_is_block_read(
  348. write_ctx->mfc_data_target,
  349. mf_classic_get_sector_trailer_num_by_block(block_num))) {
  350. FURI_LOG_E(TAG, "Sector trailer for block %d not present in target data", block_num);
  351. break;
  352. }
  353. // Check whether ACs need to be reset and whether they can be reset
  354. if(!gen2_poller_can_write_block(write_ctx->mfc_data_target, block_num)) {
  355. if(!gen2_can_reset_access_conditions(write_ctx->mfc_data_target, block_num)) {
  356. FURI_LOG_E(TAG, "Block %d cannot be written", block_num);
  357. break;
  358. } else {
  359. FURI_LOG_D(TAG, "Resetting ACs for block %d", block_num);
  360. // Generate a block with old keys and default ACs (0xFF, 0x07, 0x80)
  361. MfClassicBlock block;
  362. memset(&block, 0, sizeof(block));
  363. memcpy(block.data, write_ctx->mfc_data_target->block[block_num].data, 16);
  364. memcpy(block.data + 6, "\xFF\x07\x80", 3);
  365. error = gen2_poller_write_block_handler(instance, block_num, &block);
  366. if(error != Gen2PollerErrorNone) {
  367. FURI_LOG_E(TAG, "Failed to reset ACs for block %d", block_num);
  368. break;
  369. } else {
  370. FURI_LOG_D(TAG, "ACs for block %d reset", block_num);
  371. memcpy(write_ctx->mfc_data_target->block[block_num].data, block.data, 16);
  372. }
  373. }
  374. }
  375. // Figure out which key to use for writing
  376. write_ctx->write_key =
  377. gen2_poller_get_key_type_to_write(write_ctx->mfc_data_target, block_num);
  378. // Get the key to use for writing from the target data
  379. MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(
  380. write_ctx->mfc_data_target, mf_classic_get_sector_by_block(block_num));
  381. if(write_ctx->write_key == MfClassicKeyTypeA) {
  382. write_ctx->auth_key = sec_tr->key_a;
  383. } else {
  384. write_ctx->auth_key = sec_tr->key_b;
  385. }
  386. // Write the block
  387. error = gen2_poller_write_block_handler(
  388. instance, block_num, &write_ctx->mfc_data_source->block[block_num]);
  389. if(error != Gen2PollerErrorNone) {
  390. FURI_LOG_E(TAG, "Couldn't write block %d", block_num);
  391. }
  392. } while(false);
  393. write_ctx->current_block++;
  394. if(error != Gen2PollerErrorNone) {
  395. FURI_LOG_D(TAG, "Error occurred: %d", error);
  396. } else if(
  397. write_ctx->current_block ==
  398. mf_classic_get_total_block_num(write_ctx->mfc_data_source->type)) {
  399. instance->state = Gen2PollerStateSuccess;
  400. }
  401. return command;
  402. }
  403. NfcCommand gen2_poller_success_handler(Gen2Poller* instance) {
  404. furi_assert(instance);
  405. NfcCommand command = NfcCommandContinue;
  406. instance->gen2_event.type = Gen2PollerEventTypeSuccess;
  407. command = instance->callback(instance->gen2_event, instance->context);
  408. instance->state = Gen2PollerStateIdle;
  409. return command;
  410. }
  411. NfcCommand gen2_poller_fail_handler(Gen2Poller* instance) {
  412. furi_assert(instance);
  413. NfcCommand command = NfcCommandContinue;
  414. instance->gen2_event.type = Gen2PollerEventTypeFail;
  415. command = instance->callback(instance->gen2_event, instance->context);
  416. instance->state = Gen2PollerStateIdle;
  417. return command;
  418. }
  419. static const Gen2PollerStateHandler gen2_poller_state_handlers[Gen2PollerStateNum] = {
  420. [Gen2PollerStateIdle] = gen2_poller_idle_handler,
  421. [Gen2PollerStateRequestMode] = gen2_poller_request_mode_handler,
  422. [Gen2PollerStateWipe] = gen2_poller_wipe_handler,
  423. [Gen2PollerStateWriteSourceDataRequest] = gen2_poller_write_source_data_request_handler,
  424. [Gen2PollerStateWriteTargetDataRequest] = gen2_poller_write_target_data_request_handler,
  425. [Gen2PollerStateWrite] = gen2_poller_write_handler,
  426. [Gen2PollerStateSuccess] = gen2_poller_success_handler,
  427. [Gen2PollerStateFail] = gen2_poller_fail_handler,
  428. };
  429. NfcCommand gen2_poller_callback(NfcGenericEvent event, void* context) {
  430. furi_assert(context);
  431. furi_assert(event.protocol == NfcProtocolIso14443_3a);
  432. furi_assert(event.event_data);
  433. furi_assert(event.instance);
  434. NfcCommand command = NfcCommandContinue;
  435. Gen2Poller* instance = context;
  436. instance->iso3_poller = event.instance;
  437. Iso14443_3aPollerEvent* iso3_event = event.event_data;
  438. if(iso3_event->type == Iso14443_3aPollerEventTypeReady) {
  439. command = gen2_poller_state_handlers[instance->state](instance);
  440. }
  441. return command;
  442. }
  443. void gen2_poller_start(Gen2Poller* instance, Gen2PollerCallback callback, void* context) {
  444. furi_assert(instance);
  445. furi_assert(callback);
  446. instance->callback = callback;
  447. instance->context = context;
  448. nfc_poller_start(instance->poller, gen2_poller_callback, instance);
  449. return;
  450. }
  451. void gen2_poller_stop(Gen2Poller* instance) {
  452. furi_assert(instance);
  453. FURI_LOG_D(TAG, "Stopping Gen2 poller");
  454. nfc_poller_stop(instance->poller);
  455. return;
  456. }
  457. Gen2PollerWriteProblem gen2_poller_can_write_everything(NfcDevice* device) {
  458. furi_assert(device);
  459. Gen2PollerWriteProblem problem = Gen2PollerWriteProblemNone;
  460. Gen2PollerWriteProblem problem_next = Gen2PollerWriteProblemNone;
  461. const MfClassicData* mfc_data = nfc_device_get_data(device, NfcProtocolMfClassic);
  462. if(mfc_data) {
  463. uint16_t total_block_num = mf_classic_get_total_block_num(mfc_data->type);
  464. for(uint16_t i = 0; i < total_block_num; i++) {
  465. if(mf_classic_is_sector_trailer(i)) {
  466. problem_next = gen2_poller_can_write_sector_trailer(mfc_data, i);
  467. } else {
  468. problem_next = gen2_poller_can_write_data_block(mfc_data, i);
  469. }
  470. if(problem_next < problem) {
  471. problem = problem_next;
  472. }
  473. }
  474. } else {
  475. problem = Gen2PollerWriteProblemNoData;
  476. }
  477. return problem;
  478. }