nfc_t2t_parser.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. /**
  2. * Copyright (c) 2015 - 2019, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. #include "sdk_common.h"
  41. #if NRF_MODULE_ENABLED(NFC_T2T_PARSER)
  42. #include <string.h>
  43. #include <stdbool.h>
  44. #include "nrf_delay.h"
  45. #include "nfc_t2t_parser.h"
  46. #define NRF_LOG_MODULE_NAME nfc_t2t_parser
  47. #if NFC_T2T_PARSER_LOG_ENABLED
  48. #define NRF_LOG_LEVEL NFC_T2T_PARSER_LOG_LEVEL
  49. #define NRF_LOG_INFO_COLOR NFC_T2T_PARSER_INFO_COLOR
  50. #include "nrf_log.h"
  51. NRF_LOG_MODULE_REGISTER();
  52. #else // NFC_T2T_PARSER_LOG_ENABLED
  53. #define NRF_LOG_LEVEL 0
  54. #include "nrf_log.h"
  55. #endif // NFC_T2T_PARSER_LOG_ENABLED
  56. /// Gets least significant nibble (a 4-bit value) from a byte.
  57. #define LSN_GET(val) (val & 0x0F)
  58. /// Gets most significant nibble (a 4-bit value) from a byte.
  59. #define MSN_GET(val) ((val >> 4) & 0x0F)
  60. /**
  61. * @brief Function for inserting the TLV block into a @ref type_2_tag_t structure.
  62. *
  63. * The content of a TLV block structure pointed by the p_tlv_block is copied into a TLV block
  64. * array within the structure pointed by the p_type_2_tag.
  65. *
  66. * @param[in,out] p_type_2_tag Pointer to the structure that contains the TLV blocks array.
  67. * @param[in] p_tlv_block Pointer to the TLV block to insert.
  68. *
  69. * @retval NRF_SUCCESS If the block was inserted successfully.
  70. * @retval NRF_ERROR_NO_MEM If there is already maximum number of blocks stored in the array.
  71. *
  72. */
  73. static ret_code_t type_2_tag_tlv_block_insert(type_2_tag_t * p_type_2_tag,
  74. tlv_block_t * p_tlv_block)
  75. {
  76. if (p_type_2_tag->tlv_count == p_type_2_tag->max_tlv_blocks)
  77. {
  78. return NRF_ERROR_NO_MEM;
  79. }
  80. // Copy contents of the source block.
  81. p_type_2_tag->p_tlv_block_array[p_type_2_tag->tlv_count] = *p_tlv_block;
  82. p_type_2_tag->tlv_count++;
  83. return NRF_SUCCESS;
  84. }
  85. /**
  86. * @brief Function for checking if the TLV block length is correct.
  87. *
  88. * Some TLV block has predefined length:
  89. * TLV_NULL and TLV_TERMINATOR always have a length of 1 byte.
  90. * TLV_LOCK_CONTROL and TLV_MEMORY_CONTROL always have a length of 3 bytes.
  91. *
  92. * @param[in] p_block_to_check Pointer to the structure that contains the TLV block length.
  93. *
  94. * @retval TRUE If the length is correct.
  95. * @retval FALSE Otherwise.
  96. *
  97. */
  98. static bool tlv_block_is_data_length_correct(tlv_block_t * p_block_to_check)
  99. {
  100. switch (p_block_to_check->tag)
  101. {
  102. case TLV_NULL:
  103. case TLV_TERMINATOR:
  104. if (p_block_to_check->length != TLV_NULL_TERMINATOR_LEN)
  105. {
  106. return false;
  107. }
  108. break;
  109. case TLV_LOCK_CONTROL:
  110. case TLV_MEMORY_CONTROL:
  111. if (p_block_to_check->length != TLV_LOCK_MEMORY_CTRL_LEN)
  112. {
  113. return false;
  114. }
  115. break;
  116. case TLV_NDEF_MESSAGE:
  117. case TLV_PROPRIETARY:
  118. default:
  119. // Any length will do.
  120. break;
  121. }
  122. return true;
  123. }
  124. /**
  125. * @brief Function for checking if the end of the tag data area was reached.
  126. *
  127. * @param[in] p_type_2_tag Pointer to the structure that contains the data area size.
  128. * @param[in] offset Current byte offset.
  129. *
  130. * @retval TRUE If the offset indicates the end of the data area.
  131. * @retval FALSE Otherwise.
  132. *
  133. */
  134. static bool type_2_tag_is_end_reached(type_2_tag_t * p_type_2_tag, uint16_t offset)
  135. {
  136. return offset == (p_type_2_tag->cc.data_area_size + T2T_FIRST_DATA_BLOCK_OFFSET);
  137. }
  138. /**
  139. * @brief Function for checking if version of Type 2 Tag specification read from a tag is supported.
  140. *
  141. * @param[in] p_type_2_tag Pointer to the structure that contains the tag version.
  142. *
  143. * @retval TRUE If the version is supported and tag data can be parsed.
  144. * @retval FALSE Otherwise.
  145. *
  146. */
  147. static bool type_2_tag_is_version_supported(type_2_tag_t * p_type_2_tag)
  148. {
  149. // Simple check atm, as only 1 major version has been issued so far, so no backward compatibility
  150. // is needed, tags with newer version implemented shall be rejected according to the doc.
  151. return p_type_2_tag->cc.major_version == T2T_SUPPORTED_MAJOR_VERSION;
  152. }
  153. /**
  154. * @brief Function for checking if the field fits into the data area specified in
  155. * the Capability Container.
  156. *
  157. * @param[in] p_type_2_tag Pointer to the structure that contains the data area size.
  158. * @param[in] offset As Offset of the field to check.
  159. * @param[in] field_length Length of the field to check.
  160. *
  161. * @retval TRUE If the field fits into the data area.
  162. * @retval FALSE If the field exceeds the data area.
  163. *
  164. */
  165. static bool type_2_tag_is_field_within_data_range(type_2_tag_t * p_type_2_tag,
  166. uint16_t offset,
  167. uint16_t field_length)
  168. {
  169. // Invalid argument, return false.
  170. if (field_length == 0)
  171. {
  172. return false;
  173. }
  174. return ( (offset + field_length - 1) <
  175. (p_type_2_tag->cc.data_area_size + T2T_FIRST_DATA_BLOCK_OFFSET) )
  176. && ( offset >= T2T_FIRST_DATA_BLOCK_OFFSET );
  177. }
  178. /**
  179. * @brief Function for reading the tag field of a TLV block from the p_raw_data buffer.
  180. *
  181. * This function reads the tag field containing a TLV block type and inserts its value into
  182. * a structure pointed by the p_tlv_buf pointer.
  183. *
  184. * @param[in] p_type_2_tag Pointer to the structure that contains Type 2 Tag data parsed so far.
  185. * @param[in] p_raw_data Pointer to the buffer with a raw data from the tag.
  186. * @param[in,out] p_t_offset As input: offset of the tag field to read. As output: offset of
  187. * the first byte after the tag field.
  188. * @param[out] p_tlv_buf Pointer to a @ref tlv_block_t structure where the tag type will be
  189. * inserted.
  190. *
  191. * @retval NRF_SUCCESS If the tag field at specified offset is correct.
  192. * @retval NRF_ERROR_INVALID_DATA If the tag field at specified offset exceeds the data
  193. * area specified in the Capability Container.
  194. *
  195. */
  196. static ret_code_t type_2_tag_type_extract(type_2_tag_t * p_type_2_tag,
  197. uint8_t * p_raw_data,
  198. uint16_t * p_t_offset,
  199. tlv_block_t * p_tlv_buf)
  200. {
  201. if (!type_2_tag_is_field_within_data_range(p_type_2_tag, *p_t_offset, TLV_T_LENGTH))
  202. {
  203. return NRF_ERROR_INVALID_DATA;
  204. }
  205. p_tlv_buf->tag = p_raw_data[*p_t_offset];
  206. *p_t_offset += TLV_T_LENGTH;
  207. return NRF_SUCCESS;
  208. }
  209. /**
  210. * @brief Function for reading the length field of a TLV block from the p_raw_data buffer.
  211. *
  212. * This function reads the length field of a TLV block and inserts its value into a structure
  213. * pointed by the p_tlv_buf pointer.
  214. *
  215. * @param[in] p_type_2_tag Pointer to the structure that contains Type 2 Tag data parsed so far.
  216. * @param[in] p_raw_data Pointer to the buffer with a raw data from the tag.
  217. * @param[in,out] p_l_offset As input: offset of the length field to read. As output: offset of
  218. * the first byte after the length field.
  219. * @param[out] p_tlv_buf Pointer to a @ref tlv_block_t structure where the length will be
  220. * inserted.
  221. *
  222. * @retval NRF_SUCCESS If the length field at specified offset is correct.
  223. * @retval NRF_ERROR_INVALID_DATA If the length field at specified offset exceeds the data
  224. * area specified in the Capability Container or has
  225. * incorrect format.
  226. *
  227. */
  228. static ret_code_t type_2_tag_length_extract(type_2_tag_t * p_type_2_tag,
  229. uint8_t * p_raw_data,
  230. uint16_t * p_l_offset,
  231. tlv_block_t * p_tlv_buf)
  232. {
  233. uint16_t length;
  234. if (!type_2_tag_is_field_within_data_range(p_type_2_tag, *p_l_offset, TLV_L_SHORT_LENGTH))
  235. {
  236. return NRF_ERROR_INVALID_DATA;
  237. }
  238. length = p_raw_data[*p_l_offset];
  239. if (length == TLV_L_FORMAT_FLAG)
  240. {
  241. // Check another two bytes.
  242. if (!type_2_tag_is_field_within_data_range(p_type_2_tag, *p_l_offset, TLV_L_LONG_LENGTH))
  243. {
  244. return NRF_ERROR_INVALID_DATA;
  245. }
  246. length = uint16_big_decode(&p_raw_data[*p_l_offset + 1]);
  247. // Long length value cannot be lower than 0xFF.
  248. if (length < 0xFF)
  249. {
  250. return NRF_ERROR_INVALID_DATA;
  251. }
  252. p_tlv_buf->length = length;
  253. *p_l_offset += TLV_L_LONG_LENGTH;
  254. }
  255. else
  256. {
  257. p_tlv_buf->length = length;
  258. *p_l_offset += TLV_L_SHORT_LENGTH;
  259. }
  260. return NRF_SUCCESS;
  261. }
  262. /**
  263. * @brief Function for reading a pointer to the value field of a TLV block from the p_raw_data buffer.
  264. *
  265. * This function reads a pointer to the value field of a TLV block and inserts it into
  266. * a structure pointed by the p_tlv_buf pointer. If there is no value field present in the
  267. * TLV block, NULL is inserted.
  268. *
  269. * @param[in] p_type_2_tag Pointer to the structure that contains Type 2 Tag data parsed so far.
  270. * @param[in] p_raw_data Pointer to the buffer with a raw data from the tag.
  271. * @param[in,out] p_v_offset As input: offset of the value field to read. As output: offset of
  272. * the first byte after the value field.
  273. * @param[in,out] p_tlv_buf Pointer to a @ref tlv_block_t structure where the value field
  274. * pointer will be inserted.
  275. *
  276. * @retval NRF_SUCCESS If the value field at specified offset is correct.
  277. * @retval NRF_ERROR_INVALID_DATA If the value field at specified offset exceeds the data
  278. * area specified in the Capability Container.
  279. *
  280. */
  281. static ret_code_t type_2_tag_value_ptr_extract(type_2_tag_t * p_type_2_tag,
  282. uint8_t * p_raw_data,
  283. uint16_t * p_v_offset,
  284. tlv_block_t * p_tlv_buf)
  285. {
  286. if (p_tlv_buf->length == 0)
  287. {
  288. // Clear the value pointer, don't touch the offset.
  289. p_tlv_buf->p_value = NULL;
  290. }
  291. else
  292. {
  293. if (!type_2_tag_is_field_within_data_range(p_type_2_tag, *p_v_offset, p_tlv_buf->length))
  294. {
  295. return NRF_ERROR_INVALID_DATA;
  296. }
  297. p_tlv_buf->p_value = p_raw_data + *p_v_offset;
  298. *p_v_offset += p_tlv_buf->length;
  299. }
  300. return NRF_SUCCESS;
  301. }
  302. /**
  303. * @brief Function for reading a single TLV block from the p_raw_data buffer.
  304. *
  305. * This function reads a single TLV block from the p_raw_data buffer and stores its contents in a
  306. * structure pointed by the p_tlv_buf.
  307. *
  308. * @param[in] p_type_2_tag Pointer to the structure that contains Type 2 Tag data parsed so far.
  309. * @param[in] p_raw_data Pointer to the buffer with a raw data from the tag.
  310. * @param[in,out] p_tlv_offset As input: offset of the TLV block to read. As output: offset of the
  311. * next TLV block, 0 if it was the last block.
  312. * @param[out] p_tlv_buf Pointer to a @ref tlv_block_t structure that will be filled with
  313. * the data read.
  314. *
  315. * @retval NRF_SUCCESS If the parsing operation of the block succeeded. Otherwise, an error
  316. * code is returned.
  317. *
  318. */
  319. static ret_code_t type_2_tag_tlv_block_extract(type_2_tag_t * p_type_2_tag,
  320. uint8_t * p_raw_data,
  321. uint16_t * p_offset,
  322. tlv_block_t * p_tlv_buf)
  323. {
  324. ret_code_t err_code;
  325. memset(p_tlv_buf, 0, sizeof(tlv_block_t));
  326. // TLV Tag field.
  327. err_code = type_2_tag_type_extract(p_type_2_tag, p_raw_data, p_offset, p_tlv_buf);
  328. if (err_code != NRF_SUCCESS)
  329. {
  330. return err_code;
  331. }
  332. // Further processing depends on tag field value.
  333. switch (p_tlv_buf->tag)
  334. {
  335. case TLV_NULL:
  336. // Simply ignore NULL blocks, leave the incremented offset.
  337. break;
  338. case TLV_TERMINATOR:
  339. // Write 0 to the offset variable, indicating that last TLV block was found.
  340. *p_offset = 0;
  341. break;
  342. case TLV_LOCK_CONTROL:
  343. case TLV_MEMORY_CONTROL:
  344. case TLV_NDEF_MESSAGE:
  345. case TLV_PROPRIETARY:
  346. default:
  347. // Unknown blocks should also be extracted.
  348. err_code = type_2_tag_length_extract(p_type_2_tag, p_raw_data, p_offset, p_tlv_buf);
  349. if (err_code != NRF_SUCCESS)
  350. {
  351. return err_code;
  352. }
  353. if (p_tlv_buf->length > 0)
  354. {
  355. err_code = type_2_tag_value_ptr_extract(p_type_2_tag, p_raw_data, p_offset, p_tlv_buf);
  356. if (err_code != NRF_SUCCESS)
  357. {
  358. return err_code;
  359. }
  360. }
  361. break;
  362. }
  363. return NRF_SUCCESS;
  364. }
  365. /**
  366. * @brief Function for checking the checksum bytes of the UID stored in internal area.
  367. *
  368. * This function calculates the block check character (BCC) bytes based on the parsed serial number
  369. * and compares them with bytes read from the Type 2 Tag.
  370. *
  371. * @param[in] p_sn Pointer to the @ref type_2_tag_serial_number_t structure to check.
  372. *
  373. * @retval TRUE If the calculated BCC matched the BCC from the tag.
  374. * @retval FALSE Otherwise.
  375. *
  376. */
  377. static bool type_2_tag_is_bcc_correct(type_2_tag_serial_number_t * p_sn)
  378. {
  379. uint8_t bcc1 = (uint8_t)T2T_UID_BCC_CASCADE_BYTE ^
  380. (uint8_t)p_sn->manufacturer_id ^
  381. (uint8_t)((p_sn->serial_number_part_1 >> 8) & 0xFF) ^
  382. (uint8_t)(p_sn->serial_number_part_1 & 0xFF);
  383. uint8_t bcc2 = (uint8_t)((p_sn->serial_number_part_2 >> 24) & 0xFF) ^
  384. (uint8_t)((p_sn->serial_number_part_2 >> 16) & 0xFF) ^
  385. (uint8_t)((p_sn->serial_number_part_2 >> 8) & 0xFF) ^
  386. (uint8_t)( p_sn->serial_number_part_2 & 0xFF);
  387. return (bcc1 == p_sn->check_byte_0) && (bcc2 == p_sn->check_byte_1);
  388. }
  389. /**
  390. * @brief Function for parsing an internal area of a Type 2 Tag.
  391. *
  392. * This function reads data from an internal area in the raw data buffer and fills the
  393. * @ref type_2_tag_serial_number_t structure within @ref type_2_tag_t.
  394. *
  395. * @param[in,out] p_type_2_tag Pointer to the structure that will be filled with parsed data.
  396. * @param[in] p_raw_data Pointer to the buffer with raw data from the tag.
  397. *
  398. * @retval NRF_SUCCESS If the parsing operation of the internal area succeeded.
  399. * Otherwise, an error code is returned.
  400. *
  401. */
  402. static ret_code_t type_2_tag_internal_parse(type_2_tag_t * p_type_2_tag, uint8_t * p_raw_data)
  403. {
  404. p_type_2_tag->sn.manufacturer_id = p_raw_data[0];
  405. p_type_2_tag->sn.serial_number_part_1 = uint16_big_decode(&p_raw_data[1]);
  406. p_type_2_tag->sn.check_byte_0 = p_raw_data[3];
  407. p_type_2_tag->sn.serial_number_part_2 = uint32_big_decode(&p_raw_data[4]);
  408. p_type_2_tag->sn.check_byte_1 = p_raw_data[8];
  409. p_type_2_tag->sn.internal = p_raw_data[9];
  410. p_type_2_tag->lock_bytes = uint16_big_decode(&p_raw_data[10]);
  411. if (!type_2_tag_is_bcc_correct(&p_type_2_tag->sn))
  412. {
  413. NRF_LOG_WARNING("Warning! BCC of the serial number is not correct!");
  414. }
  415. return NRF_SUCCESS;
  416. }
  417. /**
  418. * @brief Function for parsing a Capabiliy Container area of a Type 2 Tag.
  419. *
  420. * This function reads data from a Capability Container area in the raw data buffer and fills the
  421. * @ref type_2_tag_capability_container_t structure within @ref type_2_tag_t.
  422. *
  423. * @param[in,out] p_type_2_tag Pointer to the structure that will be filled with parsed data.
  424. * @param[in] p_raw_data Pointer to the buffer with raw data from the tag.
  425. *
  426. * @retval NRF_SUCCESS If the parsing operation of the Capability Container succeeded.
  427. * Otherwise, an error code is returned.
  428. *
  429. */
  430. static ret_code_t type_2_tag_cc_parse(type_2_tag_t * p_type_2_tag, uint8_t * p_raw_data)
  431. {
  432. uint8_t * p_cc_block = p_raw_data + T2T_CC_BLOCK_OFFSET;
  433. if (p_cc_block[0] != T2T_NFC_FORUM_DEFINED_DATA)
  434. {
  435. return NRF_ERROR_INVALID_DATA;
  436. }
  437. p_type_2_tag->cc.major_version = MSN_GET(p_cc_block[1]);
  438. p_type_2_tag->cc.minor_version = LSN_GET(p_cc_block[1]);
  439. p_type_2_tag->cc.data_area_size = p_cc_block[2] * 8;
  440. p_type_2_tag->cc.read_access = MSN_GET(p_cc_block[3]);
  441. p_type_2_tag->cc.write_access = LSN_GET(p_cc_block[3]);
  442. return NRF_SUCCESS;
  443. }
  444. /**
  445. * @brief Function for parsing a single TLV block.
  446. *
  447. * This function reads a single TLV block from the raw data buffer, from the position indicated by
  448. * the p_tlv_offset, and adds it to the @ref type_2_tag_t structure.
  449. *
  450. * @param[in,out] p_type_2_tag Pointer to the structure that will be filled with parsed data.
  451. * @param[in] p_raw_data Pointer to the buffer with raw data from the tag.
  452. * @param[in,out] p_tlv_offset As input: offset of the TLV block to parse. As output: offset of the
  453. * next TLV block, 0 if it was the last block.
  454. *
  455. * @retval NRF_SUCCESS If the parsing operation of the block succeeded. Otherwise, an error
  456. * code is returned.
  457. *
  458. */
  459. static ret_code_t type_2_tag_tlv_parse(type_2_tag_t * p_type_2_tag,
  460. uint8_t * p_raw_data,
  461. uint16_t * p_tlv_offset)
  462. {
  463. ret_code_t err_code;
  464. tlv_block_t new_block;
  465. // Get tag field.
  466. err_code = type_2_tag_tlv_block_extract(p_type_2_tag, p_raw_data, p_tlv_offset, &new_block);
  467. if (err_code != NRF_SUCCESS)
  468. {
  469. return err_code;
  470. }
  471. if (!tlv_block_is_data_length_correct(&new_block))
  472. {
  473. return NRF_ERROR_INVALID_DATA;
  474. }
  475. // Further action depends on tag type.
  476. switch (new_block.tag)
  477. {
  478. case TLV_NULL:
  479. case TLV_TERMINATOR:
  480. // Ignore them.
  481. break;
  482. case TLV_LOCK_CONTROL:
  483. case TLV_MEMORY_CONTROL:
  484. case TLV_NDEF_MESSAGE:
  485. case TLV_PROPRIETARY:
  486. default:
  487. // Unknown tag types are also added.
  488. err_code = type_2_tag_tlv_block_insert(p_type_2_tag, &new_block);
  489. if (err_code != NRF_SUCCESS)
  490. {
  491. NRF_LOG_WARNING("Warning! Not enough memory to insert all of the blocks!");
  492. return err_code;
  493. }
  494. break;
  495. }
  496. return NRF_SUCCESS;
  497. }
  498. void type_2_tag_clear(type_2_tag_t * p_type_2_tag)
  499. {
  500. p_type_2_tag->tlv_count = 0;
  501. memset(&p_type_2_tag->cc, 0, sizeof(p_type_2_tag->cc));
  502. memset(&p_type_2_tag->sn, 0, sizeof(p_type_2_tag->sn));
  503. }
  504. ret_code_t type_2_tag_parse(type_2_tag_t * p_type_2_tag, uint8_t * p_raw_data)
  505. {
  506. ret_code_t err_code;
  507. type_2_tag_clear(p_type_2_tag);
  508. err_code = type_2_tag_internal_parse(p_type_2_tag, p_raw_data);
  509. if (err_code != NRF_SUCCESS)
  510. {
  511. return err_code;
  512. }
  513. err_code = type_2_tag_cc_parse(p_type_2_tag, p_raw_data);
  514. if (err_code != NRF_SUCCESS)
  515. {
  516. return err_code;
  517. }
  518. if (!type_2_tag_is_version_supported(p_type_2_tag))
  519. {
  520. return NRF_ERROR_NOT_SUPPORTED;
  521. }
  522. uint16_t offset = T2T_FIRST_DATA_BLOCK_OFFSET;
  523. while (offset > 0)
  524. {
  525. // Check if end of tag is reached (no terminator block was present).
  526. if (type_2_tag_is_end_reached(p_type_2_tag, offset))
  527. {
  528. NRF_LOG_DEBUG("No terminator block was found in the tag!");
  529. break;
  530. }
  531. err_code = type_2_tag_tlv_parse(p_type_2_tag, p_raw_data, &offset);
  532. if (err_code != NRF_SUCCESS)
  533. {
  534. return err_code;
  535. }
  536. }
  537. return NRF_SUCCESS;
  538. }
  539. void type_2_tag_printout(type_2_tag_t * p_type_2_tag)
  540. {
  541. uint32_t i;
  542. NRF_LOG_INFO("Type 2 Tag contents:");
  543. NRF_LOG_INFO("Number of TLV blocks: %d", p_type_2_tag->tlv_count);
  544. NRF_LOG_DEBUG("Internal data:");
  545. NRF_LOG_DEBUG(" Manufacturer ID: 0x%02x", p_type_2_tag->sn.manufacturer_id);
  546. NRF_LOG_DEBUG(" Serial number part 1: 0x%04x", p_type_2_tag->sn.serial_number_part_1);
  547. NRF_LOG_DEBUG(" Check byte 0: 0x%02x", p_type_2_tag->sn.check_byte_0);
  548. NRF_LOG_DEBUG(" Serial number part 2: 0x%08lx", p_type_2_tag->sn.serial_number_part_2);
  549. NRF_LOG_DEBUG(" Check byte 1: 0x%02x", p_type_2_tag->sn.check_byte_1);
  550. NRF_LOG_DEBUG(" Internal byte: 0x%02x", p_type_2_tag->sn.internal);
  551. NRF_LOG_DEBUG(" Lock bytes: 0x%04x", p_type_2_tag->lock_bytes);
  552. NRF_LOG_DEBUG("Capability Container data:");
  553. NRF_LOG_DEBUG(" Major version number: %d", p_type_2_tag->cc.major_version);
  554. NRF_LOG_DEBUG(" Minor version number: %d", p_type_2_tag->cc.minor_version);
  555. NRF_LOG_DEBUG(" Data area size: %d", p_type_2_tag->cc.data_area_size);
  556. NRF_LOG_DEBUG(" Read access: 0x%02X", p_type_2_tag->cc.read_access);
  557. NRF_LOG_DEBUG(" Write access: 0x%02X", p_type_2_tag->cc.write_access);
  558. for (i = 0; i < p_type_2_tag->tlv_count; i++)
  559. {
  560. NRF_LOG_INFO("TLV block 0x%02X: ", p_type_2_tag->p_tlv_block_array[i].tag);
  561. switch (p_type_2_tag->p_tlv_block_array[i].tag)
  562. {
  563. case TLV_LOCK_CONTROL:
  564. NRF_LOG_INFO("Lock Control");
  565. break;
  566. case TLV_MEMORY_CONTROL:
  567. NRF_LOG_INFO("Memory Control");
  568. break;
  569. case TLV_NDEF_MESSAGE:
  570. NRF_LOG_INFO("NDEF Message");
  571. break;
  572. case TLV_PROPRIETARY:
  573. NRF_LOG_INFO("Proprietary");
  574. break;
  575. case TLV_NULL:
  576. NRF_LOG_INFO("Null\r\n");
  577. break;
  578. case TLV_TERMINATOR:
  579. NRF_LOG_INFO("Terminator");
  580. break;
  581. default:
  582. NRF_LOG_INFO("Unknown");
  583. break;
  584. }
  585. NRF_LOG_INFO(" Data length: %d", p_type_2_tag->p_tlv_block_array[i].length);
  586. if (p_type_2_tag->p_tlv_block_array[i].length > 0)
  587. {
  588. NRF_LOG_DEBUG(" Data:");
  589. NRF_LOG_HEXDUMP_DEBUG(p_type_2_tag->p_tlv_block_array[i].p_value,
  590. p_type_2_tag->p_tlv_block_array[i].length);
  591. }
  592. }
  593. }
  594. #endif // NRF_MODULE_ENABLED(NFC_T2T_PARSER)