@@ -675,29 +675,49 @@ static void handle_fast_read_command(uint8_t block_num, uint8_t end_block_num) {
675675
676676 int block_max = get_block_max_by_tag_type (m_tag_type , true);
677677
678- if (block_num >= end_block_num || end_block_num >= block_max ) {
678+ if (block_num > end_block_num || end_block_num >= block_max ) {
679679 nfc_tag_14a_tx_nbit (NAK_INVALID_OPERATION_TBV , 4 );
680680 return ;
681681 }
682682
683683 NRF_LOG_INFO ("HANDLING FAST READ %02x %02x" , block_num , end_block_num );
684-
685- handle_any_read (block_num , end_block_num - block_num , block_max );
684+ // FAST_READ is inclusive: read from block_num to end_block_num (both included)
685+ handle_any_read (block_num , end_block_num - block_num + 1 , block_max );
686686}
687687
688688static bool check_ro_lock_on_page (int block_num ) {
689689 if (block_num < 3 ) return true;
690- else if (block_num == 3 ) return (m_tag_information -> memory [2 ][2 ] & 9 ) != 0 ; // bits 0 and 3
691- else if (block_num <= MF0ICU1_PAGES ) {
690+ else if (block_num == 3 ) {
691+ switch (m_tag_type ) {
692+ case TAG_TYPE_NTAG_213 :
693+ case TAG_TYPE_NTAG_215 :
694+ case TAG_TYPE_NTAG_216 :
695+ //page 3 can be locked or not independant of BL CC bit
696+ //the BL bit only freezes the lock bytes !
697+ return (m_tag_information -> memory [2 ][2 ] & 8 ) != 0 ;
698+ default :
699+ return (m_tag_information -> memory [2 ][2 ] & 9 ) != 0 ;
700+ }
701+ // bits 0 and 3
702+ } else if (block_num <= MF0ICU1_PAGES ) {
692703 bool locked = false;
704+ switch (m_tag_type ) {
705+ case TAG_TYPE_NTAG_213 :
706+ case TAG_TYPE_NTAG_215 :
707+ case TAG_TYPE_NTAG_216 :
708+ // pages can be locked or not independant of BL bits
709+ //the BL bits only freezes the lock bytes !
710+ uint16_t lock_bits = * (uint16_t * )& m_tag_information -> memory [2 ][2 ];
711+ return ((lock_bits >> block_num ) & 0x01 ) == 1 ;
712+ default :
713+ // check block locking bits
714+ if (block_num <= 9 ) locked |= (m_tag_information -> memory [2 ][2 ] & 2 ) == 2 ;
715+ else locked |= (m_tag_information -> memory [2 ][2 ] & 4 ) == 4 ;
693716
694- // check block locking bits
695- if (block_num <= 9 ) locked |= (m_tag_information -> memory [2 ][2 ] & 2 ) == 2 ;
696- else locked |= (m_tag_information -> memory [2 ][2 ] & 4 ) == 4 ;
697-
698- locked |= (((* (uint16_t * )& m_tag_information -> memory [2 ][2 ]) >> block_num ) & 1 ) == 1 ;
717+ locked |= (((* (uint16_t * )& m_tag_information -> memory [2 ][2 ]) >> block_num ) & 1 ) == 1 ;
699718
700- return locked ;
719+ return locked ;
720+ }
701721 } else {
702722 uint8_t * p_lock_bytes = NULL ;
703723 int user_memory_end = 0 ;
@@ -776,9 +796,18 @@ static bool check_ro_lock_on_page(int block_num) {
776796
777797 bool locked_small_range = ((lock_word >> (index / dyn_lock_bit_page_cnt )) & 1 ) != 0 ;
778798 bool locked_large_range = ((p_lock_bytes [2 ] >> (index / dyn_lock_bit_page_cnt / 2 )) & 1 ) != 0 ;
779-
780- return locked_small_range | locked_large_range ;
799+ switch (m_tag_type ) {
800+ case TAG_TYPE_NTAG_213 :
801+ case TAG_TYPE_NTAG_215 :
802+ case TAG_TYPE_NTAG_216 :
803+ // For NTAG213/215/216: byte 2 contains block-locking bits (BL) which only freeze
804+ // the lock configuration. We only check the actual lock bits (L0-L15) in bytes 0-1.
805+ return locked_small_range ;
806+ default :
807+ return locked_small_range | locked_large_range ;
808+ }
781809 } else {
810+ //TODO needs to check the block locking bits to see if we can touch the dynamic locks bytes for NTAG tags
782811 // check CFGLCK bit
783812 int first_cfg_page = get_first_cfg_page_by_tag_type (m_tag_type );
784813 uint8_t access = m_tag_information -> memory [first_cfg_page + CONF_ACCESS_PAGE_OFFSET ][CONF_ACCESS_BYTE ];
@@ -793,7 +822,25 @@ static bool check_ro_lock_on_page(int block_num) {
793822static int handle_write_command (uint8_t block_num , uint8_t * p_data ) {
794823 int block_max = get_block_max_by_tag_type (m_tag_type , false);
795824
796- if (block_num >= block_max ) {
825+ bool out_of_bounds = false;
826+ switch (m_tag_type ) {
827+ case TAG_TYPE_NTAG_213 :
828+ case TAG_TYPE_NTAG_215 :
829+ case TAG_TYPE_NTAG_216 :
830+ int first_cfg_page = get_first_cfg_page_by_tag_type (m_tag_type );
831+ uint8_t cfglck = m_tag_information -> memory [first_cfg_page ][0 ] & 0x40 ;
832+ // For NTAG cards we need to check CFGLCK bit for config pages
833+ bool is_config_page = (block_num >= first_cfg_page ) && (block_num <= first_cfg_page + 1 );
834+ bool config_locked = (cfglck != 0 ) && (m_tag_information -> config .mode_uid_magic );
835+ bool is_beyond_user_memory = (block_num >= block_max );
836+ out_of_bounds = (is_beyond_user_memory && !is_config_page ) || (config_locked && is_config_page );
837+ break ;
838+ default :
839+ out_of_bounds = block_num >= block_max ;
840+ break ;
841+ }
842+ // Reject out-of-bounds writes (except config pages)
843+ if (out_of_bounds ) {
797844 NRF_LOG_ERROR ("Write failed: block_num %08x >= block_max %08x" , block_num , block_max );
798845 return NAK_INVALID_OPERATION_TBV ;
799846 }
0 commit comments