The length of a packet should be non-zero am: 396ac0e081 am: 6e2338cb88 am: 653f2de33b am: 84c29af749

Original change: https://googleplex-android-review.googlesource.com/c/platform/system/nfc/+/19504916

Change-Id: I78ca4d415392e039dd4f1f72416d319094433b39
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp
index 9679a81..1576d1d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1 +1,18 @@
+package {
+    default_applicable_licenses: ["system_nfc_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "system_nfc_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 subdirs = ["src", "utils"]
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/conf/Android.bp b/conf/Android.bp
new file mode 100644
index 0000000..1f62fe0
--- /dev/null
+++ b/conf/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "system_nfc_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_nfc_license"],
+}
+
+prebuilt_etc {
+    name: "libnfc-nci.conf-default",
+    src: "libnfc-nci.conf",
+    filename: "libnfc-nci.conf",
+}
diff --git a/conf/libnfc-nci.conf b/conf/libnfc-nci.conf
new file mode 100644
index 0000000..f07f0ed
--- /dev/null
+++ b/conf/libnfc-nci.conf
@@ -0,0 +1,82 @@
+###############################################################################
+# Debug options
+NFC_DEBUG_ENABLED=0
+
+###############################################################################
+# File used for NFA storage
+NFA_STORAGE="/data/nfc"
+PRESERVE_STORAGE=0x01
+
+###############################################################################
+# When screen is turned off, specify the desired power state of the controller.
+# 0: power-off-sleep state; DEFAULT
+# 1: full-power state
+# 2: screen-off card-emulation (CE4/CE3/CE1 modes are used)
+SCREEN_OFF_POWER_STATE=1
+
+###############################################################################
+# Default poll duration (in ms)
+# Default is 500ms if not set (see nfc_target.h)
+#NFA_DM_DISC_DURATION_POLL=333
+
+###############################################################################
+# Force tag polling for the following technology(s).
+# The bits are defined as tNFA_TECHNOLOGY_MASK in nfa_api.h.
+# Default is NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B |
+#            NFA_TECHNOLOGY_MASK_F | NFA_TECHNOLOGY_MASK_ISO15693 |
+#            NFA_TECHNOLOGY_MASK_B_PRIME | NFA_TECHNOLOGY_MASK_KOVIO |
+#            NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE.
+#
+# Notable bits:
+# NFA_TECHNOLOGY_MASK_A             0x01    /* NFC Technology A             */
+# NFA_TECHNOLOGY_MASK_B             0x02    /* NFC Technology B             */
+# NFA_TECHNOLOGY_MASK_F             0x04    /* NFC Technology F             */
+# NFA_TECHNOLOGY_MASK_ISO15693      0x08    /* Proprietary Technology       */
+# NFA_TECHNOLOGY_MASK_KOVIO         0x20    /* Proprietary Technology       */
+# NFA_TECHNOLOGY_MASK_A_ACTIVE      0x40    /* NFC Technology A active mode */
+# NFA_TECHNOLOGY_MASK_F_ACTIVE      0x80    /* NFC Technology F active mode */
+POLLING_TECH_MASK=0x2F
+
+###############################################################################
+# Force P2P to only listen for the following technology(s).
+# The bits are defined as tNFA_TECHNOLOGY_MASK in nfa_api.h.
+# Default is NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_F |
+#            NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE
+#
+# Notable bits:
+# NFA_TECHNOLOGY_MASK_A             0x01    /* NFC Technology A             */
+# NFA_TECHNOLOGY_MASK_F             0x04    /* NFC Technology F             */
+# NFA_TECHNOLOGY_MASK_A_ACTIVE      0x40    /* NFC Technology A active mode */
+# NFA_TECHNOLOGY_MASK_F_ACTIVE      0x80    /* NFC Technology F active mode */
+P2P_LISTEN_TECH_MASK=0x00
+
+###############################################################################
+# Force UICC to only listen to the following technology(s).
+# The bits are defined as tNFA_TECHNOLOGY_MASK in nfa_api.h.
+# Default is NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B | NFA_TECHNOLOGY_MASK_F
+UICC_LISTEN_TECH_MASK=0x07
+
+###############################################################################
+# Override the stack default for NFA_EE_MAX_EE_SUPPORTED set in nfc_target.h.
+# The value is set to 3 by default as it assumes we will discover 0xF2,
+# 0xF3, and 0xF4. If a platform will exclude and SE, this value can be reduced
+# so that the stack will not wait any longer than necessary.
+# Maximum EE supported number
+# NXP PN547C2 0x02
+# NXP PN65T 0x03
+# NXP PN548C2 0x02
+# NXP PN66T 0x03
+NFA_MAX_EE_SUPPORTED=0x02
+
+###############################################################################
+# AID for Empty Select command
+# If specified, this AID will be substituted when an Empty SELECT command is
+# detected.  The first byte is the length of the AID.  Maximum length is 16.
+AID_FOR_EMPTY_SELECT={08:A0:00:00:01:51:00:00:00}
+
+###############################################################################
+# AID_MATCHING constants
+# AID_MATCHING_EXACT_ONLY 0x00
+# AID_MATCHING_EXACT_OR_PREFIX 0x01
+# AID_MATCHING_PREFIX_ONLY 0x02
+AID_MATCHING_MODE=0x01
diff --git a/src/Android.bp b/src/Android.bp
index 9075cf6..f691c4a 100644
--- a/src/Android.bp
+++ b/src/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "system_nfc_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_nfc_license"],
+}
+
 cc_library_shared {
     arch: {
         arm: {
@@ -26,6 +35,7 @@
         "libnfcutils",
     ],
     cflags: [
+        "-DDYN_ALLOC=1",
         "-DBUILDCFG=1",
         "-Wall",
         "-Werror",
@@ -55,6 +65,11 @@
         "gki/common/*.cc",
         "gki/ulinux/*.cc",
     ],
+    required: [
+        // Provide a default libnfc-nci.conf in /system/etc for devices that
+        // does not ship one in /product
+        "libnfc-nci.conf-default",
+    ],
     product_variables: {
         debuggable: {
             cflags: [
@@ -65,6 +80,7 @@
     sanitize: {
         misc_undefined: ["bounds"],
         integer_overflow: true,
+        scs: true,
     },
 
 }
@@ -169,4 +185,3 @@
         "fuzzers/llcp/*.cc",
     ],
 }
-
diff --git a/src/adaptation/NfcAdaptation.cc b/src/adaptation/NfcAdaptation.cc
index 2af25cf..7c6a857 100644
--- a/src/adaptation/NfcAdaptation.cc
+++ b/src/adaptation/NfcAdaptation.cc
@@ -736,7 +736,7 @@
 **
 *******************************************************************************/
 uint8_t NfcAdaptation::HalGetMaxNfcee() {
-  const char* func = "NfcAdaptation::HalPowerCycle";
+  const char* func = "NfcAdaptation::HalGetMaxNfcee";
   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", func);
 
   return nfa_ee_max_ee_cfg;
diff --git a/src/adaptation/debug_nfcsnoop.cc b/src/adaptation/debug_nfcsnoop.cc
index cd655cd..ce283c1 100644
--- a/src/adaptation/debug_nfcsnoop.cc
+++ b/src/adaptation/debug_nfcsnoop.cc
@@ -17,23 +17,33 @@
  ******************************************************************************/
 
 #include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 #include <resolv.h>
 #include <zlib.h>
 #include <mutex>
 
 #include <ringbuffer.h>
 
+#include <cutils/properties.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
 #include "bt_types.h"
 #include "include/debug_nfcsnoop.h"
 #include "nfc_int.h"
 
 #define USEC_PER_SEC 1000000ULL
 
+#define DEFAULT_NFCSNOOP_PATH "/data/misc/nfc/logs/nfcsnoop_nci_logs"
+#define DEFAULT_NFCSNOOP_FILE_SIZE 32 * 1024 * 1024
+
 // Total nfcsnoop memory log buffer size
 #ifndef NFCSNOOP_MEM_BUFFER_SIZE
 static const size_t NFCSNOOP_MEM_BUFFER_SIZE = (256 * 1024);
 #endif
 
+#define NFCSNOOP_MEM_BUFFER_THRESHOLD 1024
+
 // Block size for copying buffers (for compression/encoding etc.)
 static const size_t BLOCK_SIZE = 16384;
 
@@ -43,6 +53,9 @@
 static std::mutex buffer_mutex;
 static ringbuffer_t* buffer = nullptr;
 static uint64_t last_timestamp_ms = 0;
+static bool isDebuggable = false;
+
+using android::base::StringPrintf;
 
 static void nfcsnoop_cb(const uint8_t* data, const size_t length,
                         bool is_received, const uint64_t timestamp_us) {
@@ -85,28 +98,27 @@
   if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) return false;
 
   bool rc = true;
-  uint8_t block_src[BLOCK_SIZE];
-  uint8_t block_dst[BLOCK_SIZE];
+  std::unique_ptr<uint8_t> block_src(new uint8_t[BLOCK_SIZE]);
+  std::unique_ptr<uint8_t> block_dst(new uint8_t[BLOCK_SIZE]);
 
   const size_t num_blocks =
       (ringbuffer_size(rb_src) + BLOCK_SIZE - 1) / BLOCK_SIZE;
   for (size_t i = 0; i < num_blocks; ++i) {
     zs.avail_in =
-        ringbuffer_peek(rb_src, i * BLOCK_SIZE, block_src, BLOCK_SIZE);
-    zs.next_in = block_src;
+        ringbuffer_peek(rb_src, i * BLOCK_SIZE, block_src.get(), BLOCK_SIZE);
+    zs.next_in = block_src.get();
 
     do {
       zs.avail_out = BLOCK_SIZE;
-      zs.next_out = block_dst;
+      zs.next_out = block_dst.get();
 
       int err = deflate(&zs, (i == num_blocks - 1) ? Z_FINISH : Z_NO_FLUSH);
       if (err == Z_STREAM_ERROR) {
         rc = false;
         break;
       }
-
       const size_t length = BLOCK_SIZE - zs.avail_out;
-      ringbuffer_insert(rb_dst, block_dst, length);
+      ringbuffer_insert(rb_dst, block_dst.get(), length);
     } while (zs.avail_out == 0);
   }
 
@@ -121,7 +133,17 @@
                        static_cast<uint64_t>(tv.tv_usec);
   uint8_t* p = (uint8_t*)(packet + 1) + packet->offset;
   uint8_t mt = (*(p)&NCI_MT_MASK) >> NCI_MT_SHIFT;
-
+  if (isDebuggable &&
+      ringbuffer_available(buffer) < NFCSNOOP_MEM_BUFFER_THRESHOLD) {
+    if (storeNfcSnoopLogs(DEFAULT_NFCSNOOP_PATH, DEFAULT_NFCSNOOP_FILE_SIZE)) {
+      std::lock_guard<std::mutex> lock(buffer_mutex);
+      // Free the buffer after the content is stored in log file
+      ringbuffer_free(buffer);
+      buffer = nullptr;
+      // Allocate new buffer to store new NCI logs
+      debug_nfcsnoop_init();
+    }
+  }
   if (mt == NCI_MT_DATA) {
     nfcsnoop_cb(p, NCI_DATA_HDR_SIZE, is_received, timestamp);
   } else if (packet->len > 2) {
@@ -131,6 +153,7 @@
 
 void debug_nfcsnoop_init(void) {
   if (buffer == nullptr) buffer = ringbuffer_init(NFCSNOOP_MEM_BUFFER_SIZE);
+  isDebuggable = property_get_int32("ro.debuggable", 0);
 }
 
 void debug_nfcsnoop_dump(int fd) {
@@ -189,3 +212,35 @@
 error:
   ringbuffer_free(ringbuffer);
 }
+
+bool storeNfcSnoopLogs(std::string filepath, off_t maxFileSize) {
+  int fileStream;
+  off_t fileSize;
+  // check file size
+  struct stat st;
+  if (stat(filepath.c_str(), &st) == 0) {
+    fileSize = st.st_size;
+  } else {
+    fileSize = 0;
+  }
+
+  mode_t prevmask = umask(0);
+  if (fileSize >= maxFileSize) {
+    fileStream = open(filepath.c_str(), O_RDWR | O_CREAT | O_TRUNC,
+                      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+  } else {
+    fileStream = open(filepath.c_str(), O_RDWR | O_CREAT | O_APPEND,
+                      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+  }
+  umask(prevmask);
+
+  if (fileStream >= 0) {
+    debug_nfcsnoop_dump(fileStream);
+    close(fileStream);
+    return true;
+  } else {
+    LOG(ERROR) << StringPrintf("%s: fail to create, error = %d", __func__,
+                               errno);
+    return false;
+  }
+}
diff --git a/src/fuzzers/ce/t3t.cc b/src/fuzzers/ce/t3t.cc
index 490f6b7..e774df7 100644
--- a/src/fuzzers/ce/t3t.cc
+++ b/src/fuzzers/ce/t3t.cc
@@ -93,13 +93,13 @@
   for (auto it = ctx.Data.cbegin(); it != ctx.Data.cend(); ++it) {
     NFC_HDR* p_msg;
     p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR) + it->size());
-    if (p_msg == nullptr) {
+    if (p_msg == nullptr || it->size() < 1) {
       FUZZLOG(MODULE_NAME ": GKI_getbuf returns null, size=%zu", it->size());
       return;
     }
 
     /* Initialize NFC_HDR */
-    p_msg->len = it->size();
+    p_msg->len = it->size() - 1;
     p_msg->offset = 0;
 
     uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
diff --git a/src/fuzzers/fuzz.sh b/src/fuzzers/fuzz.sh
index c8fc235..1cba253 100755
--- a/src/fuzzers/fuzz.sh
+++ b/src/fuzzers/fuzz.sh
@@ -102,7 +102,7 @@
   SANITIZE_HOST="address" \
     SANITIZE_TARGET="hwaddress fuzzer" \
     NATIVE_COVERAGE="true" \
-    COVERAGE_PATHS="system/nfc/src" \
+    NATIVE_COVERAGE_PATHS="system/nfc/src" \
     make -j $FUZZER_NAME
   popd
   adb shell mkdir -p /$FUZZ_DIR
diff --git a/src/fuzzers/fuzz_cmn.cc b/src/fuzzers/fuzz_cmn.cc
index 43433bd..930026c 100644
--- a/src/fuzzers/fuzz_cmn.cc
+++ b/src/fuzzers/fuzz_cmn.cc
@@ -4,6 +4,7 @@
 void delete_stack_non_volatile_store(bool){};
 void debug_nfcsnoop_dump(int){};
 std::string nfc_storage_path;
+bool storeNfcSnoopLogs(std::string, off_t) { return true; };
 
 uint8_t appl_dta_mode_flag = 0;
 bool nfc_debug_enabled = true;
diff --git a/src/fuzzers/rw/t1t.cc b/src/fuzzers/rw/t1t.cc
index 94670fd..f2c4f80 100644
--- a/src/fuzzers/rw/t1t.cc
+++ b/src/fuzzers/rw/t1t.cc
@@ -213,13 +213,13 @@
   for (auto it = ctx.Data.cbegin() + 1; it != ctx.Data.cend(); ++it) {
     NFC_HDR* p_msg;
     p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR) + it->size());
-    if (p_msg == nullptr) {
+    if (p_msg == nullptr || it->size() < 1) {
       FUZZLOG(MODULE_NAME ": GKI_getbuf returns null, size=%zu", it->size());
       return;
     }
 
     /* Initialize NFC_HDR */
-    p_msg->len = it->size();
+    p_msg->len = it->size() - 1;
     p_msg->offset = 0;
 
     uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
diff --git a/src/fuzzers/rw/t2t.cc b/src/fuzzers/rw/t2t.cc
index 57ddb0f..f829e35 100644
--- a/src/fuzzers/rw/t2t.cc
+++ b/src/fuzzers/rw/t2t.cc
@@ -172,13 +172,13 @@
   for (auto it = ctx.Data.cbegin() + 1; it != ctx.Data.cend(); ++it) {
     NFC_HDR* p_msg;
     p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR) + it->size());
-    if (p_msg == nullptr) {
+    if (p_msg == nullptr || it->size() < 1) {
       FUZZLOG(MODULE_NAME ": GKI_getbuf returns null, size=%zu", it->size());
       return;
     }
 
     /* Initialize NFC_HDR */
-    p_msg->len = it->size();
+    p_msg->len = it->size() - 1;
     p_msg->offset = 0;
 
     uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
diff --git a/src/fuzzers/rw/t3t.cc b/src/fuzzers/rw/t3t.cc
index b64ffc5..8853cf7 100644
--- a/src/fuzzers/rw/t3t.cc
+++ b/src/fuzzers/rw/t3t.cc
@@ -251,6 +251,11 @@
                         .status = NFC_STATUS_OK,
                         .p_data = p_msg,
                     }};
+  if (p_msg->len < 1) {
+    FUZZLOG(MODULE_NAME ": Ivalid message length=%hu", p_msg->len);
+    return;
+  }
+  p_msg->len--;
 
   rf_cback(NFC_RF_CONN_ID, NFC_DATA_CEVT, &conn);
 }
diff --git a/src/fuzzers/rw/t5t.cc b/src/fuzzers/rw/t5t.cc
index 9ddcca6..bd61f66 100644
--- a/src/fuzzers/rw/t5t.cc
+++ b/src/fuzzers/rw/t5t.cc
@@ -72,7 +72,8 @@
 }
 
 static bool Init_StayQuiet(Fuzz_Context& /*ctx*/) {
-  return NFC_STATUS_OK == RW_I93StayQuiet();
+  uint8_t uid[] = TEST_UID_VALUE;
+  return NFC_STATUS_OK == RW_I93StayQuiet(uid);
 }
 
 static bool Init_ReadSingleBlock(Fuzz_Context& /*ctx*/) {
@@ -289,13 +290,13 @@
   for (auto it = ctx.Data.cbegin() + 1; it != ctx.Data.cend(); ++it) {
     NFC_HDR* p_msg;
     p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR) + it->size());
-    if (p_msg == nullptr) {
+    if (p_msg == nullptr || it->size() < 1) {
       FUZZLOG(MODULE_NAME ": GKI_getbuf returns null, size=%zu", it->size());
       return;
     }
 
     /* Initialize NFC_HDR */
-    p_msg->len = it->size();
+    p_msg->len = it->size() - 1;
     p_msg->offset = 0;
 
     uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
diff --git a/src/gki/common/gki_buffer.cc b/src/gki/common/gki_buffer.cc
index 72e02c6..858fe90 100644
--- a/src/gki/common/gki_buffer.cc
+++ b/src/gki/common/gki_buffer.cc
@@ -17,6 +17,7 @@
  ******************************************************************************/
 #include <android-base/stringprintf.h>
 #include <base/logging.h>
+#include <log/log.h>
 #include "gki_int.h"
 
 #if (GKI_NUM_TOTAL_BUF_POOLS > 16)
@@ -28,6 +29,8 @@
 static void gki_remove_from_pool_list(uint8_t pool_id);
 #endif /*  BTU_STACK_LITE_ENABLED == FALSE */
 
+extern bool nfc_debug_enabled;
+
 using android::base::StringPrintf;
 
 /*******************************************************************************
@@ -253,22 +256,41 @@
 *******************************************************************************/
 void* GKI_getbuf(uint16_t size) {
   BUFFER_HDR_T* p_hdr;
+  FREE_QUEUE_T* Q;
 
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-  if (size == 0) {
-    LOG(ERROR) << StringPrintf("getbuf: Size is zero");
+#if defined(DYN_ALLOC) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
+  if (size == 0 || size > (USHRT_MAX - 3)) {
+    LOG(ERROR) << StringPrintf("getbuf: Requested size(%d) is invalid", size);
+    android_errorWriteLog(0x534e4554, "205729183");
+#ifndef DYN_ALLOC
     abort();
+#else
+    return (nullptr);
+#endif
   }
 
-  size_t total_sz = size + sizeof(BUFFER_HDR_T);
+  size = ALIGN_POOL(size);
+  size_t total_sz = size + sizeof(BUFFER_HDR_T)
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+                    + sizeof(uint32_t);
+#else
+      ;
+#endif
   p_hdr = (BUFFER_HDR_T*)GKI_os_malloc(total_sz);
   if (!p_hdr) {
     LOG(ERROR) << StringPrintf("unable to allocate buffer!!!!!");
+#ifndef DYN_ALLOC
     abort();
+#else
+    return (nullptr);
+#endif
   }
 
   memset(p_hdr, 0, total_sz);
 
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+  *(uint32_t*)((uint8_t*)p_hdr + BUFFER_HDR_SIZE + size) = MAGIC_NO;
+#endif
   p_hdr->task_id = GKI_get_taskid();
   p_hdr->status = BUF_STATUS_UNLINKED;
   p_hdr->p_next = nullptr;
@@ -277,12 +299,18 @@
   p_hdr->q_id = 0;
   p_hdr->size = size;
 
-  UNUSED(gki_alloc_free_queue);
+  GKI_disable();
+  Q = &gki_cb.com.freeq[p_hdr->q_id];
+  if (++Q->cur_cnt > Q->max_cnt) Q->max_cnt = Q->cur_cnt;
+  GKI_enable();
 
+  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+      "%s %p %d:%d", __func__, ((uint8_t*)p_hdr + BUFFER_HDR_SIZE), Q->cur_cnt,
+      Q->max_cnt);
+  UNUSED(gki_alloc_free_queue);
   return (void*)((uint8_t*)p_hdr + BUFFER_HDR_SIZE);
 #else
   uint8_t i;
-  FREE_QUEUE_T* Q;
   tGKI_COM_CB* p_cb = &gki_cb.com;
 
   if (size == 0) {
@@ -367,7 +395,7 @@
 **
 *******************************************************************************/
 void* GKI_getpoolbuf(uint8_t pool_id) {
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+#if defined(DYN_ALLOC) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
   uint16_t size = 0;
   switch (pool_id) {
     // NFC_NCI_POOL_ID, NFC_RW_POOL_ID and NFC_CE_POOL_ID are all redefined to
@@ -383,7 +411,11 @@
 
     default:
       LOG(ERROR) << StringPrintf("Unknown pool ID: %d", pool_id);
+#ifndef DYN_ALLOC
       abort();
+#else
+      return (nullptr);
+#endif
       break;
   }
 
@@ -448,22 +480,6 @@
 *******************************************************************************/
 void GKI_freebuf(void* p_buf) {
   BUFFER_HDR_T* p_hdr;
-
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-  p_hdr = (BUFFER_HDR_T*)((uint8_t*)p_buf - BUFFER_HDR_SIZE);
-
-  if (p_hdr->status != BUF_STATUS_UNLINKED) {
-    GKI_exception(GKI_ERROR_FREEBUF_BUF_LINKED, "Freeing Linked Buf");
-    return;
-  }
-
-  if (p_hdr->q_id >= GKI_NUM_TOTAL_BUF_POOLS) {
-    GKI_exception(GKI_ERROR_FREEBUF_BAD_QID, "Bad Buf QId");
-    return;
-  }
-
-  GKI_os_free(p_hdr);
-#else
   FREE_QUEUE_T* Q;
 
 #if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
@@ -485,6 +501,14 @@
     return;
   }
 
+#if defined(DYN_ALLOC) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
+  GKI_disable();
+  Q = &gki_cb.com.freeq[p_hdr->q_id];
+  if (Q->cur_cnt > 0) Q->cur_cnt--;
+  GKI_enable();
+
+  GKI_os_free(p_hdr);
+#else
   GKI_disable();
 
   /*
@@ -522,7 +546,7 @@
 
   p_hdr = (BUFFER_HDR_T*)((uint8_t*)p_buf - BUFFER_HDR_SIZE);
 
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+#if defined(DYN_ALLOC) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
   return p_hdr->size;
 #else
   if ((uintptr_t)p_hdr & 1) return (0);
@@ -554,6 +578,7 @@
 
   if (*magic == MAGIC_NO) return false;
 
+  LOG(ERROR) << StringPrintf("%s 0x%x %p", __func__, *magic, p_buf);
   return true;
 
 #else
@@ -1283,10 +1308,35 @@
 **
 *******************************************************************************/
 uint16_t GKI_get_pool_bufsize(uint8_t pool_id) {
+#if defined(DYN_ALLOC) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
+  uint16_t size = 0;
+  switch (pool_id) {
+    case GKI_POOL_ID_0:
+      size = GKI_BUF0_SIZE;
+      break;
+    case GKI_POOL_ID_1:
+      size = GKI_BUF1_SIZE;
+      break;
+    case GKI_POOL_ID_2:
+      size = GKI_BUF2_SIZE;
+      break;
+    case GKI_POOL_ID_3:
+      size = GKI_BUF3_SIZE;
+      break;
+      /* Here could be more pool ids, but they are not used in the current
+       * implementation */
+    default:
+      LOG(ERROR) << StringPrintf("Unknown pool ID: %d", pool_id);
+      return (0);
+      break;
+  }
+  return (size);
+#else
   if (pool_id < GKI_NUM_TOTAL_BUF_POOLS)
     return (gki_cb.com.freeq[pool_id].size);
 
   return (0);
+#endif
 }
 
 /*******************************************************************************
diff --git a/src/gki/common/gki_common.h b/src/gki/common/gki_common.h
index d814f07..701d23b 100644
--- a/src/gki/common/gki_common.h
+++ b/src/gki/common/gki_common.h
@@ -54,7 +54,7 @@
   uint8_t task_id;            /* task which allocated the buffer*/
   uint8_t status;             /* FREE, UNLINKED or QUEUED */
   uint8_t Type;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+#if defined(DYN_ALLOC) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
   uint16_t size;
 #endif
 } BUFFER_HDR_T;
diff --git a/src/gki/ulinux/gki_ulinux.cc b/src/gki/ulinux/gki_ulinux.cc
index 093b58d..7262b5f 100644
--- a/src/gki/ulinux/gki_ulinux.cc
+++ b/src/gki/ulinux/gki_ulinux.cc
@@ -95,8 +95,8 @@
   /* Call the actual thread entry point */
   (p_pthread_info->task_entry)(p_pthread_info->params);
 
-  LOG(ERROR) << StringPrintf("gki_task task_id=%i terminating",
-                             p_pthread_info->task_id);
+  LOG(WARNING) << StringPrintf("gki_task task_id=%i terminating",
+                               p_pthread_info->task_id);
   gki_cb.os.thread_id[p_pthread_info->task_id] = 0;
 
   return nullptr;
@@ -338,9 +338,9 @@
 
 /*******************************************************************************
  **
- ** Function        GKI_run
+ ** Function        gki_system_tick_start_stop_cback
  **
- ** Description     This function runs a task
+ ** Description     This function starts or stops timer
  **
  ** Parameters:     start: TRUE start system tick (again), FALSE stop
  **
@@ -634,8 +634,8 @@
       /* unlock thread_evt_mutex as pthread_cond_wait() does auto lock when cond
        * is met */
       pthread_mutex_unlock(&gki_cb.os.thread_evt_mutex[rtask]);
-      LOG(ERROR) << StringPrintf("GKI TASK_DEAD received. exit thread %d...",
-                                 rtask);
+      LOG(WARNING) << StringPrintf("GKI TASK_DEAD received. exit thread %d...",
+                                   rtask);
 
       gki_cb.os.thread_id[rtask] = 0;
       return (EVENT_MASK(GKI_SHUTDOWN_EVT));
diff --git a/src/include/buildcfg.h b/src/include/buildcfg.h
index b66695b..d69ed55 100644
--- a/src/include/buildcfg.h
+++ b/src/include/buildcfg.h
@@ -43,6 +43,10 @@
 #define GKI_BUF0_SIZE 268
 #define GKI_BUF0_MAX 40
 
+#ifdef DYN_ALLOC
+#define GKI_NUM_FIXED_BUF_POOLS 0
+#else
 #define GKI_NUM_FIXED_BUF_POOLS 4
+#endif
 
 #endif
diff --git a/src/include/debug_nfcsnoop.h b/src/include/debug_nfcsnoop.h
index 2dd7b6b..b846d69 100644
--- a/src/include/debug_nfcsnoop.h
+++ b/src/include/debug_nfcsnoop.h
@@ -47,4 +47,6 @@
 // capture the packet
 void nfcsnoop_capture(const NFC_HDR* packet, bool is_received);
 
+// store NCI log to file
+bool storeNfcSnoopLogs(std::string filepath, off_t maxFileSize);
 #endif /* _DEBUG_NFCSNOOP_ */
diff --git a/src/include/nci_defs.h b/src/include/nci_defs.h
index b43cb1c..c23c39e 100644
--- a/src/include/nci_defs.h
+++ b/src/include/nci_defs.h
@@ -155,6 +155,7 @@
 #define NCI_STATUS_ACTIVATION_FAILED 0xA1
 #define NCI_STATUS_TEAR_DOWN 0xA2
 /* RF Interface */
+#define NCI_STATUS_RF_FRAME_CORRUPTED 0x02
 #define NCI_STATUS_RF_TRANSMISSION_ERR 0xB0
 #define NCI_STATUS_RF_PROTOCOL_ERR 0xB1
 #define NCI_STATUS_TIMEOUT 0xB2
@@ -428,17 +429,22 @@
 #define NCI_PARAM_ID_CON_DEVICES_LIMIT 0x01
 #define NCI_PARAM_ID_CON_DISCOVERY_PARAM 0x02
 #define NCI_PARAM_ID_PA_BAILOUT 0x08
+#define NCI_PARAM_ID_PA_DEVICES_LIMIT 0x09
 #define NCI_PARAM_ID_PB_AFI 0x10
 #define NCI_PARAM_ID_PB_BAILOUT 0x11
 #define NCI_PARAM_ID_PB_ATTRIB_PARAM1 0x12
+#define NCI_PARAM_ID_PB_DEVICES_LIMIT 0x14
 #define NCI_PARAM_ID_PF_BIT_RATE 0x18
 #define NCI_PARAM_ID_PF_RC 0x19
+#define NCI_PARAM_ID_PF_BAILOUT 0x19
+#define NCI_PARAM_ID_PF_DEVICES_LIMIT 0x1A
 #define NCI_PARAM_ID_PB_H_INFO 0x20
 #define NCI_PARAM_ID_PI_BIT_RATE 0x21
 
 #define NCI_PARAM_ID_BITR_NFC_DEP 0x28
 #define NCI_PARAM_ID_ATR_REQ_GEN_BYTES 0x29
 #define NCI_PARAM_ID_ATR_REQ_CONFIG 0x2A
+#define NCI_PARAM_ID_PV_DEVICES_LIMIT 0x2F
 
 #define NCI_PARAM_ID_LA_BIT_FRAME_SDD 0x30
 #define NCI_PARAM_ID_LA_PLATFORM_CONFIG 0x31
@@ -485,6 +491,7 @@
 #define NCI_PARAM_ID_WT 0x60
 #define NCI_PARAM_ID_ATR_RES_GEN_BYTES 0x61
 #define NCI_PARAM_ID_ATR_RSP_CONFIG 0x62
+#define NCI_PARAM_ID_PACM_BIT_RATE 0x68
 
 #define NCI_PARAM_ID_RF_FIELD_INFO 0x80
 #define NCI_PARAM_ID_NFC_DEP_OP 0x82
diff --git a/src/include/nfc_config.h b/src/include/nfc_config.h
index dda4260..aa7ac66 100644
--- a/src/include/nfc_config.h
+++ b/src/include/nfc_config.h
@@ -38,6 +38,9 @@
 #define NAME_AID_MATCHING_MODE "AID_MATCHING_MODE"
 #define NAME_OFFHOST_AID_ROUTE_PWR_STATE "OFFHOST_AID_ROUTE_PWR_STATE"
 #define NAME_LEGACY_MIFARE_READER "LEGACY_MIFARE_READER"
+#define NAME_RECOVERY_OPTION "RECOVERY_OPTION"
+#define NAME_ALWAYS_ON_SET_EE_POWER_AND_LINK_CONF \
+  "ALWAYS_ON_SET_EE_POWER_AND_LINK_CONF"
 
 /* Configs from vendor interface */
 #define NAME_NFA_POLL_BAIL_OUT_MODE "NFA_POLL_BAIL_OUT_MODE"
diff --git a/src/nfa/dm/nfa_dm_act.cc b/src/nfa/dm/nfa_dm_act.cc
index aa494fb..51c841d 100644
--- a/src/nfa/dm/nfa_dm_act.cc
+++ b/src/nfa/dm/nfa_dm_act.cc
@@ -36,9 +36,10 @@
 
 #if (NFC_NFCEE_INCLUDED == TRUE)
 #include "nfa_ee_int.h"
-
 #endif
 
+#include "nfc_int.h"
+
 #if (NFA_SNEP_INCLUDED == TRUE)
 #include "nfa_snep_int.h"
 #endif
@@ -336,12 +337,13 @@
       break;
 
 #if (NFC_NFCEE_INCLUDED == TRUE)
-    case NFC_NFCEE_DISCOVER_REVT: /* NFCEE Discover response */
-    case NFC_NFCEE_INFO_REVT:     /* NFCEE Discover Notification */
-    case NFC_EE_ACTION_REVT:      /* EE Action notification */
-    case NFC_NFCEE_MODE_SET_REVT: /* NFCEE Mode Set response */
-    case NFC_NFCEE_STATUS_REVT:   /* NFCEE Status notification*/
-    case NFC_SET_ROUTING_REVT:    /* Configure Routing response */
+    case NFC_NFCEE_DISCOVER_REVT:   /* NFCEE Discover response */
+    case NFC_NFCEE_INFO_REVT:       /* NFCEE Discover Notification */
+    case NFC_EE_ACTION_REVT:        /* EE Action notification */
+    case NFC_NFCEE_MODE_SET_REVT:   /* NFCEE Mode Set response */
+    case NFC_NFCEE_STATUS_REVT:     /* NFCEE Status notification*/
+    case NFC_SET_ROUTING_REVT:      /* Configure Routing response */
+    case NFC_NFCEE_PL_CONTROL_REVT: /* NFCEE pwr and link ctrl response */
       nfa_ee_proc_evt(event, p_data);
       break;
 
@@ -949,6 +951,14 @@
       poll_disc_mask |= NFA_DM_DISC_MASK_P_KOVIO;
     }
 
+    if (!(nfc_cb.nci_interfaces & (1 << NCI_INTERFACE_NFC_DEP))) {
+      /* Remove NFC-DEP related Discovery mask, if NFC_DEP interface is not
+       * supported */
+      poll_disc_mask &=
+          ~(NFA_DM_DISC_MASK_PACM_NFC_DEP | NFA_DM_DISC_MASK_PAA_NFC_DEP |
+            NFA_DM_DISC_MASK_PFA_NFC_DEP | NFA_DM_DISC_MASK_PF_NFC_DEP);
+    }
+
     nfa_dm_cb.poll_disc_handle = nfa_dm_add_rf_discover(
         poll_disc_mask, NFA_DM_DISC_HOST_ID_DH, nfa_dm_poll_disc_cback);
 
@@ -1436,6 +1446,18 @@
   } else if (event == NFC_DEACTIVATE_CEVT) {
     NFC_SetStaticRfCback(nullptr);
   }
+  /* needed if CLF reports timeout, transmission or protocol error to notify DTA
+   * that may need to resume discovery if DH stays in POLL_ACTIVE state */
+  else if (appl_dta_mode_flag && (event == NFC_ERROR_CEVT)) {
+    if (p_data) {
+      evt_data.data.status = p_data->data.status;
+      nfa_dm_conn_cback_event_notify(NFA_RW_INTF_ERROR_EVT, &evt_data);
+    } else {
+      LOG(ERROR) << StringPrintf(
+          "received NFC_ERROR_CEVT with NULL data "
+          "pointer");
+    }
+  }
 }
 
 /*******************************************************************************
@@ -1836,6 +1858,8 @@
       return "NFC_NFCEE_INFO_REVT";
     case NFC_NFCEE_MODE_SET_REVT:
       return "NFC_NFCEE_MODE_SET_REVT";
+    case NFC_NFCEE_PL_CONTROL_REVT:
+      return "NFC_NFCEE_PL_CONTROL_REVT";
     case NFC_RF_FIELD_REVT:
       return "NFC_RF_FIELD_REVT";
     case NFC_EE_ACTION_REVT:
diff --git a/src/nfa/dm/nfa_dm_api.cc b/src/nfa/dm/nfa_dm_api.cc
index 20b1730..87f6e80 100644
--- a/src/nfa/dm/nfa_dm_api.cc
+++ b/src/nfa/dm/nfa_dm_api.cc
@@ -760,7 +760,8 @@
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
   /* Post the API message */
-  p_msg = (tNFA_DM_API_SET_RF_DISC_DUR*)GKI_getbuf(sizeof(NFC_HDR));
+  p_msg = (tNFA_DM_API_SET_RF_DISC_DUR*)GKI_getbuf(
+      sizeof(tNFA_DM_API_SET_RF_DISC_DUR));
   if (p_msg != nullptr) {
     p_msg->hdr.event = NFA_DM_API_SET_RF_DISC_DURATION_EVT;
 
diff --git a/src/nfa/dm/nfa_dm_main.cc b/src/nfa/dm/nfa_dm_main.cc
index 18ca93c..a65fbcd 100644
--- a/src/nfa/dm/nfa_dm_main.cc
+++ b/src/nfa/dm/nfa_dm_main.cc
@@ -446,6 +446,9 @@
       /* Increment setcfg_pending counter */
       nfa_dm_cb.setcfg_pending_num++;
     }
+    if ((nfa_dm_cb.eDtaMode & NFA_DTA_HCEF_MODE) == NFA_DTA_HCEF_MODE) {
+      nfa_dm_cb.eDtaMode &= ~NFA_DTA_HCEF_MODE;
+    }
     return (nfc_status);
 
   } else {
diff --git a/src/nfa/ee/nfa_ee_act.cc b/src/nfa/ee/nfa_ee_act.cc
index 9fad48c..8b637d6 100644
--- a/src/nfa/ee/nfa_ee_act.cc
+++ b/src/nfa/ee/nfa_ee_act.cc
@@ -30,6 +30,7 @@
 #include "nfa_dm_int.h"
 #include "nfa_ee_int.h"
 #include "nfa_hci_int.h"
+#include "nfc_int.h"
 
 #include <statslog.h>
 #include "metrics.h"
@@ -383,11 +384,16 @@
       }
       if (p_cb->nfcee_id == NFC_DH_ID &&
           nfa_ee_proto_mask_list[xx] == NFA_PROTOCOL_MASK_NFC_DEP) {
-        /* add NFC-DEP routing to HOST */
-        add_route_tech_proto_tlv(&pp, NFC_ROUTE_TAG_PROTO, NFC_DH_ID,
-                                 NCI_ROUTE_PWR_STATE_ON, NFC_PROTOCOL_NFC_DEP);
-        DLOG_IF(INFO, nfc_debug_enabled)
-            << StringPrintf("%s - NFC DEP added for DH!!!", __func__);
+        /* add NFC-DEP routing to HOST if NFC_DEP interface is supported */
+        if (nfc_cb.nci_interfaces & (1 << NCI_INTERFACE_NFC_DEP)) {
+          add_route_tech_proto_tlv(&pp, NFC_ROUTE_TAG_PROTO, NFC_DH_ID,
+                                   NCI_ROUTE_PWR_STATE_ON,
+                                   NFC_PROTOCOL_NFC_DEP);
+          DLOG_IF(INFO, nfc_debug_enabled)
+              << StringPrintf("%s - NFC DEP added for DH!!!", __func__);
+        } else {
+          continue;
+        }
       } else {
         add_route_tech_proto_tlv(&pp, proto_tag, p_cb->nfcee_id, power_cfg,
                                  nfa_ee_proto_list[xx]);
@@ -1310,7 +1316,7 @@
     /* report NFA_EE_REMOVE_AID_EVT to the callback associated the NFCEE */
     p_cback = p_cb->p_ee_cback;
   } else {
-    LOG(ERROR) << StringPrintf(
+    LOG(WARNING)  << StringPrintf(
         "nfa_ee_api_remove_aid The AID entry is not in the database");
     evt_data.status = NFA_STATUS_INVALID_PARAM;
   }
@@ -1643,6 +1649,20 @@
 
 /*******************************************************************************
 **
+** Function         nfa_ee_api_pwr_and_link_ctrl
+**
+** Description      Initiates closing of the connection to the given NFCEE
+**
+** Returns          void
+**
+*******************************************************************************/
+void nfa_ee_api_pwr_and_link_ctrl(tNFA_EE_MSG* p_data) {
+  NFC_NfceePLConfig(p_data->pwr_and_link_ctrl.nfcee_id,
+                    p_data->pwr_and_link_ctrl.config);
+}
+
+/*******************************************************************************
+**
 ** Function         nfa_ee_report_disc_done
 **
 ** Description      Process the callback for NFCEE discovery response
@@ -2078,7 +2098,7 @@
 
   for (xx = 0; xx < nfa_ee_cb.cur_ee; xx++, p_cb++) {
     if ((p_cb->ee_status & NFA_EE_STATUS_INT_MASK) ||
-        (p_cb->ee_status != NFA_EE_STATUS_ACTIVE)) {
+        (p_cb->ee_status != NFA_EE_STATUS_ACTIVE) ) {
       continue;
     }
     p_info->ee_handle = (tNFA_HANDLE)p_cb->nfcee_id | NFA_HANDLE_GROUP_EE;
@@ -2151,8 +2171,8 @@
     /* Start routing table update debounce timer */
     nfa_ee_start_timer();
   }
-  LOG(ERROR) << StringPrintf("%s p_rsp->status:0x%02x", __func__,
-                             p_rsp->status);
+  LOG(WARNING) << StringPrintf("%s p_rsp->status:0x%02x", __func__,
+                               p_rsp->status);
   if (p_rsp->status == NFA_STATUS_OK) {
     if (p_rsp->mode == NFA_EE_MD_ACTIVATE) {
       p_cb->ee_status = NFC_NFCEE_STATUS_ACTIVE;
@@ -2261,6 +2281,23 @@
 
 /*******************************************************************************
 **
+** Function         nfa_ee_pwr_and_link_ctrl_rsp
+**
+** Description      Process the result for NCI response
+**
+** Returns          void
+**
+*******************************************************************************/
+void nfa_ee_pwr_and_link_ctrl_rsp(tNFA_EE_MSG* p_data) {
+  tNFA_EE_CBACK_DATA evt_data;
+  if (p_data != nullptr) {
+    evt_data.status = NFA_STATUS_OK;
+    nfa_ee_report_event(nullptr, NFA_EE_PWR_AND_LINK_CTRL_EVT, &evt_data);
+  }
+}
+
+/*******************************************************************************
+**
 ** Function         nfa_ee_nci_conn
 **
 ** Description      process the connection callback events
diff --git a/src/nfa/ee/nfa_ee_api.cc b/src/nfa/ee/nfa_ee_api.cc
index bb6005a..4881261 100644
--- a/src/nfa/ee/nfa_ee_api.cc
+++ b/src/nfa/ee/nfa_ee_api.cc
@@ -953,3 +953,46 @@
 
   return status;
 }
+
+/*******************************************************************************
+**
+** Function         NFA_EePowerAndLinkCtrl
+**
+** Description      This Control Message is used by the DH to constrain the way
+**                  the NFCC manages the power supply and communication links
+**                  between the NFCC and its connected NFCEEs.
+**
+** Returns          NFA_STATUS_OK if successfully initiated
+**                  NFA_STATUS_FAILED otherwise
+**                  NFA_STATUS_INVALID_PARAM If bad parameter
+**
+*******************************************************************************/
+tNFA_STATUS NFA_EePowerAndLinkCtrl(tNFA_HANDLE ee_handle, uint8_t config) {
+  tNFA_EE_API_PWR_AND_LINK_CTRL* p_msg;
+  tNFA_STATUS status = NFA_STATUS_FAILED;
+  uint8_t nfcee_id = (uint8_t)(ee_handle & 0xFF);
+  tNFA_EE_ECB* p_cb;
+
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("handle:<0x%x>, config:<0x%x>", ee_handle, config);
+  p_cb = nfa_ee_find_ecb(nfcee_id);
+
+  if ((p_cb == nullptr) || (p_cb->ee_status != NFA_EE_STATUS_ACTIVE)) {
+    LOG(ERROR) << StringPrintf("Bad ee_handle");
+    status = NFA_STATUS_INVALID_PARAM;
+  } else {
+    p_msg = (tNFA_EE_API_PWR_AND_LINK_CTRL*)GKI_getbuf(
+        sizeof(tNFA_EE_API_PWR_AND_LINK_CTRL));
+    if (p_msg != nullptr) {
+      p_msg->hdr.event = NFA_EE_API_PWR_AND_LINK_CTRL_EVT;
+      p_msg->nfcee_id = nfcee_id;
+      p_msg->config = config;
+
+      nfa_sys_sendmsg(p_msg);
+
+      status = NFA_STATUS_OK;
+    }
+  }
+
+  return status;
+}
diff --git a/src/nfa/ee/nfa_ee_main.cc b/src/nfa/ee/nfa_ee_main.cc
index 69a70d0..6331771 100644
--- a/src/nfa/ee/nfa_ee_main.cc
+++ b/src/nfa/ee/nfa_ee_main.cc
@@ -52,35 +52,37 @@
 
 const tNFA_EE_SM_ACT nfa_ee_actions[] = {
     /* NFA-EE action function/ internal events */
-    nfa_ee_api_discover,        /* NFA_EE_API_DISCOVER_EVT      */
-    nfa_ee_api_register,        /* NFA_EE_API_REGISTER_EVT      */
-    nfa_ee_api_deregister,      /* NFA_EE_API_DEREGISTER_EVT    */
-    nfa_ee_api_mode_set,        /* NFA_EE_API_MODE_SET_EVT      */
-    nfa_ee_api_set_tech_cfg,    /* NFA_EE_API_SET_TECH_CFG_EVT  */
-    nfa_ee_api_clear_tech_cfg,  /*NFA_EE_API_CLEAR_TECH_CFG_EVT */
-    nfa_ee_api_set_proto_cfg,   /* NFA_EE_API_SET_PROTO_CFG_EVT */
-    nfa_ee_api_clear_proto_cfg, /*NFA_EE_API_CLEAR_PROTO_CFG_EVT*/
-    nfa_ee_api_add_aid,         /* NFA_EE_API_ADD_AID_EVT       */
-    nfa_ee_api_remove_aid,      /* NFA_EE_API_REMOVE_AID_EVT    */
-    nfa_ee_api_add_sys_code,    /* NFA_EE_API_ADD_SYSCODE_EVT   */
-    nfa_ee_api_remove_sys_code, /* NFA_EE_API_REMOVE_SYSCODE_EVT*/
-    nfa_ee_api_lmrt_size,       /* NFA_EE_API_LMRT_SIZE_EVT     */
-    nfa_ee_api_update_now,      /* NFA_EE_API_UPDATE_NOW_EVT    */
-    nfa_ee_api_connect,         /* NFA_EE_API_CONNECT_EVT       */
-    nfa_ee_api_send_data,       /* NFA_EE_API_SEND_DATA_EVT     */
-    nfa_ee_api_disconnect,      /* NFA_EE_API_DISCONNECT_EVT    */
-    nfa_ee_nci_disc_rsp,        /* NFA_EE_NCI_DISC_RSP_EVT      */
-    nfa_ee_nci_disc_ntf,        /* NFA_EE_NCI_DISC_NTF_EVT      */
-    nfa_ee_nci_mode_set_rsp,    /* NFA_EE_NCI_MODE_SET_RSP_EVT  */
-    nfa_ee_nci_conn,            /* NFA_EE_NCI_CONN_EVT          */
-    nfa_ee_nci_conn,            /* NFA_EE_NCI_DATA_EVT          */
-    nfa_ee_nci_action_ntf,      /* NFA_EE_NCI_ACTION_NTF_EVT    */
-    nfa_ee_nci_disc_req_ntf,    /* NFA_EE_NCI_DISC_REQ_NTF_EVT  */
-    nfa_ee_nci_wait_rsp,        /* NFA_EE_NCI_WAIT_RSP_EVT      */
-    nfa_ee_rout_timeout,        /* NFA_EE_ROUT_TIMEOUT_EVT      */
-    nfa_ee_discv_timeout,       /* NFA_EE_DISCV_TIMEOUT_EVT     */
-    nfa_ee_lmrt_to_nfcc,        /* NFA_EE_CFG_TO_NFCC_EVT       */
-    nfa_ee_nci_nfcee_status_ntf /*NFA_EE_NCI_NFCEE_STATUS_NTF_EVT*/
+    nfa_ee_api_discover,          /* NFA_EE_API_DISCOVER_EVT      */
+    nfa_ee_api_register,          /* NFA_EE_API_REGISTER_EVT      */
+    nfa_ee_api_deregister,        /* NFA_EE_API_DEREGISTER_EVT    */
+    nfa_ee_api_mode_set,          /* NFA_EE_API_MODE_SET_EVT      */
+    nfa_ee_api_set_tech_cfg,      /* NFA_EE_API_SET_TECH_CFG_EVT  */
+    nfa_ee_api_clear_tech_cfg,    /*NFA_EE_API_CLEAR_TECH_CFG_EVT */
+    nfa_ee_api_set_proto_cfg,     /* NFA_EE_API_SET_PROTO_CFG_EVT */
+    nfa_ee_api_clear_proto_cfg,   /*NFA_EE_API_CLEAR_PROTO_CFG_EVT*/
+    nfa_ee_api_add_aid,           /* NFA_EE_API_ADD_AID_EVT       */
+    nfa_ee_api_remove_aid,        /* NFA_EE_API_REMOVE_AID_EVT    */
+    nfa_ee_api_add_sys_code,      /* NFA_EE_API_ADD_SYSCODE_EVT   */
+    nfa_ee_api_remove_sys_code,   /* NFA_EE_API_REMOVE_SYSCODE_EVT*/
+    nfa_ee_api_lmrt_size,         /* NFA_EE_API_LMRT_SIZE_EVT     */
+    nfa_ee_api_update_now,        /* NFA_EE_API_UPDATE_NOW_EVT    */
+    nfa_ee_api_connect,           /* NFA_EE_API_CONNECT_EVT       */
+    nfa_ee_api_send_data,         /* NFA_EE_API_SEND_DATA_EVT     */
+    nfa_ee_api_disconnect,        /* NFA_EE_API_DISCONNECT_EVT    */
+    nfa_ee_api_pwr_and_link_ctrl, /* NFA_EE_API_PWR_AND_LINK_CTRL_EVT */
+    nfa_ee_nci_disc_rsp,          /* NFA_EE_NCI_DISC_RSP_EVT      */
+    nfa_ee_nci_disc_ntf,          /* NFA_EE_NCI_DISC_NTF_EVT      */
+    nfa_ee_nci_mode_set_rsp,      /* NFA_EE_NCI_MODE_SET_RSP_EVT  */
+    nfa_ee_nci_conn,              /* NFA_EE_NCI_CONN_EVT          */
+    nfa_ee_nci_conn,              /* NFA_EE_NCI_DATA_EVT          */
+    nfa_ee_nci_action_ntf,        /* NFA_EE_NCI_ACTION_NTF_EVT    */
+    nfa_ee_nci_disc_req_ntf,      /* NFA_EE_NCI_DISC_REQ_NTF_EVT  */
+    nfa_ee_nci_wait_rsp,          /* NFA_EE_NCI_WAIT_RSP_EVT      */
+    nfa_ee_rout_timeout,          /* NFA_EE_ROUT_TIMEOUT_EVT      */
+    nfa_ee_discv_timeout,         /* NFA_EE_DISCV_TIMEOUT_EVT     */
+    nfa_ee_lmrt_to_nfcc,          /* NFA_EE_CFG_TO_NFCC_EVT       */
+    nfa_ee_nci_nfcee_status_ntf,  /*NFA_EE_NCI_NFCEE_STATUS_NTF_EVT*/
+    nfa_ee_pwr_and_link_ctrl_rsp  /* NFA_EE_PWR_CONTROL_EVT */
 };
 
 /*******************************************************************************
@@ -354,6 +356,10 @@
     case NFC_NFCEE_STATUS_REVT:
       int_event = NFA_EE_NCI_NFCEE_STATUS_NTF_EVT;
       break;
+
+    case NFC_NFCEE_PL_CONTROL_REVT:
+      int_event = NFA_EE_PWR_CONTROL_EVT;
+      break;
   }
 
   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
@@ -598,6 +604,8 @@
       return "API_SEND_DATA";
     case NFA_EE_API_DISCONNECT_EVT:
       return "API_DISCONNECT";
+    case NFA_EE_API_PWR_AND_LINK_CTRL_EVT:
+      return "NFA_EE_API_PWR_AND_LINK_CTRL_EVT";
     case NFA_EE_NCI_DISC_RSP_EVT:
       return "NCI_DISC_RSP";
     case NFA_EE_NCI_DISC_NTF_EVT:
@@ -620,6 +628,8 @@
       return "NFA_EE_DISCV_TIMEOUT_EVT";
     case NFA_EE_CFG_TO_NFCC_EVT:
       return "CFG_TO_NFCC";
+    case NFA_EE_PWR_CONTROL_EVT:
+      return "NFA_EE_PWR_CONTROL_EVT";
     default:
       return "Unknown";
   }
diff --git a/src/nfa/include/nfa_api.h b/src/nfa/include/nfa_api.h
index d139966..d89c6f3 100755
--- a/src/nfa/include/nfa_api.h
+++ b/src/nfa/include/nfa_api.h
@@ -59,9 +59,14 @@
 #define NFA_STATUS_INVALID_PARAM NCI_STATUS_INVALID_PARAM
 /* Already started      */
 #define NFA_STATUS_ALREADY_STARTED NCI_STATUS_ALREADY_STARTED
+/* RF frame error       */
+#define NFA_STATUS_RF_FRAME_CORRUPTED NCI_STATUS_RF_FRAME_CORRUPTED
+/* RF protocol error    */
+#define NFA_STATUS_RF_PROTOCOL_ERR NCI_STATUS_RF_PROTOCOL_ERR
 /* RF Timeout           */
 #define NFA_STATUS_TIMEOUT NCI_STATUS_TIMEOUT
 
+#define NFA_STATUS_CONTINUE NFC_STATUS_CONTINUE
 /* Out of GKI buffers */
 #define NFA_STATUS_NO_BUFFERS NFC_STATUS_NO_BUFFERS
 /* Protocol mismatch between API and activated one */
@@ -331,6 +336,8 @@
 #define NFA_P2P_PAUSED_EVT 38
 /* P2P services resumed event */
 #define NFA_P2P_RESUMED_EVT 39
+/* T2T command completed */
+#define NFA_T2T_CMD_CPLT_EVT 40
 
 /* NFC deactivation type */
 #define NFA_DEACTIVATE_TYPE_IDLE NFC_DEACTIVATE_TYPE_IDLE
diff --git a/src/nfa/include/nfa_ee_api.h b/src/nfa/include/nfa_ee_api.h
index 8a60dcf..30a0867 100644
--- a/src/nfa/include/nfa_ee_api.h
+++ b/src/nfa/include/nfa_ee_api.h
@@ -67,6 +67,7 @@
   NFA_EE_NEW_EE_EVT, /* A new NFCEE is discovered                             */
   NFA_EE_ACTION_EVT, /* An action happened in NFCEE                           */
   NFA_EE_DISCOVER_REQ_EVT, /* NFCEE Discover Request Notification */
+  NFA_EE_PWR_AND_LINK_CTRL_EVT, /* NFCEE power and link ctrl */
   NFA_EE_NO_MEM_ERR_EVT,   /* Error - out of GKI buffers */
   NFA_EE_NO_CB_ERR_EVT /* Error - Can not find control block or wrong state */
 };
@@ -584,4 +585,20 @@
 *******************************************************************************/
 extern tNFA_STATUS NFA_EeDisconnect(tNFA_HANDLE ee_handle);
 
+/*******************************************************************************
+**
+** Function         NFA_EePowerAndLinkCtrl
+**
+** Description      This Control Message is used by the DH to constrain the way
+**                  the NFCC manages the power supply and communication links
+**                  between the NFCC and its connected NFCEEs.
+**
+** Returns          NFA_STATUS_OK if successfully initiated
+**                  NFA_STATUS_FAILED otherwise
+**                  NFA_STATUS_INVALID_PARAM If bad parameter
+**
+*******************************************************************************/
+extern tNFA_STATUS NFA_EePowerAndLinkCtrl(tNFA_HANDLE ee_handle,
+                                          uint8_t config);
+
 #endif /* NFA_EE_API_H */
diff --git a/src/nfa/include/nfa_ee_int.h b/src/nfa/include/nfa_ee_int.h
index bf9a864..cf1781a 100644
--- a/src/nfa/include/nfa_ee_int.h
+++ b/src/nfa/include/nfa_ee_int.h
@@ -62,6 +62,7 @@
   NFA_EE_API_CONNECT_EVT,
   NFA_EE_API_SEND_DATA_EVT,
   NFA_EE_API_DISCONNECT_EVT,
+  NFA_EE_API_PWR_AND_LINK_CTRL_EVT,
 
   NFA_EE_NCI_DISC_RSP_EVT,
   NFA_EE_NCI_DISC_NTF_EVT,
@@ -76,8 +77,8 @@
   NFA_EE_DISCV_TIMEOUT_EVT,
   NFA_EE_CFG_TO_NFCC_EVT,
   NFA_EE_NCI_NFCEE_STATUS_NTF_EVT,
+  NFA_EE_PWR_CONTROL_EVT,
   NFA_EE_MAX_EVT
-
 };
 
 typedef uint16_t tNFA_EE_INT_EVT;
@@ -129,7 +130,7 @@
 /* AID routing changed                */
 #define NFA_EE_ECB_FLAGS_AID 0x08
 /* System Code routing changed        */
-#define NFA_EE_ECB_FLAGS_SYSCODE 0xE0
+#define NFA_EE_ECB_FLAGS_SYSCODE 0x01
 /* VS changed                         */
 #define NFA_EE_ECB_FLAGS_VS 0x10
 /* Restore related                    */
@@ -335,6 +336,14 @@
   uint8_t nfcee_id;
 } tNFA_EE_API_DISCONNECT;
 
+/* data type for NFA_EE_API_PWR_AND_LINK_CTRL_EVT */
+typedef struct {
+  NFC_HDR hdr;
+  tNFA_EE_ECB* p_cb;
+  uint8_t nfcee_id;
+  uint8_t config;
+} tNFA_EE_API_PWR_AND_LINK_CTRL;
+
 /* common data type for internal events with nfa_ee_use_cfg_cb[] as TRUE */
 typedef struct {
   NFC_HDR hdr;
@@ -393,6 +402,12 @@
   tNFC_NFCEE_STATUS_REVT* p_data;
 } tNFA_EE_NCI_NFCEE_STATUS_NTF;
 
+/* data type for NFA_EE_NCI_NFCEE_STATUS_EVT */
+typedef struct {
+  NFC_HDR hdr;
+  tNFC_NFCEE_PL_CONTROL_REVT* p_data;
+} tNFA_EE_NCI_PWR_AND_LINK_CTRL_RSP;
+
 /* union of all event data types */
 typedef union {
   NFC_HDR hdr;
@@ -413,6 +428,7 @@
   tNFA_EE_API_CONNECT connect;
   tNFA_EE_API_SEND_DATA send_data;
   tNFA_EE_API_DISCONNECT disconnect;
+  tNFA_EE_API_PWR_AND_LINK_CTRL pwr_and_link_ctrl;
   tNFA_EE_NCI_DISC_RSP disc_rsp;
   tNFA_EE_NCI_DISC_NTF disc_ntf;
   tNFA_EE_NCI_MODE_SET mode_set_rsp;
@@ -421,6 +437,7 @@
   tNFA_EE_NCI_ACTION act;
   tNFA_EE_NCI_DISC_REQ disc_req;
   tNFA_EE_NCI_NFCEE_STATUS_NTF nfcee_status_ntf;
+  tNFA_EE_NCI_PWR_AND_LINK_CTRL_RSP ncfee_pwr_and_link_ctrl_rsp;
 } tNFA_EE_MSG;
 
 /* type for State Machine (SM) action functions */
@@ -545,11 +562,13 @@
 void nfa_ee_api_connect(tNFA_EE_MSG* p_data);
 void nfa_ee_api_send_data(tNFA_EE_MSG* p_data);
 void nfa_ee_api_disconnect(tNFA_EE_MSG* p_data);
+void nfa_ee_api_pwr_and_link_ctrl(tNFA_EE_MSG* p_data);
 void nfa_ee_report_disc_done(bool notify_sys);
 void nfa_ee_nci_disc_rsp(tNFA_EE_MSG* p_data);
 void nfa_ee_nci_disc_ntf(tNFA_EE_MSG* p_data);
 void nfa_ee_nci_mode_set_rsp(tNFA_EE_MSG* p_data);
 void nfa_ee_nci_nfcee_status_ntf(tNFA_EE_MSG* p_data);
+void nfa_ee_pwr_and_link_ctrl_rsp(tNFA_EE_MSG* p_data);
 void nfa_ee_nci_wait_rsp(tNFA_EE_MSG* p_data);
 void nfa_ee_nci_conn(tNFA_EE_MSG* p_data);
 void nfa_ee_nci_action_ntf(tNFA_EE_MSG* p_data);
diff --git a/src/nfa/include/nfa_rw_api.h b/src/nfa/include/nfa_rw_api.h
index ee9bec7..c9ba23c 100644
--- a/src/nfa/include/nfa_rw_api.h
+++ b/src/nfa/include/nfa_rw_api.h
@@ -417,6 +417,24 @@
 
 /*******************************************************************************
 **
+** Function         NFA_RwT2tReadDynLockBytes
+**
+** Description:
+**      Configure NFA skip_dyn_locks flag to send or not READ commands to the
+**      activated Type 2 tag to read the DynLock_Area contents.
+**
+**      When the operation has completed (or if an error occurs), the app will
+**      be notified with NFA_T2T_CMD_CPLT_EVT.
+**
+** Returns:
+**      NFA_STATUS_OK if successfully initiated
+**      NFA_STATUS_FAILED otherwise
+**
+*******************************************************************************/
+extern tNFA_STATUS NFA_RwT2tReadDynLockBytes(bool read_dyn_locks);
+
+/*******************************************************************************
+**
 ** Function         NFA_RwT3tRead
 **
 ** Description:
@@ -491,7 +509,7 @@
 **      NFA_STATUS_FAILED otherwise
 **
 *******************************************************************************/
-extern tNFA_STATUS NFA_RwI93StayQuiet(void);
+extern tNFA_STATUS NFA_RwI93StayQuiet(uint8_t* p_uid);
 
 /*******************************************************************************
 **
@@ -742,4 +760,21 @@
 extern tNFA_STATUS NFA_RwI93GetMultiBlockSecurityStatus(
     uint8_t first_block_number, uint16_t number_blocks);
 
+/*******************************************************************************
+**
+** Function         NFA_RwI93SetAddressingMode
+**
+** Description:
+**      Set addressing mode to use to communicate with T5T tag.
+**      mode = true: addressed (default if API not called)
+**      mode = false: non-addressed
+**
+** Returns:
+**      NFA_STATUS_OK if successfully initiated
+**      NFA_STATUS_WRONG_PROTOCOL: T5T tag not activated
+**      NFA_STATUS_FAILED otherwise
+**
+*******************************************************************************/
+extern tNFA_STATUS NFA_RwI93SetAddressingMode(bool mode);
+
 #endif /* NFA_RW_API_H */
diff --git a/src/nfa/include/nfa_rw_int.h b/src/nfa/include/nfa_rw_int.h
index f9a53c2..38101d7 100644
--- a/src/nfa/include/nfa_rw_int.h
+++ b/src/nfa/include/nfa_rw_int.h
@@ -95,6 +95,7 @@
   NFA_RW_OP_T2T_READ,
   NFA_RW_OP_T2T_WRITE,
   NFA_RW_OP_T2T_SECTOR_SELECT,
+  NFA_RW_OP_T2T_READ_DYN_LOCKS,
 
   /* Exclusive Type-3 tag operations */
   NFA_RW_OP_T3T_READ,
@@ -117,7 +118,7 @@
   NFA_RW_OP_I93_LOCK_DSFID,
   NFA_RW_OP_I93_GET_SYS_INFO,
   NFA_RW_OP_I93_GET_MULTI_BLOCK_STATUS,
-
+  NFA_RW_OP_I93_SET_ADDR_MODE,
   NFA_RW_OP_MAX
 };
 typedef uint8_t tNFA_RW_OP;
@@ -164,6 +165,11 @@
 /* NFA_RW_OP_T2T_SECTOR_SELECT params */
 typedef struct { uint8_t sector_number; } tNFA_RW_OP_PARAMS_T2T_SECTOR_SELECT;
 
+/* NFA_RW_OP_T2T_READ_DYN_LOCKS params */
+typedef struct {
+  bool read_dyn_locks;
+} tNFA_RW_OP_PARAMS_T2T_READ_DYN_LOCKS;
+
 /* NFA_RW_OP_T3T_READ params */
 typedef struct {
   uint8_t num_blocks;
@@ -184,6 +190,7 @@
   bool afi_present;
   uint8_t afi;
   uint8_t dsfid;
+  bool addr_mode;
   uint16_t first_block_number;
   uint16_t number_blocks;
   uint8_t* p_data;
@@ -209,6 +216,7 @@
   tNFA_RW_OP_PARAMS_T2T_READ t2t_read;
   tNFA_RW_OP_PARAMS_T2T_WRITE t2t_write;
   tNFA_RW_OP_PARAMS_T2T_SECTOR_SELECT t2t_sector_select;
+  tNFA_RW_OP_PARAMS_T2T_READ_DYN_LOCKS t2t_read_dyn_locks;
 
   /* params for NFA_RW_OP_T3T_READ and NFA_RW_OP_T3T_WRITE */
   tNFA_RW_OP_PARAMS_T3T_READ t3t_read;
@@ -315,6 +323,7 @@
   uint8_t i93_block_size;
   uint16_t i93_num_block;
   uint8_t i93_uid[I93_UID_BYTE_LEN];
+  uint8_t i93_addr_mode;
 } tNFA_RW_CB;
 extern tNFA_RW_CB nfa_rw_cb;
 
diff --git a/src/nfa/rw/nfa_rw_act.cc b/src/nfa/rw/nfa_rw_act.cc
index 0c0e608..4721b68 100644
--- a/src/nfa/rw/nfa_rw_act.cc
+++ b/src/nfa/rw/nfa_rw_act.cc
@@ -776,7 +776,7 @@
       break;
 
     case RW_T2T_TLV_DETECT_EVT: /* Lock control/Mem/Prop tlv detection complete
-                                   */
+                                 */
       nfa_rw_handle_tlv_detect(p_rw_data);
       break;
 
@@ -966,6 +966,9 @@
       break;
 
     case RW_T3T_INTF_ERROR_EVT:
+      DLOG_IF(INFO, nfc_debug_enabled)
+          << StringPrintf("%s; send deactivate", __func__);
+      nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_DISCOVERY);
       conn_evt_data.status = p_rw_data->status;
       nfa_dm_act_conn_cback_notify(NFA_RW_INTF_ERROR_EVT, &conn_evt_data);
       break;
@@ -1696,8 +1699,7 @@
       status = RW_T3tUpdateNDef(nfa_rw_cb.ndef_wr_len, nfa_rw_cb.p_ndef_wr_buf);
     } else if (NFC_PROTOCOL_ISO_DEP == protocol) {
       /* ISODEP/4A,4B- NFC-A or NFC-B */
-      status = RW_T4tUpdateNDef((uint16_t)nfa_rw_cb.ndef_wr_len,
-                                nfa_rw_cb.p_ndef_wr_buf);
+      status = RW_T4tUpdateNDef(nfa_rw_cb.ndef_wr_len, nfa_rw_cb.p_ndef_wr_buf);
     } else if (NFC_PROTOCOL_T5T == protocol) {
       /* ISO 15693 */
       status = RW_I93UpdateNDef((uint16_t)nfa_rw_cb.ndef_wr_len,
@@ -1790,8 +1792,8 @@
   } else if (nfa_rw_cb.ndef_st == NFA_RW_NDEF_ST_FALSE) {
     if (nfa_rw_cb.protocol == NFC_PROTOCOL_T1T) {
       /* For Type 1 tag, NDEF can be written on Initialized tag
-      *  Perform ndef detection first to check if tag is in Initialized state to
-      * Write NDEF */
+       *  Perform ndef detection first to check if tag is in Initialized state
+       * to Write NDEF */
       write_status = nfa_rw_start_ndef_detection();
     } else {
       /* Tag is not NDEF */
@@ -2366,7 +2368,7 @@
 
     case NFA_RW_OP_I93_STAY_QUIET:
       i93_command = I93_CMD_STAY_QUIET;
-      status = RW_I93StayQuiet();
+      status = RW_I93StayQuiet(p_data->op_req.params.i93_cmd.p_data);
       break;
 
     case NFA_RW_OP_I93_READ_SINGLE_BLOCK:
@@ -2449,6 +2451,25 @@
           p_data->op_req.params.i93_cmd.number_blocks);
       break;
 
+    case NFA_RW_OP_I93_SET_ADDR_MODE:
+      i93_command = I93_CMD_SET_ADDR_MODE;
+      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+          "%s - T5T addressing mode (0: addressed, "
+          "1: non-addressed) is %d",
+          __func__, p_data->op_req.params.i93_cmd.addr_mode);
+
+      status = RW_I93SetAddressingMode(p_data->op_req.params.i93_cmd.addr_mode);
+      if (status != NFC_STATUS_OK) {
+        break;
+      }
+
+      /* Command complete - perform cleanup, notify app */
+      nfa_rw_command_complete();
+      conn_evt_data.i93_cmd_cplt.status = NFA_STATUS_OK;
+      conn_evt_data.i93_cmd_cplt.sent_command = i93_command;
+      nfa_dm_act_conn_cback_notify(NFA_I93_CMD_CPLT_EVT, &conn_evt_data);
+      break;
+
     default:
       break;
   }
@@ -2634,22 +2655,16 @@
     memcpy(tag_params.t2t.uid, p_activate_params->rf_tech_param.param.pa.nfcid1,
            p_activate_params->rf_tech_param.param.pa.nfcid1_len);
   } else if (NFC_PROTOCOL_T3T == nfa_rw_cb.protocol) {
-    if (appl_dta_mode_flag) {
-      /* Incase of DTA mode Dont send commands to get system code. Just notify
-       * activation */
-      activate_notify = true;
-    } else {
-      /* Delay notifying upper layer of NFA_ACTIVATED_EVT until system codes
-       * are retrieved */
-      activate_notify = false;
+    /* Delay notifying upper layer of NFA_ACTIVATED_EVT until system codes
+     * are retrieved */
+    activate_notify = false;
 
-      /* Issue command to get Felica system codes */
-      tNFA_RW_MSG msg;
-      msg.op_req.op = NFA_RW_OP_T3T_GET_SYSTEM_CODES;
-      bool free_buf = nfa_rw_handle_op_req(&msg);
-      CHECK(free_buf)
-          << "nfa_rw_handle_op_req is holding on to soon-garbage stack memory.";
-    }
+    /* Issue command to get Felica system codes */
+    tNFA_RW_MSG msg;
+    msg.op_req.op = NFA_RW_OP_T3T_GET_SYSTEM_CODES;
+    bool free_buf = nfa_rw_handle_op_req(&msg);
+    CHECK(free_buf)
+        << "nfa_rw_handle_op_req is holding on to soon-garbage stack memory.";
   } else if (NFA_PROTOCOL_T5T == nfa_rw_cb.protocol) {
     /* Delay notifying upper layer of NFA_ACTIVATED_EVT to retrieve additional
      * tag infomation */
@@ -2699,8 +2714,23 @@
       /* Tag-it HF-I Plus Chip/Inlay supports Get System Information Command */
       /* just try for others */
 
-      if (RW_I93GetSysInfo(nfa_rw_cb.i93_uid) != NFC_STATUS_OK) {
-        /* notify activation without AFI/MEM size/IC-Ref */
+      if (!appl_dta_mode_flag) {
+        if (RW_I93GetSysInfo(nfa_rw_cb.i93_uid) != NFC_STATUS_OK) {
+          /* notify activation without AFI/MEM size/IC-Ref */
+          nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING;
+          activate_notify = true;
+
+          tag_params.i93.info_flags = I93_INFO_FLAG_DSFID;
+          tag_params.i93.dsfid = nfa_rw_cb.i93_dsfid;
+          tag_params.i93.block_size = 0;
+          tag_params.i93.num_block = 0;
+          memcpy(tag_params.i93.uid, nfa_rw_cb.i93_uid, I93_UID_BYTE_LEN);
+        } else {
+          /* reset memory size */
+          nfa_rw_cb.i93_block_size = 0;
+          nfa_rw_cb.i93_num_block = 0;
+        }
+      } else {
         nfa_rw_cb.flags &= ~NFA_RW_FL_ACTIVATION_NTF_PENDING;
         activate_notify = true;
 
@@ -2709,10 +2739,6 @@
         tag_params.i93.block_size = 0;
         tag_params.i93.num_block = 0;
         memcpy(tag_params.i93.uid, nfa_rw_cb.i93_uid, I93_UID_BYTE_LEN);
-      } else {
-        /* reset memory size */
-        nfa_rw_cb.i93_block_size = 0;
-        nfa_rw_cb.i93_num_block = 0;
       }
     }
   }
@@ -2779,6 +2805,7 @@
 **
 *******************************************************************************/
 bool nfa_rw_handle_op_req(tNFA_RW_MSG* p_data) {
+  tNFA_CONN_EVT_DATA conn_evt_data;
   bool freebuf = true;
   uint16_t presence_check_start_delay = 0;
 
@@ -2817,7 +2844,6 @@
   /* Call appropriate handler for requested operation */
   switch (p_data->op_req.op) {
     case NFA_RW_OP_DETECT_NDEF:
-      nfa_rw_cb.skip_dyn_locks = false;
       nfa_rw_detect_ndef();
       break;
 
@@ -2904,6 +2930,22 @@
       nfa_rw_t2t_sector_select(p_data);
       break;
 
+    case NFA_RW_OP_T2T_READ_DYN_LOCKS:
+      if (p_data->op_req.params.t2t_read_dyn_locks.read_dyn_locks == true) {
+        nfa_rw_cb.skip_dyn_locks = false;
+      } else {
+        nfa_rw_cb.skip_dyn_locks = true;
+      }
+      DLOG_IF(INFO, nfc_debug_enabled)
+          << StringPrintf("%s - Skip reading of dynamic lock bytes: %d",
+                          __func__, nfa_rw_cb.skip_dyn_locks);
+
+      /* Command complete - perform cleanup, notify app */
+      nfa_rw_command_complete();
+      conn_evt_data.status = NFA_STATUS_OK;
+      nfa_dm_act_conn_cback_notify(NFA_T2T_CMD_CPLT_EVT, &conn_evt_data);
+      break;
+
     /* Type-3 tag commands */
     case NFA_RW_OP_T3T_READ:
       nfa_rw_t3t_read(p_data);
@@ -2933,6 +2975,7 @@
     case NFA_RW_OP_I93_LOCK_DSFID:
     case NFA_RW_OP_I93_GET_SYS_INFO:
     case NFA_RW_OP_I93_GET_MULTI_BLOCK_STATUS:
+    case NFA_RW_OP_I93_SET_ADDR_MODE:
       nfa_rw_i93_command(p_data);
       break;
 
diff --git a/src/nfa/rw/nfa_rw_api.cc b/src/nfa/rw/nfa_rw_api.cc
index 1c130f7..0e7a98e 100644
--- a/src/nfa/rw/nfa_rw_api.cc
+++ b/src/nfa/rw/nfa_rw_api.cc
@@ -699,6 +699,48 @@
 
 /*******************************************************************************
 **
+** Function         NFA_RwT2tReadDynLockBytes
+**
+** Description:
+**      Configure NFA skip_dyn_locks flag.
+**
+**      This API must be called after activation but before NFA_RwDetectNDef()
+**      or NFA_RwReadNDef() and NFA_RwWriteNDef() in case NDEF Detection is
+**      triggered internally. It overwrites skip_dyn_locks default setting
+**      set to false at activation. If not called, at the end of the NDEF
+**      Detection, the DynLock_Area will be read and its content used to define
+**      max_ndef_msg_len.
+**
+**      When the operation has completed (or if an error occurs), the app will
+**      be notified with NFA_T2T_CMD_CPLT_EVT.
+**
+** Returns:
+**      NFA_STATUS_OK if successfully initiated
+**      NFA_STATUS_FAILED otherwise
+**
+*******************************************************************************/
+tNFA_STATUS NFA_RwT2tReadDynLockBytes(bool read_dyn_locks) {
+  tNFA_RW_OPERATION* p_msg;
+
+  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+      "%s - read DynLock_Area bytes: %d", __func__, read_dyn_locks);
+
+  p_msg = (tNFA_RW_OPERATION*)GKI_getbuf((uint16_t)(sizeof(tNFA_RW_OPERATION)));
+  if (p_msg != nullptr) {
+    /* Fill in tNFA_RW_OPERATION struct */
+    p_msg->hdr.event = NFA_RW_OP_REQUEST_EVT;
+    p_msg->op = NFA_RW_OP_T2T_READ_DYN_LOCKS;
+
+    p_msg->params.t2t_read_dyn_locks.read_dyn_locks = read_dyn_locks;
+
+    nfa_sys_sendmsg(p_msg);
+    return (NFA_STATUS_OK);
+  }
+  return (NFA_STATUS_FAILED);
+}
+
+/*******************************************************************************
+**
 ** Function         NFA_RwT3tRead
 **
 ** Description:
@@ -874,7 +916,7 @@
 **      NFA_STATUS_FAILED otherwise
 **
 *******************************************************************************/
-tNFA_STATUS NFA_RwI93StayQuiet(void) {
+tNFA_STATUS NFA_RwI93StayQuiet(uint8_t* p_uid) {
   tNFA_RW_OPERATION* p_msg;
 
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
@@ -888,6 +930,8 @@
     /* Fill in tNFA_RW_OPERATION struct */
     p_msg->hdr.event = NFA_RW_OP_REQUEST_EVT;
     p_msg->op = NFA_RW_OP_I93_STAY_QUIET;
+    p_msg->params.i93_cmd.p_data = (uint8_t*)(p_msg + 1);
+    memcpy(p_msg->params.i93_cmd.p_data, p_uid, I93_UID_BYTE_LEN);
 
     nfa_sys_sendmsg(p_msg);
 
@@ -1480,3 +1524,43 @@
 
   return (NFA_STATUS_FAILED);
 }
+
+/*******************************************************************************
+**
+** Function         NFA_RwI93SetAddressingMode
+**
+** Description:
+**      Set addressing mode to use to communicate with T5T tag.
+**      mode = true: addressed (default if API not called)
+**      mode = false: non-addressed
+**
+** Returns:
+**      NFA_STATUS_OK if successfully initiated
+**      NFA_STATUS_WRONG_PROTOCOL: T5T tag not activated
+**      NFA_STATUS_FAILED otherwise
+**
+*******************************************************************************/
+tNFA_STATUS NFA_RwI93SetAddressingMode(bool mode) {
+  tNFA_RW_OPERATION* p_msg;
+
+  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s - %d", __func__, mode);
+
+  if (nfa_rw_cb.protocol != NFC_PROTOCOL_T5T) {
+    return (NFA_STATUS_WRONG_PROTOCOL);
+  }
+
+  p_msg = (tNFA_RW_OPERATION*)GKI_getbuf((uint16_t)(sizeof(tNFA_RW_OPERATION)));
+  if (p_msg != nullptr) {
+    /* Fill in tNFA_RW_OPERATION struct */
+    p_msg->hdr.event = NFA_RW_OP_REQUEST_EVT;
+    p_msg->op = NFA_RW_OP_I93_SET_ADDR_MODE;
+
+    p_msg->params.i93_cmd.addr_mode = mode;
+
+    nfa_sys_sendmsg(p_msg);
+
+    return (NFA_STATUS_OK);
+  }
+
+  return (NFA_STATUS_FAILED);
+}
diff --git a/src/nfc/include/nfc_api.h b/src/nfc/include/nfc_api.h
index 5e4d6ca..145bbf0 100644
--- a/src/nfc/include/nfc_api.h
+++ b/src/nfc/include/nfc_api.h
@@ -113,8 +113,14 @@
  * NFC Config Parameter IDs defined by NCI
  **********************************************/
 #define NFC_PMID_TOTAL_DURATION NCI_PARAM_ID_TOTAL_DURATION
+#define NFC_PMID_PA_BAILOUT NCI_PARAM_ID_PA_BAILOUT
 #define NFC_PMID_PF_RC NCI_PARAM_ID_PF_RC
+#define NFC_PMID_PB_BAILOUT NCI_PARAM_ID_PB_BAILOUT
+#define NFC_PMID_PF_BIT_RATE NCI_PARAM_ID_PF_BIT_RATE
+#define NFC_PMID_PF_BAILOUT NCI_PARAM_ID_PF_BAILOUT
+#define NFC_PMID_PF_DEVICES_LIMIT NCI_PARAM_ID_PF_DEVICES_LIMIT
 #define NFC_PMID_ATR_REQ_GEN_BYTES NCI_PARAM_ID_ATR_REQ_GEN_BYTES
+#define NFC_PMID_ATR_REQ_CONFIG NCI_PARAM_ID_ATR_REQ_CONFIG
 #define NFC_PMID_LA_HIST_BY NCI_PARAM_ID_LA_HIST_BY
 #define NFC_PMID_LA_NFCID1 NCI_PARAM_ID_LA_NFCID1
 #define NFC_PMID_LA_BIT_FRAME_SDD NCI_PARAM_ID_LA_BIT_FRAME_SDD
@@ -135,6 +141,7 @@
 #define NFC_PMID_WT NCI_PARAM_ID_WT
 #define NFC_PMID_ATR_RES_GEN_BYTES NCI_PARAM_ID_ATR_RES_GEN_BYTES
 #define NFC_PMID_ATR_RSP_CONFIG NCI_PARAM_ID_ATR_RSP_CONFIG
+#define NFC_PMID_PACM_BIT_RATE NCI_PARAM_ID_PACM_BIT_RATE
 #define NFC_PMID_RF_FIELD_INFO NCI_PARAM_ID_RF_FIELD_INFO
 
 /* Technology based routing  */
diff --git a/src/nfc/include/rw_api.h b/src/nfc/include/rw_api.h
index ea9c1cf..242b568 100644
--- a/src/nfc/include/rw_api.h
+++ b/src/nfc/include/rw_api.h
@@ -169,6 +169,9 @@
 #define RW_T4T_CHK_EMPTY_I_BLOCK 1
 #define RW_T4T_CHK_ISO_DEP_NAK_PRES_CHK 5
 
+#define RW_I93_MODE_ADDRESSED 0
+#define RW_I93_MODE_NON_ADDRESSED 1
+
 typedef struct {
   tNFC_STATUS status;
   uint16_t msg_len; /* Length of the NDEF message */
@@ -933,7 +936,7 @@
 **                  NFC_STATUS_FAILED if T4T is busy or other error
 **
 *******************************************************************************/
-extern tNFC_STATUS RW_T4tUpdateNDef(uint16_t length, uint8_t* p_data);
+extern tNFC_STATUS RW_T4tUpdateNDef(uint32_t length, uint8_t* p_data);
 
 /*****************************************************************************
 **
@@ -1002,7 +1005,7 @@
 **                  NFC_STATUS_FAILED if other error
 **
 *******************************************************************************/
-extern tNFC_STATUS RW_I93StayQuiet(void);
+extern tNFC_STATUS RW_I93StayQuiet(uint8_t* p_uid);
 
 /*******************************************************************************
 **
@@ -1326,6 +1329,22 @@
 *****************************************************************************/
 extern tNFC_STATUS RW_I93PresenceCheck(void);
 
+/*****************************************************************************
+**
+** Function         RW_I93SetAddressingMode
+**
+** Description      Set if the tag must be addressed with UID or not.
+**
+**                  The addressing mode (addressed or non-addressed) must be
+**                  done at the module initialization prior to the Tag
+**                  activation.
+**
+** Returns          NFC_STATUS_OK, if mode is stored
+**                  NFC_STATUS_FAILED: other error
+**
+*****************************************************************************/
+extern tNFC_STATUS RW_I93SetAddressingMode(bool mode);
+
 /*******************************************************************************
 **
 ** Function         RW_SendRawFrame
diff --git a/src/nfc/include/rw_int.h b/src/nfc/include/rw_int.h
index 5c95e76..e25f48e 100644
--- a/src/nfc/include/rw_int.h
+++ b/src/nfc/include/rw_int.h
@@ -254,7 +254,7 @@
 /* Maximum supported Lock control TLVS in the tag           */
 #define RW_T2T_MAX_LOCK_TLVS 0x05
 /* Maximum supported dynamic lock bytes                     */
-#define RW_T2T_MAX_LOCK_BYTES 0x1E
+#define RW_T2T_MAX_LOCK_BYTES 0x20
 #define RW_T2T_SEGMENT_BYTES 128
 #define RW_T2T_SEGMENT_SIZE 16
 
@@ -361,19 +361,17 @@
 #define RW_T2T_SUBSTATE_WAIT_READ_DYN_LOCK_BYTE_BLOCK 0x1A
 /* waiting for response to set dynamic lock bits            */
 #define RW_T2T_SUBSTATE_WAIT_SET_DYN_LOCK_BITS 0x1B
-/* waiting for response to set static lock bits             */
-#define RW_T2T_SUBSTATE_WAIT_SET_ST_LOCK_BITS 0x1C
 
 typedef struct {
   uint16_t offset;              /* Offset of the lock byte in the Tag */
-  uint8_t num_bits;             /* Number of lock bits in the lock byte */
-  uint8_t bytes_locked_per_bit; /* No. of tag bytes gets locked by a bit in this
-                                   byte       */
+  uint16_t num_bits;            /* Number of lock bits in the lock byte */
+  uint16_t bytes_locked_per_bit; /* No. of tag bytes gets locked by a bit
+                                    in this byte */
 } tRW_T2T_LOCK_INFO;
 
 typedef struct {
   uint16_t offset;   /* Reserved bytes offset taken from Memory control TLV */
-  uint8_t num_bytes; /* Number of reserved bytes as per the TLV */
+  uint16_t num_bytes; /* Number of reserved bytes as per the TLV */
 } tRW_T2T_RES_INFO;
 
 typedef struct {
@@ -527,6 +525,8 @@
   uint8_t cur_poll_rc; /* RC used in current POLL command */
 
   uint8_t flags; /* Flags see RW_T3T_FL_* */
+  /* Recall System Code used in last T3T polling command */
+  int32_t cur_active_sc;
 } tRW_T3T_CB;
 
 /*
@@ -540,16 +540,34 @@
 
 /* Max data size using a single UpdateBinary. 6 bytes are for CLA, INS, P1, P2,
  * Lc */
+/* Use worst case where Extended Field Coding and ODO format are used */
 #define RW_T4T_MAX_DATA_PER_WRITE                              \
   (NFC_RW_POOL_BUF_SIZE - NFC_HDR_SIZE - NCI_MSG_OFFSET_SIZE - \
-   NCI_DATA_HDR_SIZE - T4T_CMD_MAX_HDR_SIZE)
+   NCI_DATA_HDR_SIZE - T4T_CMD_MAX_EXT_HDR_SIZE)
 
+#define RW_T4T_EXT_FIELD_CODING 0x01
+#define RW_T4T_DDO_LC_FIELD_CODING 0x02
+
+#define RW_T4T_BER_TLV_LENGTH_1_BYTE 0x01
+#define RW_T4T_BER_TLV_LENGTH_2_BYTES 0x02
+#define RW_T4T_BER_TLV_LENGTH_3_BYTES 0x03
+
+/* Minimum data header in command APDU data:
+ * ODO: 54 00 xxyyzz: tag '54' with 3-byte offset xxyyzz
+ * DDO: 53 Ld {data to be written to the ENDEF File}
+ * Ld (data length) can be 1, 2 or 3 bytes
+ */
+#define RW_T4T_ODO_DDO_HEADER_MIN_LENGTH 0x06 /* ODO + tag '53' */
+/* Ld encoded on two bytes with '81' tag and N=0 to 255
+ * for data field length coded on one byte */
+#define RW_T4T_ODO_DDO_HEADER_2BYTES_LENGTH 8 /* ODO + tag '53' + '81' + N */
 /* Mandatory NDEF file control */
 typedef struct {
   uint16_t file_id;       /* File Identifier          */
-  uint16_t max_file_size; /* Max NDEF file size       */
+  uint32_t max_file_size; /* Max NDEF file size       */
   uint8_t read_access;    /* read access condition    */
   uint8_t write_access;   /* write access condition   */
+  uint8_t nlen_size;      /* (E)NLEN size (2 or 4 bytes) */
 } tRW_T4T_NDEF_FC;
 
 /* Capability Container */
@@ -571,10 +589,11 @@
   uint8_t version;               /* currently effective version      */
   TIMER_LIST_ENT timer;          /* timeout for each API call        */
 
-  uint16_t ndef_length;    /* length of NDEF data              */
-  uint8_t* p_update_data;  /* pointer of data to update        */
-  uint16_t rw_length;      /* remaining bytes to read/write    */
-  uint16_t rw_offset;      /* remaining offset to read/write   */
+  uint32_t ndef_length;   /* length of NDEF data              */
+  uint8_t* p_update_data; /* pointer of data to update        */
+  uint32_t rw_length;     /* remaining bytes to read/write    */
+  uint32_t rw_offset;     /* remaining offset to read/write   */
+
   NFC_HDR* p_data_to_free; /* GKI buffet to delete after done  */
 
   tRW_T4T_CC cc_file; /* Capability Container File        */
@@ -591,6 +610,7 @@
   uint16_t max_update_size; /* max updating size per a command  */
   uint16_t card_size;
   uint8_t card_type;
+  uint8_t intl_flags; /* flags for internal information   */
 } tRW_T4T_CB;
 
 /* RW retransmission statistics */
@@ -665,6 +685,10 @@
 #define RW_I93_FLAG_16BIT_NUM_BLOCK 0x10
 /* use extended commands */
 #define RW_I93_FLAG_EXT_COMMANDS 0x20
+/* use Special Frame in Write-Alike commands */
+#define RW_I93_FLAG_SPECIAL_FRAME 0x40
+/* use SMS bit in Selected state           */
+#define RW_I93_FLAG_SELECTED_STATE 0x80
 
 /* searching for type                      */
 #define RW_I93_TLV_DETECT_STATE_TYPE 0x01
@@ -676,6 +700,50 @@
 #define RW_I93_TLV_DETECT_STATE_LENGTH_3 0x04
 /* reading value field                     */
 #define RW_I93_TLV_DETECT_STATE_VALUE 0x05
+#define RW_I93_GET_SYS_INFO_MEM_INFO 1
+#define RW_T5T_CC_READ_MEM_INFO 0
+
+/* capability Container CC Size */
+#define RW_I93_CC_SIZE 4
+
+/* main state */
+enum {
+  RW_I93_STATE_NOT_ACTIVATED, /* ISO15693 is not activated            */
+  RW_I93_STATE_IDLE,          /* waiting for upper layer API          */
+  RW_I93_STATE_BUSY,          /* waiting for response from tag        */
+
+  RW_I93_STATE_DETECT_NDEF,   /* performing NDEF detection precedure  */
+  RW_I93_STATE_READ_NDEF,     /* performing read NDEF procedure       */
+  RW_I93_STATE_UPDATE_NDEF,   /* performing update NDEF procedure     */
+  RW_I93_STATE_FORMAT,        /* performing format procedure          */
+  RW_I93_STATE_SET_READ_ONLY, /* performing set read-only procedure   */
+
+  RW_I93_STATE_PRESENCE_CHECK /* checking presence of tag             */
+};
+
+/* sub state */
+enum {
+  RW_I93_SUBSTATE_WAIT_UID,          /* waiting for response of inventory    */
+  RW_I93_SUBSTATE_WAIT_SYS_INFO,     /* waiting for response of get sys info */
+  RW_I93_SUBSTATE_WAIT_CC,           /* waiting for reading CC               */
+  RW_I93_SUBSTATE_WAIT_CC_EXT,       /* waiting for reading CC second byte   */
+  RW_I93_SUBSTATE_SEARCH_NDEF_TLV,   /* searching NDEF TLV                   */
+  RW_I93_SUBSTATE_CHECK_LOCK_STATUS, /* check if any NDEF TLV is locked      */
+
+  RW_I93_SUBSTATE_RESET_LEN,  /* set length to 0 to update NDEF TLV   */
+  RW_I93_SUBSTATE_WRITE_NDEF, /* writing NDEF and Terminator TLV      */
+  RW_I93_SUBSTATE_UPDATE_LEN, /* set length into NDEF TLV             */
+
+  RW_I93_SUBSTATE_WAIT_RESET_DSFID_AFI, /* reset DSFID and AFI */
+  RW_I93_SUBSTATE_CHECK_READ_ONLY,   /* check if any block is locked         */
+  RW_I93_SUBSTATE_WRITE_CC_NDEF_TLV, /* write CC and empty NDEF/Terminator TLV
+                                      */
+
+  RW_I93_SUBSTATE_WAIT_UPDATE_CC, /* updating CC as read-only             */
+  RW_I93_SUBSTATE_LOCK_NDEF_TLV,  /* lock blocks of NDEF TLV              */
+  RW_I93_SUBSTATE_WAIT_LOCK_CC,   /* lock block of CC                     */
+  RW_I93_SUBSTATE_LOCK_T5T_AREA   /* lock blocks of T5T_Area              */
+};
 
 enum {
   RW_I93_ICODE_SLI,                  /* ICODE SLI, SLIX                  */
@@ -692,6 +760,7 @@
   RW_I93_STM_M24LR64_R,              /* STM M24LR64-R                    */
   RW_I93_STM_M24LR04E_R,             /* STM M24LR04E-R                   */
   RW_I93_STM_M24LR16E_R,             /* STM M24LR16E-R                   */
+  RW_I93_STM_M24LR16D_W,             /* STM M24LR16D-W                   */
   RW_I93_STM_M24LR64E_R,             /* STM M24LR64E-R                   */
   RW_I93_STM_ST25DV04K,              /* STM ST25DV04K                    */
   RW_I93_STM_ST25DVHIK,              /* STM ST25DV 16K OR 64K            */
@@ -726,6 +795,16 @@
 
   uint8_t tlv_detect_state; /* TLV detecting state              */
   uint8_t tlv_type;         /* currently detected type          */
+  uint8_t addr_mode;
+  uint8_t i93_t5t_mode;
+  uint8_t t5t_area_start_block;  /* offset of first block of T5T_Area  */
+  uint16_t t5t_area_last_offset; /* offset of last byte of T5T_Area  */
+
+  /* Greedy collection with NDEF Detection data */
+  uint8_t gre_validity;
+  uint8_t gre_cc_content[8];
+  uint16_t gre_ndef_tlv_pos;
+  uint16_t gre_ndef_tlv_length;
   uint16_t tlv_length;      /* currently detected length        */
 
   uint16_t ndef_tlv_start_offset; /* offset of first byte of NDEF TLV */
@@ -825,6 +904,12 @@
 
 extern tNFC_STATUS rw_i93_select(uint8_t* p_uid);
 extern void rw_i93_process_timeout(TIMER_LIST_ENT* p_tle);
+extern std::string rw_i93_get_state_name(uint8_t state);
+extern std::string rw_i93_get_sub_state_name(uint8_t sub_state);
+extern void rw_t5t_sm_detect_ndef(NFC_HDR*);
+extern void rw_t5t_sm_update_ndef(NFC_HDR*);
+extern void rw_t5t_sm_set_read_only(NFC_HDR*);
+
 extern void rw_t4t_handle_isodep_nak_rsp(uint8_t status, bool is_ntf);
 
 extern tNFC_STATUS rw_mfc_select(uint8_t selres, uint8_t uid[T1T_CMD_UID_LEN]);
diff --git a/src/nfc/include/tags_defs.h b/src/nfc/include/tags_defs.h
index 0e73c36..9572286 100644
--- a/src/nfc/include/tags_defs.h
+++ b/src/nfc/include/tags_defs.h
@@ -366,15 +366,24 @@
 #define T4T_CMD_MIN_HDR_SIZE 4 /* CLA, INS, P1, P2 */
 #define T4T_CMD_MAX_HDR_SIZE 5 /* CLA, INS, P1, P2, Lc */
 
+/* CLA, INS, P1, P2, Data ODO */
+#define T4T_CMD_MIN_EXT_HDR_SIZE 9
+/* CLA, INS, P1, P2, Lc, Data ODO, Le
+ * with Lc and Le coded using Extended Field Coding */
+#define T4T_CMD_MAX_EXT_HDR_SIZE 15
+
+#define T4T_VERSION_3_0 0x30 /* version 3.0 */
 #define T4T_VERSION_2_0 0x20 /* version 2.0 */
 #define T4T_VERSION_1_0 0x10 /* version 1.0 */
-#define T4T_MY_VERSION T4T_VERSION_2_0
+#define T4T_MY_VERSION T4T_VERSION_3_0
 #define T4T_GET_MAJOR_VERSION(x) ((x) >> 4)
 
 #define T4T_CMD_CLASS 0x00
 #define T4T_CMD_INS_SELECT 0xA4
 #define T4T_CMD_INS_READ_BINARY 0xB0
 #define T4T_CMD_INS_UPDATE_BINARY 0xD6
+#define T4T_CMD_INS_READ_BINARY_ODO 0xB1
+#define T4T_CMD_INS_UPDATE_BINARY_ODO 0xD7
 #define T4T_CMD_DES_CLASS 0x90
 #define T4T_CMD_INS_GET_HW_VERSION 0x60
 #define T4T_CMD_CREATE_AID 0xCA
@@ -415,6 +424,8 @@
 
 #define T4T_VERSION_OFFSET_IN_CC 0x02
 #define T4T_FC_TLV_OFFSET_IN_CC 0x07
+/* size of T(1),L(1),V(8) for extended NDEF file control */
+#define T4T_ENDEF_FC_V_FIELD_OFFSET 0x09
 /* Offset of Write access byte from type field in CC */
 #define T4T_FC_WRITE_ACCESS_OFFSET_IN_TLV 0x07
 
@@ -425,8 +436,18 @@
 /* size of V(6) for file control */
 #define T4T_FILE_CONTROL_LENGTH 0x06
 
+#define T4T_ENDEF_FILE_CONTROL_TYPE 0x06 /* Extended NDEF File Control Type */
+/* size of T(1),L(1),V(8) for extended NDEF file control */
+#define T4T_ENDEF_FILE_CONTROL_TLV_SIZE 0x0A
+/* size of V(8) for extended NDEF file control */
+#define T4T_ENDEF_FILE_CONTROL_LENGTH 0x08
+
 /* read access granted without any security */
 #define T4T_FC_READ_ACCESS 0x00
+/* no read access granted at all */
+#define T4T_FC_NO_READ_ACCESS 0xFF
+/* proprietary read access range start */
+#define T4T_FC_READ_ACCESS_PROP_START 0x80
 /* write access granted without any security */
 #define T4T_FC_WRITE_ACCESS 0x00
 /* proprietary write access range start */
@@ -435,6 +456,7 @@
 #define T4T_FC_NO_WRITE_ACCESS 0xFF
 
 #define T4T_FILE_LENGTH_SIZE 0x02
+#define T4T_EFILE_LENGTH_SIZE 0x04
 #define T4T_ADDI_FRAME_RESP 0xAFU
 #define T4T_DES_GET_VERSION_LEN 0x09
 #define T4T_SIZE_IDENTIFIER_2K 0x16U
@@ -456,6 +478,8 @@
 **
 */
 
+#define I93_VERSION_1_x 0x40 /* major mapping version 1.x */
+
 /* A single sub-carrier frequency shall be used by VICC */
 #define I93_FLAG_SUB_CARRIER_SINGLE 0x00
 
@@ -470,10 +494,13 @@
 /* Protocol format is extended. Reserved for future use */
 #define I93_FLAG_PROT_EXT_YES 0x08
 
-/* Request is addressed. UID field is included. It shall be executed only by
- * VICC */
+/* Request is addressed with AMS (Address Mode Selector). UID field is included.
+ * It shall be executed only by VICC */
 #define I93_FLAG_ADDRESS_SET 0x20
 /* whose UID matches the UID specified in the request */
+/* Request is addressed with SMS (Select Mode Selector). UID field is included
+ * or not.  It shall be executed by the unique VICC to be in SELECTED state */
+#define I93_FLAG_SELECT_SET 0x10
 
 /* AFI field is present     */
 #define I93_FLAG_AFI_PRESENT 0x10
@@ -530,6 +557,7 @@
 #define I93_CMD_GET_MULTI_BLK_SEC 0x2C
 /* Get extended multiple block security status */
 #define I93_CMD_EXT_GET_MULTI_BLK_SEC 0x3C
+#define I93_CMD_SET_ADDR_MODE 0x3D /* Set address mode            */
 
 /* Information flags definition */
 /* DSFID is supported and DSFID field is present */
@@ -558,6 +586,11 @@
 /* Max block size in bytes */
 #define I93_MAX_BLOCK_LENGH 32
 
+/* Block lengths */
+#define I93_BLEN_4BYTES 0x04
+#define I93_BLEN_8BYTES 0x08
+#define I93_BLEN_16BYTES 0x10
+#define I93_BLEN_32BYTES 0x20
 /* ICODE Capability Container(CC) definition */
 #define I93_ICODE_CC_MAGIC_NUMER_E1 0xE1 /* magic number in CC[0]  */
 #define I93_ICODE_CC_MAGIC_NUMER_E2 0xE2 /* magic number in CC[0]  */
@@ -578,6 +611,8 @@
 /* More than 2040 bytes are supported in CC[3] */
 #define I93_STM_CC_OVERFLOW_MASK 0x04
 #define I93_ONS_CC_OVERFLOW_MASK 0x04
+/* Special Frame are supported in CC[3] */
+#define I93_ICODE_CC_SPECIAL_FRAME_MASK 0x10
 
 /* ICODE TLV type */
 #define I93_ICODE_TLV_TYPE_NULL 0x00 /* NULL TLV         */
@@ -647,7 +682,10 @@
 /* IC Reference for M24LR16E-R: 01001110(b), blockSize: 4, numberBlocks: 0x200
  */
 #define I93_IC_REF_STM_M24LR16E_R 0x4E
-/* IC Reference for M24LR64E-R: 01011110(b), blockSize: 4, numberBlocks: 0x800
+/* IC Reference for M24LR16D-W: 01001101(b), blockSize: 4, numberBlocks: 0x200
+ */
+#define I93_IC_REF_STM_M24LR16D_W 0x4D
+/* IC Reference for M24LR64D-W: 01011110(b), blockSize: 4, numberBlocks: 0x800
  */
 #define I93_IC_REF_STM_M24LR64E_R 0x5E
 /* IC Reference for ST25DV04K: 00100100(b), blockSize: 4, numberBlocks: 0x80
@@ -660,17 +698,17 @@
 
 /* ONS, product version (IC manufacturer code) */
 /* IC Reference for N36RW02:  00011010(b), blockSize: 4, numberBlocks: 0x40 */
-#define I93_IC_REF_ONS_N36RW02 0x1A
+#define I93_IC_REF_ONS_N36RW02  0x1A
 /* IC Reference for N24RF04:  00101010(b), blockSize: 4, numberBlocks: 0x80 */
-#define I93_IC_REF_ONS_N24RF04 0x2A
+#define I93_IC_REF_ONS_N24RF04  0x2A
 /* IC Reference for N24RF04E: 00101110(b), blockSize: 4, numberBlocks: 0x80 */
 #define I93_IC_REF_ONS_N24RF04E 0x2E
 /* IC Reference for N24RF16:  01001010(b), blockSize: 4, numberBlocks: 0x200 */
-#define I93_IC_REF_ONS_N24RF16 0x4A
+#define I93_IC_REF_ONS_N24RF16  0x4A
 /* IC Reference for N24RF16E: 01001110(b), blockSize: 4, numberBlocks: 0x200 */
 #define I93_IC_REF_ONS_N24RF16E 0x4E
 /* IC Reference for N24RF64:  01101010(b), blockSize: 4, numberBlocks: 0x800 */
-#define I93_IC_REF_ONS_N24RF64 0x6A
+#define I93_IC_REF_ONS_N24RF64  0x6A
 /* IC Reference for N24RF64E: 01101110(b), blockSize: 4, numberBlocks: 0x800 */
 #define I93_IC_REF_ONS_N24RF64E 0x6E
 
@@ -680,4 +718,4 @@
 #define I93_ONS_BLOCKS_PER_SECTOR 32
 #define I93_ONS_MAX_BLOCKS_PER_READ 32
 
-#endif /* TAGS_DEFS_H */
\ No newline at end of file
+#endif /* TAGS_DEFS_H */ 
\ No newline at end of file
diff --git a/src/nfc/nci/nci_hrcv.cc b/src/nfc/nci/nci_hrcv.cc
index 7dfa408..50a6297 100644
--- a/src/nfc/nci/nci_hrcv.cc
+++ b/src/nfc/nci/nci_hrcv.cc
@@ -275,6 +275,10 @@
       break;
 
     case NCI_MSG_RF_FIELD:
+      if (p_msg->len < 4) {
+        android_errorWriteLog(0x534e4554, "176582502");
+        return;
+      }
       nfc_ncif_proc_rf_field_ntf(*pp);
       break;
 
@@ -299,6 +303,10 @@
 #endif
 #endif
     case NCI_MSG_RF_ISO_DEP_NAK_PRESENCE:
+      if (p_msg->len < 4) {
+        android_errorWriteLog(0x534e4554, "176582502");
+        return;
+      }
       nfc_ncif_proc_isodep_nak_presence_check_status(*pp, true);
       break;
     default:
@@ -356,6 +364,8 @@
         nfc_response.mode_set.status = *pp;
       } else {
         nfc_response.mode_set.status = NFC_STATUS_FAILED;
+        android_errorWriteLog(0x534e4554, "176203800");
+        return;
       }
       nfc_response.mode_set.nfcee_id = *p_old++;
       nfc_response.mode_set.mode = *p_old++;
@@ -471,9 +481,7 @@
         DLOG_IF(INFO, nfc_debug_enabled)
             << StringPrintf("tag:0x%x, len:0x%x", p_tlv->tag, p_tlv->len);
         if (p_tlv->len > NFC_MAX_EE_INFO) p_tlv->len = NFC_MAX_EE_INFO;
-        p = pp;
         STREAM_TO_ARRAY(p_tlv->info, pp, p_tlv->len);
-        pp = p += yy;
       }
       break;
     case NCI_MSG_NFCEE_MODE_SET:
diff --git a/src/nfc/nfc/nfc_ncif.cc b/src/nfc/nfc/nfc_ncif.cc
index 93a3509..101b333 100644
--- a/src/nfc/nfc/nfc_ncif.cc
+++ b/src/nfc/nfc/nfc_ncif.cc
@@ -62,40 +62,9 @@
 static struct timeval timer_start;
 static struct timeval timer_end;
 
+#define DEFAULT_CRASH_NFCSNOOP_PATH "/data/misc/nfc/logs/native_crash_logs"
 static const off_t NATIVE_CRASH_FILE_SIZE = (1024 * 1024);
 
-void storeNativeCrashLogs(void) {
-  std::string filename = "/native_crash_logs";
-  std::string filepath = nfc_storage_path + filename;
-  int fileStream;
-  off_t fileSize;
-  DLOG_IF(INFO, nfc_debug_enabled)
-      << StringPrintf("%s: file=%s", __func__, filepath.c_str());
-  // check file size
-  struct stat st;
-  if (stat(filepath.c_str(), &st) == 0) {
-    fileSize = st.st_size;
-  } else {
-    fileSize = 0;
-  }
-
-  if (fileSize >= NATIVE_CRASH_FILE_SIZE) {
-    fileStream =
-        open(filepath.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
-  } else {
-    fileStream =
-        open(filepath.c_str(), O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
-  }
-
-  if (fileStream >= 0) {
-    debug_nfcsnoop_dump(fileStream);
-    close(fileStream);
-  } else {
-    LOG(ERROR) << StringPrintf("%s: fail to create, error = %d", __func__,
-                               errno);
-  }
-}
-
 /*******************************************************************************
 **
 ** Function         nfc_ncif_update_window
@@ -136,7 +105,7 @@
 void nfc_ncif_cmd_timeout(void) {
   LOG(ERROR) << StringPrintf("nfc_ncif_cmd_timeout");
 
-  storeNativeCrashLogs();
+  storeNfcSnoopLogs(DEFAULT_CRASH_NFCSNOOP_PATH, NATIVE_CRASH_FILE_SIZE);
 
   /* report an error */
   nfc_ncif_event_status(NFC_GEN_ERROR_REVT, NFC_STATUS_HW_TIMEOUT);
@@ -146,14 +115,6 @@
   if (nfc_cb.nfc_state == NFC_STATE_CORE_INIT) {
     nfc_enabled(NFC_STATUS_FAILED, nullptr);
   }
-
-  /* XXX maco since this failure is unrecoverable, abort the process */
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-  // Do not abort if for fuzz testing -- this may have some undesired
-  // effect but this is the best we can do.
-#else
-  abort();
-#endif
 }
 
 /*******************************************************************************
@@ -1691,7 +1652,7 @@
 
   status = *p_len > 0 ? *p++ : NCI_STATUS_FAILED;
   if (*p_len > 2 && is_ntf) {
-    LOG(ERROR) << StringPrintf("reset notification!!:0x%x ", status);
+    LOG(WARNING) << StringPrintf("reset notification!!:0x%x ", status);
     /* clean up, if the state is OPEN
      * FW does not report reset ntf right now */
     if (status == NCI2_0_RESET_TRIGGER_TYPE_CORE_RESET_CMD_RECEIVED ||
@@ -1707,7 +1668,7 @@
       status = NCI_STATUS_OK;
     } else {
       /* CORE_RESET_NTF received error case , trigger recovery*/
-      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+      LOG(ERROR) << StringPrintf(
           "CORE_RESET_NTF Received status nfc_state : 0x%x : 0x%x", status,
           nfc_cb.nfc_state);
       nfc_ncif_cmd_timeout();
diff --git a/src/nfc/nfc/nfc_utils.cc b/src/nfc/nfc/nfc_utils.cc
index 855908b..8131e48 100644
--- a/src/nfc/nfc/nfc_utils.cc
+++ b/src/nfc/nfc/nfc_utils.cc
@@ -159,7 +159,11 @@
 
   while ((p_buf = GKI_dequeue(&p_cb->tx_q)) != nullptr) GKI_freebuf(p_buf);
 
-  nfc_cb.conn_id[p_cb->conn_id] = 0;
+  if (p_cb->conn_id <= NFC_MAX_CONN_ID) {
+    nfc_cb.conn_id[p_cb->conn_id] = 0;
+  } else {
+    LOG(ERROR) << StringPrintf("invalid conn_id.");
+  }
   p_cb->p_cback = nullptr;
   p_cb->conn_id = NFC_ILLEGAL_CONN_ID;
 }
diff --git a/src/nfc/tags/rw_i93.cc b/src/nfc/tags/rw_i93.cc
index 1c64ea8..5bf9afc 100644
--- a/src/nfc/tags/rw_i93.cc
+++ b/src/nfc/tags/rw_i93.cc
@@ -39,6 +39,7 @@
 using android::base::StringPrintf;
 
 extern bool nfc_debug_enabled;
+extern unsigned char appl_dta_mode_flag;
 
 /* Response timeout     */
 #define RW_I93_TOUT_RESP 1000
@@ -50,48 +51,7 @@
 #define RW_I93_FORMAT_DATA_LEN 8
 /* max getting lock status if get multi block sec is supported */
 #define RW_I93_GET_MULTI_BLOCK_SEC_SIZE 253
-/*Capability Container CC Size */
-#define RW_I93_CC_SIZE 4
 
-/* main state */
-enum {
-  RW_I93_STATE_NOT_ACTIVATED, /* ISO15693 is not activated            */
-  RW_I93_STATE_IDLE,          /* waiting for upper layer API          */
-  RW_I93_STATE_BUSY,          /* waiting for response from tag        */
-
-  RW_I93_STATE_DETECT_NDEF,   /* performing NDEF detection precedure  */
-  RW_I93_STATE_READ_NDEF,     /* performing read NDEF procedure       */
-  RW_I93_STATE_UPDATE_NDEF,   /* performing update NDEF procedure     */
-  RW_I93_STATE_FORMAT,        /* performing format procedure          */
-  RW_I93_STATE_SET_READ_ONLY, /* performing set read-only procedure   */
-
-  RW_I93_STATE_PRESENCE_CHECK /* checking presence of tag             */
-};
-
-/* sub state */
-enum {
-  RW_I93_SUBSTATE_WAIT_UID,          /* waiting for response of inventory    */
-  RW_I93_SUBSTATE_WAIT_SYS_INFO,     /* waiting for response of get sys info */
-  RW_I93_SUBSTATE_WAIT_CC,           /* waiting for reading CC               */
-  RW_I93_SUBSTATE_SEARCH_NDEF_TLV,   /* searching NDEF TLV                   */
-  RW_I93_SUBSTATE_CHECK_LOCK_STATUS, /* check if any NDEF TLV is locked      */
-
-  RW_I93_SUBSTATE_RESET_LEN,  /* set length to 0 to update NDEF TLV   */
-  RW_I93_SUBSTATE_WRITE_NDEF, /* writing NDEF and Terminator TLV      */
-  RW_I93_SUBSTATE_UPDATE_LEN, /* set length into NDEF TLV             */
-
-  RW_I93_SUBSTATE_WAIT_RESET_DSFID_AFI, /* reset DSFID and AFI */
-  RW_I93_SUBSTATE_CHECK_READ_ONLY,   /* check if any block is locked         */
-  RW_I93_SUBSTATE_WRITE_CC_NDEF_TLV, /* write CC and empty NDEF/Terminator TLV
-                                        */
-
-  RW_I93_SUBSTATE_WAIT_UPDATE_CC, /* updating CC as read-only             */
-  RW_I93_SUBSTATE_LOCK_NDEF_TLV,  /* lock blocks of NDEF TLV              */
-  RW_I93_SUBSTATE_WAIT_LOCK_CC    /* lock block of CC                     */
-};
-
-static std::string rw_i93_get_state_name(uint8_t state);
-static std::string rw_i93_get_sub_state_name(uint8_t sub_state);
 static std::string rw_i93_get_tag_name(uint8_t product_version);
 
 static void rw_i93_data_cback(uint8_t conn_id, tNFC_CONN_EVT event,
@@ -150,6 +110,8 @@
       p_i93->product_version = RW_I93_STM_M24LR04E_R;
     else if (p_i93->ic_reference == I93_IC_REF_STM_M24LR16E_R)
       p_i93->product_version = RW_I93_STM_M24LR16E_R;
+    else if (p_i93->ic_reference == I93_IC_REF_STM_M24LR16D_W)
+      p_i93->product_version = RW_I93_STM_M24LR16D_W;
     else if (p_i93->ic_reference == I93_IC_REF_STM_M24LR64E_R)
       p_i93->product_version = RW_I93_STM_M24LR64E_R;
     else if (p_i93->ic_reference == I93_IC_REF_STM_ST25DVHIK)
@@ -180,32 +142,32 @@
     }
   } else if ((p_uid[1] == I93_UID_IC_MFG_CODE_ONS) &&
              (p_i93->info_flags & I93_INFO_FLAG_IC_REF)) {
-    switch (p_i93->ic_reference) {
-      case I93_IC_REF_ONS_N36RW02:
-        p_i93->product_version = RW_I93_ONS_N36RW02;
+      switch (p_i93->ic_reference) {
+        case I93_IC_REF_ONS_N36RW02:
+          p_i93->product_version = RW_I93_ONS_N36RW02;
+          break;
+        case I93_IC_REF_ONS_N24RF04:
+          p_i93->product_version = RW_I93_ONS_N24RF04;
+          break;
+        case I93_IC_REF_ONS_N24RF04E:
+          p_i93->product_version = RW_I93_ONS_N24RF04E;
+          break;
+        case I93_IC_REF_ONS_N24RF16:
+          p_i93->product_version = RW_I93_ONS_N24RF16;
+          break;
+        case I93_IC_REF_ONS_N24RF16E:
+          p_i93->product_version = RW_I93_ONS_N24RF16E;
+          break;
+        case I93_IC_REF_ONS_N24RF64:
+          p_i93->product_version = RW_I93_ONS_N24RF64;
+          break;
+        case I93_IC_REF_ONS_N24RF64E:
+          p_i93->product_version = RW_I93_ONS_N24RF64E;
+          break;
+        default:
+          p_i93->product_version = RW_I93_UNKNOWN_PRODUCT;
         break;
-      case I93_IC_REF_ONS_N24RF04:
-        p_i93->product_version = RW_I93_ONS_N24RF04;
-        break;
-      case I93_IC_REF_ONS_N24RF04E:
-        p_i93->product_version = RW_I93_ONS_N24RF04E;
-        break;
-      case I93_IC_REF_ONS_N24RF16:
-        p_i93->product_version = RW_I93_ONS_N24RF16;
-        break;
-      case I93_IC_REF_ONS_N24RF16E:
-        p_i93->product_version = RW_I93_ONS_N24RF16E;
-        break;
-      case I93_IC_REF_ONS_N24RF64:
-        p_i93->product_version = RW_I93_ONS_N24RF64;
-        break;
-      case I93_IC_REF_ONS_N24RF64E:
-        p_i93->product_version = RW_I93_ONS_N24RF64E;
-        break;
-      default:
-        p_i93->product_version = RW_I93_UNKNOWN_PRODUCT;
-        break;
-    }
+      }
   } else {
     p_i93->product_version = RW_I93_UNKNOWN_PRODUCT;
   }
@@ -303,8 +265,7 @@
     rw_i93_get_product_version(p_uid);
 
     if (p_i93->uid[0] == I93_UID_FIRST_BYTE) {
-      if ((p_i93->uid[1] == I93_UID_IC_MFG_CODE_STM) ||
-          (p_i93->uid[1] == I93_UID_IC_MFG_CODE_ONS)) {
+      if ((p_i93->uid[1] == I93_UID_IC_MFG_CODE_STM) || (p_i93->uid[1] == I93_UID_IC_MFG_CODE_ONS)){
         /* STM & ONS supports more than 2040 bytes */
         p_i93->intl_flags |= RW_I93_FLAG_EXT_COMMANDS;
       }
@@ -403,12 +364,14 @@
         **  M24LR64-R:  001011xx(b), blockSize: 4, numberBlocks: 0x800
         **  M24LR04E-R: 01011010(b), blockSize: 4, numberBlocks: 0x80
         **  M24LR16E-R: 01001110(b), blockSize: 4, numberBlocks: 0x200
+        **  M24LR16D-W: 01001101(b), blockSize: 4, numberBlocks: 0x200
         **  M24LR64E-R: 01011110(b), blockSize: 4, numberBlocks: 0x800
         */
         if ((p_i93->product_version == RW_I93_STM_M24LR16E_R) ||
+            (p_i93->product_version == RW_I93_STM_M24LR16D_W) ||
             (p_i93->product_version == RW_I93_STM_M24LR64E_R)) {
           /*
-          ** M24LR16E-R or M24LR64E-R returns system information
+          ** M24LR16E-R or M24LR16D-W or M24LR64E-R returns system information
           ** without memory size, if option flag is not set.
           ** LRIS64K and M24LR64-R return error if option flag is not
           ** set.
@@ -448,28 +411,28 @@
         **  N24RF64:  01101010(b), blockSize: 4, numberBlocks: 0x800
         **  N24RF64E: 01101110(b), blockSize: 4, numberBlocks: 0x800
         */
-        p_i93->block_size = 4;
-        switch (p_i93->product_version) {
-          case RW_I93_ONS_N36RW02:
-            p_i93->num_block = 0x40;
-            break;
-          case RW_I93_ONS_N24RF04:
-          case RW_I93_ONS_N24RF04E:
-            p_i93->num_block = 0x80;
-            break;
-          case RW_I93_ONS_N24RF16:
-          case RW_I93_ONS_N24RF16E:
-            p_i93->num_block = 0x200;
-            p_i93->intl_flags |= RW_I93_FLAG_16BIT_NUM_BLOCK;
-            break;
-          case RW_I93_ONS_N24RF64:
-          case RW_I93_ONS_N24RF64E:
-            p_i93->num_block = 0x800;
-            p_i93->intl_flags |= RW_I93_FLAG_16BIT_NUM_BLOCK;
-            break;
-          default:
-            return false;
-        }
+          p_i93->block_size = 4;
+          switch (p_i93->product_version){
+            case RW_I93_ONS_N36RW02:
+                 p_i93->num_block = 0x40;
+                 break;
+            case RW_I93_ONS_N24RF04:
+            case RW_I93_ONS_N24RF04E:
+                 p_i93->num_block = 0x80;
+                 break;
+            case RW_I93_ONS_N24RF16:
+            case RW_I93_ONS_N24RF16E:
+                 p_i93->num_block = 0x200;
+                 p_i93->intl_flags |= RW_I93_FLAG_16BIT_NUM_BLOCK;
+                 break;
+            case RW_I93_ONS_N24RF64:
+            case RW_I93_ONS_N24RF64E:
+                 p_i93->num_block = 0x800;
+                 p_i93->intl_flags |= RW_I93_FLAG_16BIT_NUM_BLOCK;
+                 break;
+            default:
+                 return false;
+          }
       }
     }
   }
@@ -492,8 +455,7 @@
 
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
-  if (((p_i93->uid[1] == I93_UID_IC_MFG_CODE_STM) ||
-       (p_i93->uid[1] == I93_UID_IC_MFG_CODE_ONS)) &&
+  if (((p_i93->uid[1] == I93_UID_IC_MFG_CODE_STM) || (p_i93->uid[1] == I93_UID_IC_MFG_CODE_ONS)) &&
       (p_i93->sent_cmd == I93_CMD_GET_SYS_INFO) &&
       (error_code == I93_ERROR_CODE_OPTION_NOT_SUPPORTED) &&
       (rw_i93_send_cmd_get_sys_info(nullptr, I93_FLAG_PROT_EXT_YES) ==
@@ -635,6 +597,7 @@
 
         memcpy(rw_data.i93_sys_info.uid, p_i93->uid, I93_UID_BYTE_LEN);
 
+        p_i93->i93_t5t_mode = RW_I93_GET_SYS_INFO_MEM_INFO;
         event = RW_I93_SYS_INFO_EVT;
       } else {
         /* retrying with protocol extension flag */
@@ -656,6 +619,7 @@
 
         memcpy(rw_data.i93_sys_info.uid, p_i93->uid, I93_UID_BYTE_LEN);
 
+        p_i93->i93_t5t_mode = RW_I93_GET_SYS_INFO_MEM_INFO;
         event = RW_I93_SYS_INFO_EVT;
       } else {
         /* retrying with protocol extension flag or with extended sys info
@@ -788,7 +752,7 @@
 ** Returns          tNFC_STATUS
 **
 *******************************************************************************/
-tNFC_STATUS rw_i93_send_cmd_stay_quiet(void) {
+tNFC_STATUS rw_i93_send_cmd_stay_quiet(uint8_t* p_uid) {
   NFC_HDR* p_cmd;
   uint8_t* p;
 
@@ -813,7 +777,9 @@
   UINT8_TO_STREAM(p, I93_CMD_STAY_QUIET);
 
   /* Parameters */
-  ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
+  /* Beware the UID is provided with the same order as the transmission
+     one (LSB first) */
+  ARRAY_TO_STREAM(p, p_uid, I93_UID_BYTE_LEN); /* UID */
 
   if (rw_i93_send_to_lower(p_cmd)) {
     rw_cb.tcb.i93.sent_cmd = I93_CMD_STAY_QUIET;
@@ -841,6 +807,7 @@
                                               bool read_security) {
   NFC_HDR* p_cmd;
   uint8_t *p, flags;
+  tRW_I93_CB* p_i93 = &rw_cb.tcb.i93;
 
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
@@ -852,13 +819,22 @@
   }
 
   p_cmd->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
-  p_cmd->len = 11;
+  if (p_i93->addr_mode == RW_I93_MODE_ADDRESSED)
+    p_cmd->len = 11;
+  else
+    p_cmd->len = 3;
   p = (uint8_t*)(p_cmd + 1) + p_cmd->offset;
 
   /* Flags */
-  flags =
-      (I93_FLAG_ADDRESS_SET | RW_I93_FLAG_SUB_CARRIER | RW_I93_FLAG_DATA_RATE);
+  if (p_i93->addr_mode == RW_I93_MODE_ADDRESSED) {
+    flags = (I93_FLAG_ADDRESS_SET | RW_I93_FLAG_SUB_CARRIER |
+             RW_I93_FLAG_DATA_RATE);
+  } else {
+    flags = (RW_I93_FLAG_SUB_CARRIER | RW_I93_FLAG_DATA_RATE);
 
+    if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_SELECTED_STATE)
+      flags |= I93_FLAG_SELECT_SET;
+  }
   if (read_security) flags |= I93_FLAG_OPTION_SET;
 
   if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK)
@@ -874,7 +850,8 @@
   }
 
   /* Parameters */
-  ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
+  if (flags & I93_FLAG_ADDRESS_SET)
+    ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
 
   if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK ||
       rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
@@ -908,6 +885,7 @@
                                                uint8_t* p_data) {
   NFC_HDR* p_cmd;
   uint8_t *p, flags;
+  tRW_I93_CB* p_i93 = &rw_cb.tcb.i93;
 
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
@@ -919,7 +897,10 @@
   }
 
   p_cmd->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
-  p_cmd->len = 11 + rw_cb.tcb.i93.block_size;
+  if (p_i93->addr_mode == RW_I93_MODE_ADDRESSED)
+    p_cmd->len = 11 + rw_cb.tcb.i93.block_size;
+  else
+    p_cmd->len = 3 + rw_cb.tcb.i93.block_size;
   p = (uint8_t*)(p_cmd + 1) + p_cmd->offset;
 
   /* Flags */
@@ -931,8 +912,19 @@
     flags = (I93_FLAG_ADDRESS_SET | I93_FLAG_OPTION_SET |
              RW_I93_FLAG_SUB_CARRIER | RW_I93_FLAG_DATA_RATE);
   } else {
-    flags = (I93_FLAG_ADDRESS_SET | RW_I93_FLAG_SUB_CARRIER |
-             RW_I93_FLAG_DATA_RATE);
+    if (p_i93->addr_mode == RW_I93_MODE_ADDRESSED) {
+      flags = (I93_FLAG_ADDRESS_SET | RW_I93_FLAG_SUB_CARRIER |
+               RW_I93_FLAG_DATA_RATE);
+    } else {
+      flags = (RW_I93_FLAG_SUB_CARRIER | RW_I93_FLAG_DATA_RATE);
+      if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_SELECTED_STATE)
+        flags |= I93_FLAG_SELECT_SET;
+    }
+
+    if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_SPECIAL_FRAME) {
+      /* Option Flag bit must be set */
+      flags |= I93_FLAG_OPTION_SET;
+    }
   }
 
   if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK)
@@ -948,7 +940,8 @@
   }
 
   /* Parameters */
-  ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
+  if (flags & I93_FLAG_ADDRESS_SET)
+    ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
 
   if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK ||
       rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
@@ -978,15 +971,17 @@
 **
 ** Description      Send Lock Block Request to VICC
 **
-**                  STM LRIS64K, M24LR64-R, M24LR04E-R, M24LR16E-R, M24LR64E-R
-**                  do not support.
+**                  STM LRIS64K, M24LR64-R, M24LR04E-R, M24LR16E-R, M24LR64E-R,
+**                  M24LR16D-W do not support.
 **
 ** Returns          tNFC_STATUS
 **
 *******************************************************************************/
-tNFC_STATUS rw_i93_send_cmd_lock_block(uint8_t block_number) {
+tNFC_STATUS rw_i93_send_cmd_lock_block(uint16_t block_number) {
   NFC_HDR* p_cmd;
   uint8_t* p;
+  tRW_I93_CB* p_i93 = &rw_cb.tcb.i93;
+  uint8_t flags;
 
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
@@ -998,7 +993,10 @@
   }
 
   p_cmd->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
-  p_cmd->len = 11;
+  if (p_i93->addr_mode == RW_I93_MODE_ADDRESSED)
+    p_cmd->len = 11;
+  else
+    p_cmd->len = 3;
   p = (uint8_t*)(p_cmd + 1) + p_cmd->offset;
 
   /* Flags */
@@ -1010,8 +1008,21 @@
     UINT8_TO_STREAM(p, (I93_FLAG_ADDRESS_SET | I93_FLAG_OPTION_SET |
                         RW_I93_FLAG_SUB_CARRIER | RW_I93_FLAG_DATA_RATE));
   } else {
-    UINT8_TO_STREAM(p, (I93_FLAG_ADDRESS_SET | RW_I93_FLAG_SUB_CARRIER |
-                        RW_I93_FLAG_DATA_RATE));
+    if (p_i93->addr_mode == RW_I93_MODE_ADDRESSED) {
+      /* Address Mode Selector must be set */
+      flags = I93_FLAG_ADDRESS_SET | RW_I93_FLAG_SUB_CARRIER |
+              RW_I93_FLAG_DATA_RATE;
+    } else {
+      flags = RW_I93_FLAG_SUB_CARRIER | RW_I93_FLAG_DATA_RATE;
+
+      if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_SELECTED_STATE)
+        flags |= I93_FLAG_SELECT_SET;
+    }
+    if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_SPECIAL_FRAME) {
+      /* Option Flag bit must be set */
+      flags |= I93_FLAG_OPTION_SET;
+    }
+    UINT8_TO_STREAM(p, flags);
   }
 
   /* Command Code */
@@ -1022,10 +1033,11 @@
   }
 
   /* Parameters */
-  ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
+  if (p_i93->addr_mode == RW_I93_MODE_ADDRESSED)
+    ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
 
   if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
-    UINT8_TO_STREAM(p, block_number); /* Block number */
+    UINT16_TO_STREAM(p, block_number); /* Block number */
     p_cmd->len++;
   } else {
     UINT8_TO_STREAM(p, block_number); /* Block number */
@@ -1055,6 +1067,7 @@
                                               uint16_t number_blocks) {
   NFC_HDR* p_cmd;
   uint8_t *p, flags;
+  tRW_I93_CB* p_i93 = &rw_cb.tcb.i93;
 
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
@@ -1066,12 +1079,22 @@
   }
 
   p_cmd->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
-  p_cmd->len = 12;
+  if (p_i93->addr_mode == RW_I93_MODE_ADDRESSED)
+    p_cmd->len = 12;
+  else
+    p_cmd->len = 4;
   p = (uint8_t*)(p_cmd + 1) + p_cmd->offset;
 
   /* Flags */
-  flags =
-      (I93_FLAG_ADDRESS_SET | RW_I93_FLAG_SUB_CARRIER | RW_I93_FLAG_DATA_RATE);
+  if (p_i93->addr_mode == RW_I93_MODE_ADDRESSED) {
+    flags = (I93_FLAG_ADDRESS_SET | RW_I93_FLAG_SUB_CARRIER |
+             RW_I93_FLAG_DATA_RATE);
+  } else {
+    flags = (RW_I93_FLAG_SUB_CARRIER | RW_I93_FLAG_DATA_RATE);
+
+    if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_SELECTED_STATE)
+      flags |= I93_FLAG_SELECT_SET;
+  }
 
   if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK) {
     flags |= I93_FLAG_PROT_EXT_YES;
@@ -1087,7 +1110,8 @@
   }
 
   /* Parameters */
-  ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
+  if (flags & I93_FLAG_ADDRESS_SET)
+    ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
 
   if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK ||
       rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
@@ -1224,7 +1248,9 @@
   UINT8_TO_STREAM(p, I93_CMD_SELECT);
 
   /* Parameters */
-  ARRAY8_TO_STREAM(p, p_uid); /* UID */
+  /* Beware the UID is provided with the same order as the transmission
+     one (LSB first) */
+  ARRAY_TO_STREAM(p, p_uid, I93_UID_BYTE_LEN); /* UID */
 
   if (rw_i93_send_to_lower(p_cmd)) {
     rw_cb.tcb.i93.sent_cmd = I93_CMD_SELECT;
@@ -1650,11 +1676,21 @@
   if (p_i93->intl_flags & RW_I93_FLAG_READ_MULTI_BLOCK) {
     num_block = RW_I93_READ_MULTI_BLOCK_SIZE / p_i93->block_size;
 
-    if (num_block + first_block > p_i93->num_block)
-      num_block = p_i93->num_block - first_block;
+    // first_block is an offset related to the beginning of the T5T_Area for T5T
+    // tags but physical memory for ISO15693 tags
+    if (p_i93->i93_t5t_mode == RW_I93_GET_SYS_INFO_MEM_INFO) {
+      if (num_block + first_block > p_i93->num_block)
+        num_block = p_i93->num_block - first_block;
+    } else {
+      if (num_block + first_block >
+          p_i93->num_block + p_i93->t5t_area_start_block)
+        num_block =
+            p_i93->num_block - first_block + p_i93->t5t_area_start_block;
+    }
 
     if (p_i93->uid[1] == I93_UID_IC_MFG_CODE_STM) {
-      /* LRIS64K, M24LR64-R, M24LR04E-R, M24LR16E-R, M24LR64E-R requires
+      /* LRIS64K, M24LR64-R, M24LR04E-R, M24LR16E-R, M24LR16D-W, M24LR64E-R
+      ** require
       ** - The max number of blocks is 32 and they are all located in the
       **   same sector.
       ** - The sector is 32 blocks of 4 bytes.
@@ -1663,6 +1699,7 @@
           (p_i93->product_version == RW_I93_STM_M24LR64_R) ||
           (p_i93->product_version == RW_I93_STM_M24LR04E_R) ||
           (p_i93->product_version == RW_I93_STM_M24LR16E_R) ||
+          (p_i93->product_version == RW_I93_STM_M24LR16D_W) ||
           (p_i93->product_version == RW_I93_STM_M24LR64E_R)) {
         if (num_block > I93_STM_MAX_BLOCKS_PER_READ)
           num_block = I93_STM_MAX_BLOCKS_PER_READ;
@@ -1683,9 +1720,9 @@
       */
       if ((p_i93->product_version == RW_I93_ONS_N36RW02) ||
           (p_i93->product_version == RW_I93_ONS_N24RF04) ||
-          (p_i93->product_version == RW_I93_ONS_N24RF04E) ||
+          (p_i93->product_version == RW_I93_ONS_N24RF04E)||
           (p_i93->product_version == RW_I93_ONS_N24RF16) ||
-          (p_i93->product_version == RW_I93_ONS_N24RF16E) ||
+          (p_i93->product_version == RW_I93_ONS_N24RF16E)||
           (p_i93->product_version == RW_I93_ONS_N24RF64) ||
           (p_i93->product_version == RW_I93_ONS_N24RF64E)) {
         if (num_block > I93_ONS_MAX_BLOCKS_PER_READ)
@@ -1699,6 +1736,11 @@
       }
     }
 
+    if (num_block == 0) {
+      /* only one remaining block to read */
+      return rw_i93_send_cmd_read_single_block(first_block, false);
+    }
+
     return rw_i93_send_cmd_read_multi_blocks(first_block, num_block);
   } else {
     return rw_i93_send_cmd_read_single_block(first_block, false);
@@ -1763,7 +1805,7 @@
   tNFC_STATUS status = NFC_STATUS_FAILED;
 
   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-      "sub_state:%s (0x%x)",
+      "%s - sub_state:%s (0x%x)", __func__,
       rw_i93_get_sub_state_name(p_i93->sub_state).c_str(), p_i93->sub_state);
 
   if (length == 0) {
@@ -1781,7 +1823,7 @@
       p_i93->intl_flags |= RW_I93_FLAG_16BIT_NUM_BLOCK;
     } else {
       DLOG_IF(INFO, nfc_debug_enabled)
-          << StringPrintf("Got error flags (0x%02x)", flags);
+          << StringPrintf("%s - Got error flags (0x%02x)", __func__, flags);
       rw_i93_handle_error(NFC_STATUS_FAILED);
     }
     return;
@@ -1802,7 +1844,7 @@
       if (u8 != I93_DFS_UNSUPPORTED) {
         /* if Data Storage Format is unknown */
         DLOG_IF(INFO, nfc_debug_enabled)
-            << StringPrintf("Got unknown DSFID (0x%02x)", u8);
+            << StringPrintf("%s - Got unknown DSFID (0x%02x)", __func__, u8);
         rw_i93_handle_error(NFC_STATUS_FAILED);
       } else {
         /* get system information to get memory size */
@@ -1827,7 +1869,7 @@
 
       if ((p_i93->block_size == 0) || (p_i93->num_block == 0)) {
         DLOG_IF(INFO, nfc_debug_enabled)
-            << StringPrintf("Unable to get tag memory size");
+            << StringPrintf("%s - Unable to get tag memory size", __func__);
         rw_i93_handle_error(status);
       } else {
         /* read CC in the first block */
@@ -1869,14 +1911,23 @@
       **       : Bit 2:More than 2040 bytes are supported [STM, ONS]
       */
 
-      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-          "cc: 0x%02X 0x%02X 0x%02X 0x%02X", cc[0], cc[1], cc[2], cc[3]);
       DLOG_IF(INFO, nfc_debug_enabled)
-          << StringPrintf("Total blocks:0x%04X, Block size:0x%02X",
-                          p_i93->num_block, p_i93->block_size);
+          << StringPrintf("%s - cc[0-3]: 0x%02X 0x%02X 0x%02X 0x%02X", __func__,
+                          cc[0], cc[1], cc[2], cc[3]);
+
+      DLOG_IF(INFO, nfc_debug_enabled)
+          << StringPrintf("%s - Total blocks:0x%04X, Block size:0x%02X",
+                          __func__, p_i93->num_block, p_i93->block_size);
 
       if ((cc[0] == I93_ICODE_CC_MAGIC_NUMER_E1) ||
           (cc[0] == I93_ICODE_CC_MAGIC_NUMER_E2)) {
+        if ((cc[1] & 0xC0) > I93_VERSION_1_x) {
+          DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+              "%s - Major mapping version above 1 %d.x", __func__, cc[1] >> 6);
+          /* major mapping version above 1 not supported */
+          rw_i93_handle_error(NFC_STATUS_FAILED);
+          break;
+        }
         if ((cc[1] & I93_ICODE_CC_READ_ACCESS_MASK) ==
             I93_ICODE_CC_READ_ACCESS_GRANTED) {
           if ((cc[1] & I93_ICODE_CC_WRITE_ACCESS_MASK) !=
@@ -1885,9 +1936,13 @@
             p_i93->intl_flags |= RW_I93_FLAG_READ_ONLY;
           }
           if (cc[3] & I93_ICODE_CC_MBREAD_MASK) {
-            /* tag supports read multi blocks command */
+            /* tag supports read multiple blocks command */
             p_i93->intl_flags |= RW_I93_FLAG_READ_MULTI_BLOCK;
           }
+          if (cc[3] & I93_ICODE_CC_SPECIAL_FRAME_MASK) {
+            /* tag supports Special Frame for Write-Alike commands */
+            p_i93->intl_flags |= RW_I93_FLAG_SPECIAL_FRAME;
+          }
           if (cc[0] == I93_ICODE_CC_MAGIC_NUMER_E2) {
             p_i93->intl_flags |= RW_I93_FLAG_EXT_COMMANDS;
           }
@@ -1934,8 +1989,8 @@
             p_i93->tlv_type = I93_ICODE_TLV_TYPE_TERM;
             break;
           } else {
-            DLOG_IF(INFO, nfc_debug_enabled)
-                << StringPrintf("Invalid type: 0x%02x", *(p + xx));
+            DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+                "%s - Invalid type: 0x%02x", __func__, *(p + xx));
             rw_i93_handle_error(NFC_STATUS_FAILED);
             return;
           }
@@ -2134,7 +2189,7 @@
       p_i93->sent_cmd = 0;
 
       DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-          "NDEF cur_size(%d),max_size (%d), flags (0x%x)",
+          "%s - NDEF cur_size(%d),max_size (%d), flags (0x%x)", __func__,
           rw_data.ndef.cur_size, rw_data.ndef.max_size, rw_data.ndef.flags);
 
       (*(rw_cb.p_cback))(RW_I93_NDEF_DETECT_EVT, &rw_data);
@@ -2174,7 +2229,7 @@
 
   if (flags & I93_FLAG_ERROR_DETECTED) {
     DLOG_IF(INFO, nfc_debug_enabled)
-        << StringPrintf("Got error flags (0x%02x)", flags);
+        << StringPrintf("%s - Got error flags (0x%02x)", __func__, flags);
     rw_i93_handle_error(NFC_STATUS_FAILED);
     return;
   }
@@ -2221,14 +2276,14 @@
     p_i93->sent_cmd = 0;
 
     DLOG_IF(INFO, nfc_debug_enabled)
-        << StringPrintf("NDEF read complete read (%d)/total (%d)", p_resp->len,
-                        p_i93->ndef_length);
+        << StringPrintf("%s - NDEF read complete read (%d)/total (%d)",
+                        __func__, p_resp->len, p_i93->ndef_length);
 
     (*(rw_cb.p_cback))(RW_I93_NDEF_READ_CPLT_EVT, &rw_data);
   } else {
     DLOG_IF(INFO, nfc_debug_enabled)
-        << StringPrintf("NDEF read segment read (%d)/total (%d)", p_resp->len,
-                        p_i93->ndef_length);
+        << StringPrintf("%s - NDEF read segment read (%d)/total (%d)", __func__,
+                        p_resp->len, p_i93->ndef_length);
 
     if (p_resp->len > 0) {
       (*(rw_cb.p_cback))(RW_I93_NDEF_READ_EVT, &rw_data);
@@ -2264,7 +2319,7 @@
   tRW_DATA rw_data;
 
   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-      "sub_state:%s (0x%x)",
+      "%s - sub_state:%s (0x%x)", __func__,
       rw_i93_get_sub_state_name(p_i93->sub_state).c_str(), p_i93->sub_state);
 
   if (length == 0 || p_i93->block_size > I93_MAX_BLOCK_LENGH) {
@@ -2285,7 +2340,7 @@
       /* ignore error */
     } else {
       DLOG_IF(INFO, nfc_debug_enabled)
-          << StringPrintf("Got error flags (0x%02x)", flags);
+          << StringPrintf("%s - Got error flags (0x%02x)", __func__, flags);
       rw_i93_handle_error(NFC_STATUS_FAILED);
       return;
     }
@@ -2503,8 +2558,9 @@
         }
       } else {
         DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-            "NDEF update complete, %d bytes, (%d-%d)", p_i93->ndef_length,
-            p_i93->ndef_tlv_start_offset, p_i93->ndef_tlv_last_offset);
+            "%s - NDEF update complete, %d bytes, (%d-%d)", __func__,
+            p_i93->ndef_length, p_i93->ndef_tlv_start_offset,
+            p_i93->ndef_tlv_last_offset);
 
         p_i93->state = RW_I93_STATE_IDLE;
         p_i93->sent_cmd = 0;
@@ -3021,8 +3077,8 @@
   tRW_DATA rw_data;
   tRW_EVENT event;
 
-  DLOG_IF(INFO, nfc_debug_enabled)
-      << StringPrintf("status:0x%02X, state:0x%X", status, p_i93->state);
+  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+      "%s - status:0x%02X, state:0x%X", __func__, status, p_i93->state);
 
   nfc_stop_quick_timer(&p_i93->timer);
 
@@ -3109,14 +3165,16 @@
 void rw_i93_process_timeout(TIMER_LIST_ENT* p_tle) {
   NFC_HDR* p_buf;
 
-  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("event=%d", p_tle->event);
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("%s - event=%d", __func__, p_tle->event);
 
   if (p_tle->event == NFC_TTYPE_RW_I93_RESPONSE) {
     if ((rw_cb.tcb.i93.retry_count < RW_MAX_RETRIES) &&
         (rw_cb.tcb.i93.p_retry_cmd) &&
         (rw_cb.tcb.i93.sent_cmd != I93_CMD_STAY_QUIET)) {
       rw_cb.tcb.i93.retry_count++;
-      LOG(ERROR) << StringPrintf("retry_count = %d", rw_cb.tcb.i93.retry_count);
+      LOG(ERROR) << StringPrintf("%s - retry_count = %d", __func__,
+                                 rw_cb.tcb.i93.retry_count);
 
       p_buf = rw_cb.tcb.i93.p_retry_cmd;
       rw_cb.tcb.i93.p_retry_cmd = nullptr;
@@ -3134,7 +3192,7 @@
     }
     rw_i93_handle_error(NFC_STATUS_TIMEOUT);
   } else {
-    LOG(ERROR) << StringPrintf("unknown event=%d", p_tle->event);
+    LOG(ERROR) << StringPrintf("%s - unknown event=%d", __func__, p_tle->event);
   }
 }
 
@@ -3155,7 +3213,8 @@
 
   uint8_t begin_state = p_i93->state;
 
-  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("event = 0x%X", event);
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("%s - event = 0x%X", __func__, event);
 
   if ((event == NFC_DEACTIVATE_CEVT) || (event == NFC_ERROR_CEVT) ||
       ((event == NFC_DATA_CEVT) && (p_data->status != NFC_STATUS_OK))) {
@@ -3165,7 +3224,8 @@
       if ((p_i93->retry_count < RW_MAX_RETRIES) && (p_i93->p_retry_cmd)) {
         p_i93->retry_count++;
 
-        LOG(ERROR) << StringPrintf("retry_count = %d", p_i93->retry_count);
+        LOG(ERROR) << StringPrintf("%s - retry_count = %d", __func__,
+                                   p_i93->retry_count);
 
         p_resp = p_i93->p_retry_cmd;
         p_i93->p_retry_cmd = nullptr;
@@ -3219,8 +3279,8 @@
   }
 
   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-      "RW I93 state: <%s (%d)>", rw_i93_get_state_name(p_i93->state).c_str(),
-      p_i93->state);
+      "%s - RW I93 state: <%s (%d)>", __func__,
+      rw_i93_get_state_name(p_i93->state).c_str(), p_i93->state);
 
   switch (p_i93->state) {
     case RW_I93_STATE_IDLE:
@@ -3243,7 +3303,15 @@
       break;
 
     case RW_I93_STATE_DETECT_NDEF:
-      rw_i93_sm_detect_ndef(p_resp);
+      if (p_i93->i93_t5t_mode == RW_I93_GET_SYS_INFO_MEM_INFO) {
+        DLOG_IF(INFO, nfc_debug_enabled)
+            << StringPrintf("%s - rw_i93_sm_detect_ndef()", __func__);
+        rw_i93_sm_detect_ndef(p_resp);
+      } else {
+        DLOG_IF(INFO, nfc_debug_enabled)
+            << StringPrintf("%s - rw_t5t_sm_detect_ndef()", __func__);
+        rw_t5t_sm_detect_ndef(p_resp);
+      }
       GKI_freebuf(p_resp);
       break;
 
@@ -3253,7 +3321,15 @@
       break;
 
     case RW_I93_STATE_UPDATE_NDEF:
-      rw_i93_sm_update_ndef(p_resp);
+      if (p_i93->i93_t5t_mode == RW_I93_GET_SYS_INFO_MEM_INFO) {
+        DLOG_IF(INFO, nfc_debug_enabled)
+            << StringPrintf("%s - rw_i93_sm_update_ndef()", __func__);
+        rw_i93_sm_update_ndef(p_resp);
+      } else {
+        DLOG_IF(INFO, nfc_debug_enabled)
+            << StringPrintf("%s - rw_t5t_sm_update_ndef()", __func__);
+        rw_t5t_sm_update_ndef(p_resp);
+      }
       GKI_freebuf(p_resp);
       break;
 
@@ -3263,7 +3339,15 @@
       break;
 
     case RW_I93_STATE_SET_READ_ONLY:
-      rw_i93_sm_set_read_only(p_resp);
+      if (p_i93->i93_t5t_mode == RW_I93_GET_SYS_INFO_MEM_INFO) {
+        DLOG_IF(INFO, nfc_debug_enabled)
+            << StringPrintf("%s - rw_i93_sm_set_read_only()", __func__);
+        rw_i93_sm_set_read_only(p_resp);
+      } else {
+        DLOG_IF(INFO, nfc_debug_enabled)
+            << StringPrintf("%s - rw_t5t_sm_set_read_only()", __func__);
+        rw_t5t_sm_set_read_only(p_resp);
+      }
       GKI_freebuf(p_resp);
       break;
 
@@ -3278,14 +3362,15 @@
       break;
 
     default:
-      LOG(ERROR) << StringPrintf("invalid state=%d", p_i93->state);
+      LOG(ERROR) << StringPrintf("%s - invalid state=%d", __func__,
+                                 p_i93->state);
       GKI_freebuf(p_resp);
       break;
   }
 
   if (begin_state != p_i93->state) {
     DLOG_IF(INFO, nfc_debug_enabled)
-        << StringPrintf("RW I93 state changed:<%s> -> <%s>",
+        << StringPrintf("%s - RW I93 state changed:<%s> -> <%s>", __func__,
                         rw_i93_get_state_name(begin_state).c_str(),
                         rw_i93_get_state_name(p_i93->state).c_str());
   }
@@ -3369,20 +3454,23 @@
 **                  NFC_STATUS_FAILED if other error
 **
 *******************************************************************************/
-tNFC_STATUS RW_I93StayQuiet(void) {
-  tNFC_STATUS status;
+tNFC_STATUS RW_I93StayQuiet(uint8_t* p_uid) {
+  tNFC_STATUS status = NFC_STATUS_FAILED;
 
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
   if (rw_cb.tcb.i93.state != RW_I93_STATE_IDLE) {
-    LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
-                               rw_cb.tcb.i93.state);
+    LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+                               __func__, rw_cb.tcb.i93.state);
     return NFC_STATUS_BUSY;
   }
 
-  status = rw_i93_send_cmd_stay_quiet();
-  if (status == NFC_STATUS_OK) {
-    rw_cb.tcb.i93.state = RW_I93_STATE_BUSY;
+  if (p_uid) {
+    status = rw_i93_send_cmd_stay_quiet(p_uid);
+    if (status == NFC_STATUS_OK) {
+      rw_cb.tcb.i93.state = RW_I93_STATE_BUSY;
+      rw_cb.tcb.i93.addr_mode = RW_I93_MODE_ADDRESSED;
+    }
   }
 
   return status;
@@ -3406,7 +3494,7 @@
   tNFC_STATUS status;
 
   DLOG_IF(INFO, nfc_debug_enabled)
-      << StringPrintf("block_number:0x%02X", block_number);
+      << StringPrintf("%s - block_number:0x%02X", __func__, block_number);
 
   if (rw_cb.tcb.i93.state != RW_I93_STATE_IDLE) {
     LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
@@ -3594,8 +3682,8 @@
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
   if (rw_cb.tcb.i93.state != RW_I93_STATE_IDLE) {
-    LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
-                               rw_cb.tcb.i93.state);
+    LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+                               __func__, rw_cb.tcb.i93.state);
     return NFC_STATUS_BUSY;
   }
 
@@ -3603,9 +3691,11 @@
     status = rw_i93_send_cmd_select(p_uid);
     if (status == NFC_STATUS_OK) {
       rw_cb.tcb.i93.state = RW_I93_STATE_BUSY;
+      rw_cb.tcb.i93.addr_mode = RW_I93_MODE_NON_ADDRESSED;
+      rw_cb.tcb.i93.intl_flags |= RW_I93_FLAG_SELECTED_STATE;
     }
   } else {
-    LOG(ERROR) << StringPrintf("UID shall be provided");
+    LOG(ERROR) << StringPrintf("%s - UID shall be provided", __func__);
     status = NFC_STATUS_FAILED;
   }
 
@@ -3632,8 +3722,8 @@
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
   if (rw_cb.tcb.i93.state != RW_I93_STATE_IDLE) {
-    LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
-                               rw_cb.tcb.i93.state);
+    LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+                               __func__, rw_cb.tcb.i93.state);
     return NFC_STATUS_BUSY;
   }
 
@@ -3797,8 +3887,8 @@
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
   if (rw_cb.tcb.i93.state != RW_I93_STATE_IDLE) {
-    LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
-                               rw_cb.tcb.i93.state);
+    LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+                               __func__, rw_cb.tcb.i93.state);
     return NFC_STATUS_BUSY;
   }
 
@@ -3872,16 +3962,18 @@
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
   if (rw_cb.tcb.i93.state != RW_I93_STATE_IDLE) {
-    LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
-                               rw_cb.tcb.i93.state);
+    LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+                               __func__, rw_cb.tcb.i93.state);
     return NFC_STATUS_FAILED;
   }
 
   if (rw_cb.tcb.i93.uid[0] != I93_UID_FIRST_BYTE) {
     status = rw_i93_send_cmd_inventory(nullptr, false, 0x00);
     sub_state = RW_I93_SUBSTATE_WAIT_UID;
-  } else if ((rw_cb.tcb.i93.num_block == 0) ||
-             (rw_cb.tcb.i93.block_size == 0)) {
+
+  } else if (((rw_cb.tcb.i93.num_block == 0) ||
+              (rw_cb.tcb.i93.block_size == 0)) &&
+             (!appl_dta_mode_flag)) {
     status =
         rw_i93_send_cmd_get_sys_info(rw_cb.tcb.i93.uid, I93_FLAG_PROT_EXT_NO);
     sub_state = RW_I93_SUBSTATE_WAIT_SYS_INFO;
@@ -3926,8 +4018,8 @@
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
   if (rw_cb.tcb.i93.state != RW_I93_STATE_IDLE) {
-    LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
-                               rw_cb.tcb.i93.state);
+    LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+                               __func__, rw_cb.tcb.i93.state);
     return NFC_STATUS_FAILED;
   }
 
@@ -3942,7 +4034,7 @@
       return NFC_STATUS_FAILED;
     }
   } else {
-    LOG(ERROR) << StringPrintf("No NDEF detected");
+    LOG(ERROR) << StringPrintf("%s - No NDEF detected", __func__);
     return NFC_STATUS_FAILED;
   }
 
@@ -3969,24 +4061,25 @@
 tNFC_STATUS RW_I93UpdateNDef(uint16_t length, uint8_t* p_data) {
   uint16_t block_number;
 
-  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("length:%d", length);
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("%s - length:%d", __func__, length);
 
   if (rw_cb.tcb.i93.state != RW_I93_STATE_IDLE) {
-    LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
-                               rw_cb.tcb.i93.state);
+    LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+                               __func__, rw_cb.tcb.i93.state);
     return NFC_STATUS_FAILED;
   }
 
   if (rw_cb.tcb.i93.tlv_type == I93_ICODE_TLV_TYPE_NDEF) {
     if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_READ_ONLY) {
-      LOG(ERROR) << StringPrintf("NDEF is read-only");
+      LOG(ERROR) << StringPrintf("%s - NDEF is read-only", __func__);
       return NFC_STATUS_FAILED;
     }
     if (rw_cb.tcb.i93.max_ndef_length < length) {
       LOG(ERROR) << StringPrintf(
-          "data (%d bytes) is more than max NDEF length "
+          "%s - data (%d bytes) is more than max NDEF length "
           "(%d)",
-          length, rw_cb.tcb.i93.max_ndef_length);
+          __func__, length, rw_cb.tcb.i93.max_ndef_length);
       return NFC_STATUS_FAILED;
     }
 
@@ -4007,7 +4100,7 @@
       return NFC_STATUS_FAILED;
     }
   } else {
-    LOG(ERROR) << StringPrintf("No NDEF detected");
+    LOG(ERROR) << StringPrintf("%s - No NDEF detected", __func__);
     return NFC_STATUS_FAILED;
   }
 
@@ -4077,17 +4170,20 @@
 **
 *******************************************************************************/
 tNFC_STATUS RW_I93SetTagReadOnly(void) {
+  uint8_t cc_blk0[4];
+
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
   if (rw_cb.tcb.i93.state != RW_I93_STATE_IDLE) {
-    LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
-                               rw_cb.tcb.i93.state);
+    LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+                               __func__, rw_cb.tcb.i93.state);
     return NFC_STATUS_FAILED;
   }
 
-  if (rw_cb.tcb.i93.tlv_type == I93_ICODE_TLV_TYPE_NDEF) {
+  if ((rw_cb.tcb.i93.tlv_type == I93_ICODE_TLV_TYPE_NDEF) &&
+      (rw_cb.tcb.i93.i93_t5t_mode != RW_T5T_CC_READ_MEM_INFO)) {
     if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_READ_ONLY) {
-      LOG(ERROR) << StringPrintf("NDEF is already read-only");
+      LOG(ERROR) << StringPrintf("%s - NDEF is already read-only", __func__);
       return NFC_STATUS_FAILED;
     }
 
@@ -4099,7 +4195,28 @@
       return NFC_STATUS_FAILED;
     }
   } else {
-    LOG(ERROR) << StringPrintf("No NDEF detected");
+    if (rw_cb.tcb.i93.i93_t5t_mode == RW_T5T_CC_READ_MEM_INFO) {
+      memcpy(cc_blk0, rw_cb.tcb.i93.gre_cc_content, 4);
+
+      /* mark CC as read-only */
+      *(cc_blk0 + 1) |= I93_ICODE_CC_READ_ONLY;
+
+      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+          "%s - Set CC1 to RO - cc[0]=0x%02x, cc[1]=0x%02x, "
+          "cc[2]=0x%02x, cc[3]=0x%02x",
+          __func__, *cc_blk0, *(cc_blk0 + 1), *(cc_blk0 + 2), *(cc_blk0 + 3));
+
+      if (rw_i93_send_cmd_write_single_block(0, cc_blk0) == NFC_STATUS_OK) {
+        rw_cb.tcb.i93.state = RW_I93_STATE_SET_READ_ONLY;
+        rw_cb.tcb.i93.sub_state = RW_I93_SUBSTATE_WAIT_UPDATE_CC;
+      } else {
+        rw_i93_handle_error(NFC_STATUS_FAILED);
+        return NFC_STATUS_FAILED;
+      }
+
+      return NFC_STATUS_OK;
+    }
+    LOG(ERROR) << StringPrintf("%s - No NDEF detected", __func__);
     return NFC_STATUS_FAILED;
   }
 
@@ -4131,14 +4248,20 @@
     return NFC_STATUS_FAILED;
   } else if (rw_cb.tcb.i93.state == RW_I93_STATE_NOT_ACTIVATED) {
     evt_data.status = NFC_STATUS_FAILED;
-    (*rw_cb.p_cback)(RW_T4T_PRESENCE_CHECK_EVT, &evt_data);
+    (*rw_cb.p_cback)(RW_I93_PRESENCE_CHECK_EVT, &evt_data);
 
     return NFC_STATUS_OK;
   } else if (rw_cb.tcb.i93.state != RW_I93_STATE_IDLE) {
     return NFC_STATUS_BUSY;
   } else {
-    /* The support of AFI by the VICC is optional, so do not include AFI */
-    status = rw_i93_send_cmd_inventory(rw_cb.tcb.i93.uid, false, 0x00);
+    if (rw_cb.tcb.i93.i93_t5t_mode == RW_I93_GET_SYS_INFO_MEM_INFO) {
+      /* The support of AFI by the VICC is optional, so do not include AFI */
+      status = rw_i93_send_cmd_inventory(rw_cb.tcb.i93.uid, false, 0x00);
+    } else {
+      /* Extended command not expected for presence check */
+      rw_cb.tcb.i93.intl_flags &= ~RW_I93_FLAG_EXT_COMMANDS;
+      status = rw_i93_send_cmd_read_single_block(0, false);
+    }
 
     if (status == NFC_STATUS_OK) {
       /* do not retry during presence check */
@@ -4150,6 +4273,38 @@
   return (status);
 }
 
+/*****************************************************************************
+**
+** Function         RW_I93SetAddressingMode
+**
+** Description      Set if the tag must be addressed with UID or not.
+**
+**                  The addressing mode (addressed or non-addressed) must be
+**                  done at the module initialization prior to the Tag
+**                  activation.
+**
+** Returns          NFC_STATUS_OK, if mode is stored
+**                  NFC_STATUS_FAILED: other error
+**
+*****************************************************************************/
+tNFC_STATUS RW_I93SetAddressingMode(bool mode) {
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("%s - I93 state:%d", __func__, rw_cb.tcb.i93.state);
+
+  if (rw_cb.tcb.i93.state == RW_I93_STATE_IDLE) {
+    DLOG_IF(INFO, nfc_debug_enabled)
+        << StringPrintf("%s - mode:%d", __func__, mode);
+    if (mode) {
+      rw_cb.tcb.i93.addr_mode = RW_I93_MODE_ADDRESSED;
+    } else {
+      rw_cb.tcb.i93.addr_mode = RW_I93_MODE_NON_ADDRESSED;
+    }
+    return NFC_STATUS_OK;
+  } else {
+    return NFC_STATUS_FAILED;
+  }
+}
+
 /*******************************************************************************
 **
 ** Function         rw_i93_get_state_name
@@ -4161,7 +4316,7 @@
 ** Returns          pointer to the name
 **
 *******************************************************************************/
-static std::string rw_i93_get_state_name(uint8_t state) {
+std::string rw_i93_get_state_name(uint8_t state) {
   switch (state) {
     case RW_I93_STATE_NOT_ACTIVATED:
       return "NOT_ACTIVATED";
@@ -4197,7 +4352,7 @@
 ** Returns          pointer to the name
 **
 *******************************************************************************/
-static std::string rw_i93_get_sub_state_name(uint8_t sub_state) {
+std::string rw_i93_get_sub_state_name(uint8_t sub_state) {
   switch (sub_state) {
     case RW_I93_SUBSTATE_WAIT_UID:
       return "WAIT_UID";
@@ -4205,6 +4360,8 @@
       return "WAIT_SYS_INFO";
     case RW_I93_SUBSTATE_WAIT_CC:
       return "WAIT_CC";
+    case RW_I93_SUBSTATE_WAIT_CC_EXT:
+      return "WAIT_CC_EXT";
     case RW_I93_SUBSTATE_SEARCH_NDEF_TLV:
       return "SEARCH_NDEF_TLV";
     case RW_I93_SUBSTATE_CHECK_LOCK_STATUS:
@@ -4227,6 +4384,8 @@
       return "LOCK_NDEF_TLV";
     case RW_I93_SUBSTATE_WAIT_LOCK_CC:
       return "WAIT_LOCK_CC";
+    case RW_I93_SUBSTATE_LOCK_T5T_AREA:
+      return "LOCK_T5T_AREA";
     default:
       return "???? UNKNOWN SUBSTATE";
   }
@@ -4273,6 +4432,8 @@
       return "M24LR04E";
     case RW_I93_STM_M24LR16E_R:
       return "M24LR16E";
+    case RW_I93_STM_M24LR16D_W:
+      return "M24LR16D-W";
     case RW_I93_STM_M24LR64E_R:
       return "M24LR64E";
     case RW_I93_STM_ST25DV04K:
diff --git a/src/nfc/tags/rw_mfc.cc b/src/nfc/tags/rw_mfc.cc
index aaa5908..649f333 100644
--- a/src/nfc/tags/rw_mfc.cc
+++ b/src/nfc/tags/rw_mfc.cc
@@ -634,6 +634,11 @@
   NFC_HDR* mfc_data = nullptr;
   tRW_DATA rw_data;
 
+  if (!p_data) {
+    LOG(ERROR) << __func__ << "Invalid p_data";
+    return;
+  }
+
   DLOG_IF(INFO, nfc_debug_enabled)
       << StringPrintf("%s conn_id=%i, evt=0x%x", __func__, conn_id, event);
   /* Only handle static conn_id */
@@ -676,10 +681,7 @@
           evt_data.status = (tNFC_STATUS)(*(uint8_t*)p_data);
         } else if (p_data) {
           evt_data.status = p_data->status;
-        } else {
-          evt_data.status = NFC_STATUS_FAILED;
         }
-
         evt_data.p_data = NULL;
         (*rw_cb.p_cback)(RW_MFC_INTF_ERROR_EVT, (tRW_DATA*)&evt_data);
         break;
@@ -691,6 +693,11 @@
       break;
   }
 
+  if ((p_mfc->state != RW_MFC_STATE_IDLE) && (mfc_data == NULL)) {
+    LOG(ERROR) << StringPrintf("%s NULL pointer", __func__);
+    return;
+  }
+
   switch (p_mfc->state) {
     case RW_MFC_STATE_IDLE:
       /* Unexpected R-APDU, it should be raw frame response */
@@ -1012,7 +1019,7 @@
       if (tlv_found) {
         p_mfc->ndef_status = MFC_NDEF_DETECTED;
         p_mfc->ndef_first_block = p_mfc->last_block_accessed.block;
-        rw_mfc_ntf_tlv_detect_complete(tlv_found);
+        rw_mfc_ntf_tlv_detect_complete(NFC_STATUS_OK);
       }
       break;
 
diff --git a/src/nfc/tags/rw_t1t.cc b/src/nfc/tags/rw_t1t.cc
index c4e5e31..97c504a 100644
--- a/src/nfc/tags/rw_t1t.cc
+++ b/src/nfc/tags/rw_t1t.cc
@@ -628,7 +628,7 @@
   rw_event = rw_t1t_info_to_event(p_cmd_rsp_info);
   if (p_t1t->state != RW_T1T_STATE_NOT_ACTIVATED) rw_t1t_handle_op_complete();
 
-  if (rw_event == RW_T2T_NDEF_DETECT_EVT) {
+  if (rw_event == RW_T1T_NDEF_DETECT_EVT) {
     tRW_DETECT_NDEF_DATA ndef_data;
     ndef_data.status = NFC_STATUS_TIMEOUT;
     ndef_data.protocol = NFC_PROTOCOL_T1T;
diff --git a/src/nfc/tags/rw_t2t_ndef.cc b/src/nfc/tags/rw_t2t_ndef.cc
index ad98228..1297815 100644
--- a/src/nfc/tags/rw_t2t_ndef.cc
+++ b/src/nfc/tags/rw_t2t_ndef.cc
@@ -404,7 +404,7 @@
   bool found = false;
   tRW_EVENT event;
   uint8_t index;
-  uint8_t count = 0;
+  uint16_t count = 0;
   uint8_t xx;
   tNFC_STATUS status;
   tT2T_CMD_RSP_INFO* p_cmd_rsp_info =
@@ -615,20 +615,16 @@
                 p_t2t->lock_tlv[p_t2t->num_lock_tlvs].offset =
                     (p_t2t->tlv_value[0] >> 4) & 0x0F;
                 p_t2t->lock_tlv[p_t2t->num_lock_tlvs].offset *=
-                    (uint8_t)tags_pow(2, p_t2t->tlv_value[2] & 0x0F);
+                    (uint16_t)tags_pow(2, p_t2t->tlv_value[2] & 0x0F);
                 p_t2t->lock_tlv[p_t2t->num_lock_tlvs].offset +=
                     p_t2t->tlv_value[0] & 0x0F;
                 p_t2t->lock_tlv[p_t2t->num_lock_tlvs].bytes_locked_per_bit =
-                    (uint8_t)tags_pow(2, ((p_t2t->tlv_value[2] & 0xF0) >> 4));
-                /* Note: 0 value in DLA_NbrLockBits means 256 */
+                    (uint16_t)tags_pow(2, ((p_t2t->tlv_value[2] & 0xF0) >> 4));
+                /* Note: 0 value in DLA_NbrLockBits means 256 bits */
                 count = p_t2t->tlv_value[1];
                 /* Set it to max value that can be stored in lockbytes */
                 if (count == 0) {
-#if RW_T2T_MAX_LOCK_BYTES > 0x1F
-                  count = UCHAR_MAX;
-#else
                   count = RW_T2T_MAX_LOCK_BYTES * TAG_BITS_PER_BYTE;
-#endif
                 }
                 p_t2t->lock_tlv[p_t2t->num_lock_tlvs].num_bits = count;
                 count = count / TAG_BITS_PER_BYTE +
@@ -681,11 +677,17 @@
                   p_t2t->mem_tlv[p_t2t->num_mem_tlvs].offset =
                       (p_t2t->tlv_value[0] >> 4) & 0x0F;
                   p_t2t->mem_tlv[p_t2t->num_mem_tlvs].offset *=
-                      (uint8_t)tags_pow(2, p_t2t->tlv_value[2] & 0x0F);
+                      (uint16_t)tags_pow(2, p_t2t->tlv_value[2] & 0x0F);
+
                   p_t2t->mem_tlv[p_t2t->num_mem_tlvs].offset +=
                       p_t2t->tlv_value[0] & 0x0F;
-                  p_t2t->mem_tlv[p_t2t->num_mem_tlvs].num_bytes =
-                      p_t2t->tlv_value[1];
+                  count = p_t2t->tlv_value[1];
+                  /* Note: 0 value in Rsvd_Area_Size means 256 bytes */
+                  if (count == 0) {
+                    count = RW_T2T_MAX_LOCK_BYTES * TAG_BITS_PER_BYTE;
+                  }
+                  p_t2t->mem_tlv[p_t2t->num_mem_tlvs].num_bytes = count;
+
                   p_t2t->num_mem_tlvs++;
                   rw_t2t_update_attributes();
                   p_t2t->substate = RW_T2T_SUBSTATE_WAIT_TLV_DETECT;
@@ -855,6 +857,7 @@
   tRW_T2T_CB* p_t2t = &rw_cb.tcb.t2t;
   const tT2T_INIT_TAG* p_ret;
   uint8_t bytes_locked_per_lock_bit = T2T_DEFAULT_LOCK_BLPB;
+  uint16_t t2t_dyn_lock_area_size;
 
   if ((p_t2t->num_lock_tlvs == 0) &&
       (p_t2t->tag_hdr[T2T_CC2_TMS_BYTE] > T2T_CC2_TMS_STATIC)) {
@@ -864,10 +867,12 @@
     p_ret = t2t_tag_init_data(p_t2t->tag_hdr[0], false, 0);
     if (p_ret != nullptr) bytes_locked_per_lock_bit = p_ret->default_lock_blpb;
 
-    num_dynamic_lock_bits =
+    t2t_dyn_lock_area_size =
         ((p_t2t->tag_hdr[T2T_CC2_TMS_BYTE] * T2T_TMS_TAG_FACTOR) -
-         (T2T_STATIC_SIZE - T2T_HEADER_SIZE)) /
-        bytes_locked_per_lock_bit;
+         (T2T_STATIC_SIZE - T2T_HEADER_SIZE));
+    num_dynamic_lock_bits = t2t_dyn_lock_area_size / bytes_locked_per_lock_bit;
+    num_dynamic_lock_bits += (t2t_dyn_lock_area_size % 8 == 0) ? 0 : 1;
+
     num_dynamic_lock_bytes = num_dynamic_lock_bits / 8;
     num_dynamic_lock_bytes += (num_dynamic_lock_bits % 8 == 0) ? 0 : 1;
     if (num_dynamic_lock_bytes > RW_T2T_MAX_LOCK_BYTES) {
@@ -921,8 +926,7 @@
   uint16_t total_ndef_bytes;
   uint16_t last_ndef_byte_offset;
   uint16_t terminator_tlv_byte_index;
-  tNFC_STATUS status;
-  uint16_t block;
+  tNFC_STATUS status = NFC_STATUS_OK;
 
   total_ndef_bytes = header_len + p_t2t->new_ndef_msg_len;
   num_ndef_bytes = 0;
@@ -937,60 +941,23 @@
   }
   p_t2t->ndef_last_block_num =
       (uint16_t)((last_ndef_byte_offset - 1) / T2T_BLOCK_SIZE);
-  block = p_t2t->ndef_last_block_num;
 
-  p_t2t->substate = RW_T2T_SUBSTATE_WAIT_READ_NDEF_LAST_BLOCK;
-  /* Read NDEF last block before updating */
-  status = rw_t2t_read(block);
-  if (status == NFC_STATUS_OK) {
-    if ((p_t2t->new_ndef_msg_len + 1) <= p_t2t->max_ndef_msg_len) {
-      /* Locate Terminator TLV Block */
-      total_ndef_bytes++;
-      terminator_tlv_byte_index = last_ndef_byte_offset;
+  if ((p_t2t->new_ndef_msg_len + 1) <= p_t2t->max_ndef_msg_len) {
+    /* Locate Terminator TLV Block */
+    terminator_tlv_byte_index = last_ndef_byte_offset;
 
-      while (num_ndef_bytes < total_ndef_bytes) {
-        if (rw_t2t_is_lock_res_byte((uint16_t)terminator_tlv_byte_index) ==
-            false)
-          num_ndef_bytes++;
-
-        terminator_tlv_byte_index++;
-      }
-
-      p_t2t->terminator_byte_index = terminator_tlv_byte_index - 1;
-    } else {
-      /* No space for Terminator TLV */
+    if (rw_t2t_is_lock_res_byte((uint16_t)terminator_tlv_byte_index) == false)
+      p_t2t->terminator_byte_index = terminator_tlv_byte_index;
+    else
       p_t2t->terminator_byte_index = 0x00;
-    }
+  } else {
+    /* No space for Terminator TLV */
+    p_t2t->terminator_byte_index = 0x00;
   }
+
   return status;
 }
 
-/*******************************************************************************
-**
-** Function         rw_t2t_read_terminator_tlv_block
-**
-** Description      This function will read the block where terminator tlv will
-**                  be added later
-**
-** Returns          NCI_STATUS_OK, if read was started. Otherwise, error status.
-**
-*******************************************************************************/
-tNFC_STATUS rw_t2t_read_terminator_tlv_block(void) {
-  tRW_T2T_CB* p_t2t = &rw_cb.tcb.t2t;
-  tNFC_STATUS status;
-  uint16_t block;
-
-  /* Send read command to read base block (Block % 4==0) where this block is
-   * also read as part of 16 bytes */
-  block = p_t2t->terminator_byte_index / T2T_BLOCK_SIZE;
-  block -= block % T2T_READ_BLOCKS;
-
-  p_t2t->substate = RW_T2T_SUBSTATE_WAIT_READ_TERM_TLV_BLOCK;
-  /* Read the block where Terminator TLV may be added later during NDEF Write
-   * operation */
-  status = rw_t2t_read(block);
-  return status;
-}
 
 /*******************************************************************************
 **
@@ -1410,25 +1377,27 @@
 *******************************************************************************/
 static uint16_t rw_t2t_get_ndef_max_size(void) {
   uint16_t offset;
-  uint8_t xx;
   tRW_T2T_CB* p_t2t = &rw_cb.tcb.t2t;
-  uint16_t tag_size = (p_t2t->tag_hdr[T2T_CC2_TMS_BYTE] * T2T_TMS_TAG_FACTOR) +
-                      (T2T_FIRST_DATA_BLOCK * T2T_BLOCK_LEN) +
-                      p_t2t->num_lockbytes;
+  uint16_t tag_size = (p_t2t->tag_hdr[T2T_CC2_TMS_BYTE] * T2T_TMS_TAG_FACTOR);
 
-  for (xx = 0; xx < p_t2t->num_mem_tlvs; xx++)
-    tag_size += p_t2t->mem_tlv[xx].num_bytes;
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("%s - T2T_Area size: %d", __func__, tag_size);
+
+  /* Add header to compute max T2T NDEF data offset */
+  tag_size += (T2T_FIRST_DATA_BLOCK * T2T_BLOCK_LEN);
 
   offset = p_t2t->ndef_msg_offset;
   p_t2t->max_ndef_msg_len = 0;
 
-  if ((tag_size < T2T_STATIC_SIZE) ||
-      (tag_size > (T2T_SECTOR_SIZE * T2T_MAX_SECTOR)) ||
+  if ((tag_size <= T2T_STATIC_SIZE) ||
       ((p_t2t->tag_hdr[T2T_CC0_NMN_BYTE] != T2T_CC0_NMN) &&
        (p_t2t->tag_hdr[T2T_CC0_NMN_BYTE] != 0))) {
     /* Tag not formated, assume static tag */
     p_t2t->max_ndef_msg_len = T2T_STATIC_SIZE - T2T_HEADER_SIZE -
                               T2T_TLV_TYPE_LEN - T2T_SHORT_NDEF_LEN_FIELD_LEN;
+    DLOG_IF(INFO, nfc_debug_enabled)
+        << StringPrintf("%s - Tag assumed static : max_ndef_msg_len=%d",
+                        __func__, p_t2t->max_ndef_msg_len);
     return p_t2t->max_ndef_msg_len;
   }
 
@@ -1440,15 +1409,19 @@
     }
     offset++;
   }
+
   /* NDEF Length field length changes based on NDEF size */
   if ((p_t2t->max_ndef_msg_len >= T2T_LONG_NDEF_LEN_FIELD_BYTE0) &&
       ((p_t2t->ndef_msg_offset - p_t2t->ndef_header_offset) ==
        T2T_SHORT_NDEF_LEN_FIELD_LEN)) {
     p_t2t->max_ndef_msg_len -=
-        (p_t2t->max_ndef_msg_len == T2T_LONG_NDEF_LEN_FIELD_BYTE0)
-            ? 1
-            : (T2T_LONG_NDEF_LEN_FIELD_LEN - T2T_SHORT_NDEF_LEN_FIELD_LEN);
+        (T2T_LONG_NDEF_LEN_FIELD_LEN - T2T_SHORT_NDEF_LEN_FIELD_LEN);
   }
+
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("%s - Max NDEF data storage: max_ndef_msg_len=%d",
+                      __func__, p_t2t->max_ndef_msg_len);
+
   return p_t2t->max_ndef_msg_len;
 }
 
@@ -1466,14 +1439,49 @@
   tRW_T2T_CB* p_t2t = &rw_cb.tcb.t2t;
   tNFC_STATUS status;
   uint16_t block;
+  uint8_t term_byte_idx;
 
   /* Add Terminator TLV after NDEF Message */
-  p_t2t->terminator_tlv_block[p_t2t->terminator_byte_index % T2T_BLOCK_LEN] =
-      TAG_TERMINATOR_TLV;
-  p_t2t->substate = RW_T2T_SUBSTATE_WAIT_WRITE_TERM_TLV_CMPLT;
-
   block = p_t2t->terminator_byte_index / T2T_BLOCK_LEN;
-  status = rw_t2t_write(block, p_t2t->terminator_tlv_block);
+
+  if (block == p_t2t->ndef_last_block_num) {
+    DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+        "%s - Terminator TLV in same block %d as last NDEF"
+        " bytes",
+        __func__, block);
+
+    /* If Terminator TLV will reside on the NDEF Final block */
+    memcpy(p_t2t->terminator_tlv_block, p_t2t->ndef_last_block, T2T_BLOCK_LEN);
+
+    term_byte_idx = p_t2t->terminator_byte_index % T2T_BLOCK_LEN;
+
+    p_t2t->terminator_tlv_block[term_byte_idx] = TAG_TERMINATOR_TLV;
+    if (term_byte_idx < (T2T_BLOCK_LEN - 1)) {
+      for (int i = term_byte_idx + 1; i < T2T_BLOCK_LEN; i++)
+        p_t2t->terminator_tlv_block[i] = 0x00;
+    }
+
+    p_t2t->substate = RW_T2T_SUBSTATE_WAIT_WRITE_TERM_TLV_CMPLT;
+    status = rw_t2t_write(block, p_t2t->terminator_tlv_block);
+
+  } else if (p_t2t->terminator_byte_index != 0) {
+    /* If there is space for Terminator TLV and if it will reside outside
+     * NDEF Final block */
+    DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+        "%s - Terminator TLV in block %d following the last NDEF block",
+        __func__, block);
+    p_t2t->terminator_tlv_block[0] = TAG_TERMINATOR_TLV;
+    p_t2t->terminator_tlv_block[1] = 0x00;
+    p_t2t->terminator_tlv_block[2] = 0x00;
+    p_t2t->terminator_tlv_block[3] = 0x00;
+
+    p_t2t->substate = RW_T2T_SUBSTATE_WAIT_WRITE_TERM_TLV_CMPLT;
+    status = rw_t2t_write(block, p_t2t->terminator_tlv_block);
+
+  } else {
+    /* If there is no space for Terminator TLV, conclude NDEF procedure */
+    status = NFC_STATUS_CONTINUE;
+  }
 
   return status;
 }
@@ -1554,6 +1562,7 @@
   bool done = false;
   uint16_t block;
   uint8_t offset;
+  tNFC_STATUS status = NFC_STATUS_FAILED;
 
   switch (p_t2t->substate) {
     case RW_T2T_SUBSTATE_WAIT_READ_NDEF_FIRST_BLOCK:
@@ -1562,40 +1571,8 @@
       memcpy(p_t2t->ndef_first_block, p_data, T2T_BLOCK_LEN);
       /* Read ndef final block */
       if (rw_t2t_read_ndef_last_block() != NFC_STATUS_OK) failed = true;
-      break;
+      memset(p_t2t->terminator_tlv_block, 0, T2T_BLOCK_LEN);
 
-    case RW_T2T_SUBSTATE_WAIT_READ_NDEF_LAST_BLOCK:
-
-      offset = (uint8_t)(p_t2t->ndef_last_block_num - p_t2t->block_read) *
-               T2T_BLOCK_SIZE;
-      /* Backup the read NDEF final block */
-      memcpy(p_t2t->ndef_last_block, &p_data[offset], T2T_BLOCK_LEN);
-      if ((p_t2t->terminator_byte_index / T2T_BLOCK_SIZE) ==
-          p_t2t->ndef_last_block_num) {
-        /* If Terminator TLV will reside on the NDEF Final block */
-        memcpy(p_t2t->terminator_tlv_block, p_t2t->ndef_last_block,
-               T2T_BLOCK_LEN);
-        if (rw_t2t_write_ndef_first_block(0x0000, false) != NFC_STATUS_OK)
-          failed = true;
-      } else if (p_t2t->terminator_byte_index != 0) {
-        /* If there is space for Terminator TLV and if it will reside outside
-         * NDEF Final block */
-        if (rw_t2t_read_terminator_tlv_block() != NFC_STATUS_OK) failed = true;
-      } else {
-        if (rw_t2t_write_ndef_first_block(0x0000, false) != NFC_STATUS_OK)
-          failed = true;
-      }
-      break;
-
-    case RW_T2T_SUBSTATE_WAIT_READ_TERM_TLV_BLOCK:
-
-      offset = (uint8_t)(((p_t2t->terminator_byte_index / T2T_BLOCK_SIZE) -
-                          p_t2t->block_read) *
-                         T2T_BLOCK_SIZE);
-      /* Backup the read Terminator TLV block */
-      memcpy(p_t2t->terminator_tlv_block, &p_data[offset], T2T_BLOCK_LEN);
-
-      /* Write the first block for new NDEF Message */
       if (rw_t2t_write_ndef_first_block(0x0000, false) != NFC_STATUS_OK)
         failed = true;
       break;
@@ -1673,7 +1650,11 @@
       break;
 
     case RW_T2T_SUBSTATE_WAIT_WRITE_NDEF_LEN_BLOCK:
-      if (rw_t2t_add_terminator_tlv() != NFC_STATUS_OK) failed = true;
+      status = rw_t2t_add_terminator_tlv();
+      if (status == NFC_STATUS_CONTINUE)
+        done = true;
+      else if (status != NFC_STATUS_OK)
+        failed = true;
       break;
 
     case RW_T2T_SUBSTATE_WAIT_WRITE_TERM_TLV_CMPLT:
@@ -1756,7 +1737,10 @@
 
       /* First soft lock the tag */
       rw_t2t_soft_lock_tag();
-
+      if (p_t2t->b_hard_lock) {
+        /* Tag configuration not complete */
+        status = NFC_STATUS_OK;
+      }
       break;
 
     case RW_T2T_SUBSTATE_WAIT_SET_CC_RO:
@@ -1768,11 +1752,21 @@
         status = NFC_STATUS_OK;
         b_notify = true;
         break;
+      } else {
+        /* Tag configuration not complete */
+        status = NFC_STATUS_OK;
+        /* Copy the internal bytes */
+        memcpy(write_block,
+               &p_t2t->tag_hdr[T2T_STATIC_LOCK0 - T2T_INTERNAL_BYTES_LEN],
+               T2T_INTERNAL_BYTES_LEN);
+        /* Set all Static lock bits */
+        write_block[T2T_STATIC_LOCK0 % T2T_BLOCK_SIZE] = 0xFF;
+        write_block[T2T_STATIC_LOCK1 % T2T_BLOCK_SIZE] = 0xFF;
+        p_t2t->substate = RW_T2T_SUBSTATE_WAIT_SET_DYN_LOCK_BITS;
+        status = rw_t2t_write((T2T_STATIC_LOCK0 / T2T_BLOCK_SIZE), write_block);
       }
-      FALLTHROUGH_INTENDED;
+      break;
 
-    /* Coverity: [FALSE-POSITIVE error] intended fall through */
-    /* Missing break statement between cases in switch statement */
     case RW_T2T_SUBSTATE_WAIT_SET_DYN_LOCK_BITS:
 
       num_locks = 0;
@@ -1787,8 +1781,21 @@
         if (!b_pending &&
             p_t2t->lockbyte[num_locks].lock_status == RW_T2T_LOCK_NOT_UPDATED) {
           /* One or more dynamic lock bits are not set */
-          b_pending = true;
-          read_lock = num_locks;
+          if (num_locks == 0) {
+            offset = p_t2t->lock_tlv[p_t2t->lockbyte[0].tlv_index].offset +
+                     p_t2t->lockbyte[0].byte_index;
+            if (offset % T2T_BLOCK_SIZE) {
+              /* For backward compatibility in case the DynLock_Area is not
+               * aligned to a block boundary, first read the block not to
+               * overwrite possible NDEF or Reserved data
+               */
+              b_pending = true;
+              read_lock = num_locks;
+            } else {
+              /* Write zero in internal byte */
+              memset(write_block, 0, T2T_BLOCK_SIZE);
+            }
+          }
         }
         num_locks++;
       }
@@ -1796,35 +1803,24 @@
       if (b_pending) {
         /* Read the block where dynamic lock bits are present to avoid writing
          * to NDEF bytes in the same block */
-        offset = p_t2t->lock_tlv[p_t2t->lockbyte[read_lock].tlv_index].offset +
-                 p_t2t->lockbyte[read_lock].byte_index;
         p_t2t->substate = RW_T2T_SUBSTATE_WAIT_READ_DYN_LOCK_BYTE_BLOCK;
         status = rw_t2t_read((uint16_t)(offset / T2T_BLOCK_LEN));
       } else {
-        /* Now set Static lock bits as no more dynamic lock bits to set */
-
-        /* Copy the internal bytes */
-        memcpy(write_block,
-               &p_t2t->tag_hdr[T2T_STATIC_LOCK0 - T2T_INTERNAL_BYTES_LEN],
-               T2T_INTERNAL_BYTES_LEN);
-        /* Set all Static lock bits */
-        write_block[T2T_STATIC_LOCK0 % T2T_BLOCK_SIZE] = 0xFF;
-        write_block[T2T_STATIC_LOCK1 % T2T_BLOCK_SIZE] = 0xFF;
-        p_t2t->substate = RW_T2T_SUBSTATE_WAIT_SET_ST_LOCK_BITS;
-        status = rw_t2t_write((T2T_STATIC_LOCK0 / T2T_BLOCK_SIZE), write_block);
+        /* Now set the dynamic lock bits present in the block read now */
+        status = rw_t2t_set_dynamic_lock_bits(write_block);
+        if (status == NFC_STATUS_CONTINUE) {
+          /* Tag configuration complete */
+          status = NFC_STATUS_OK;
+          b_notify = true;
+        }
       }
+
       break;
 
     case RW_T2T_SUBSTATE_WAIT_READ_DYN_LOCK_BYTE_BLOCK:
       /* Now set the dynamic lock bits present in the block read now */
       status = rw_t2t_set_dynamic_lock_bits(p_data);
       break;
-
-    case RW_T2T_SUBSTATE_WAIT_SET_ST_LOCK_BITS:
-      /* Tag configuration complete */
-      status = NFC_STATUS_OK;
-      b_notify = true;
-      break;
   }
 
   if (status != NFC_STATUS_OK || b_notify) {
@@ -1970,6 +1966,9 @@
   uint16_t lower_offset;
   uint16_t upper_offset;
   uint16_t offset;
+  uint16_t offset_in_seg;
+  uint16_t block_boundary;
+  uint8_t num_internal_bytes;
   uint8_t num_bytes;
 
   /* Prepare attr for the current segment */
@@ -1989,18 +1988,53 @@
     if (offset >= lower_offset && offset < upper_offset) {
       /* Calculate offset in the current segment as p_t2t->attr is prepared for
        * one segment only */
-      offset %= RW_T2T_SEGMENT_BYTES;
+      offset_in_seg = offset % RW_T2T_SEGMENT_BYTES;
       /* Every bit in p_t2t->attr indicates one byte of the tag is either a
        * lock/reserved byte or not
        * So, each array element in p_t2t->attr covers two blocks in the tag as
        * T2 block size is 4 and array element size is 8
        * Set the corresponding bit in attr to indicate - reserved byte */
-      p_t2t->attr[offset / TAG_BITS_PER_BYTE] |=
-          rw_t2t_mask_bits[offset % TAG_BITS_PER_BYTE];
+      p_t2t->attr[offset_in_seg / TAG_BITS_PER_BYTE] |=
+          rw_t2t_mask_bits[offset_in_seg % TAG_BITS_PER_BYTE];
     }
     count++;
   }
 
+  block_boundary = (offset + 1) % T2T_BLOCK_LEN;
+  if (block_boundary) {
+    /* End of DynLock_Area is not aligned to a block boundary. The bytes that
+     * are not part of the area within the same block are Internal Bytes (see
+     * [T2T-TS] section 4.7).
+     * According to REQ 4.4.1.5, either write them to 00h or to their existing
+     * values. However according to the NDEF Write procedure, REQ 7.5.5.5,
+     * symbol 5, the Reader SHALL not write to the DynLock_Area and the
+     * Rsvd_Area(s), as indicated by the Lock Control TLV or the Memory
+     * Control TLVs, if any.
+     * Choice is made to consider the bytes within the same block as the
+     * DynLock_Area last bytes as lock bytes i.e. they will not be written
+     * and therefore previously read (steps anyhow not expected by NFC Forum
+     * Test Specifications).
+     */
+    num_internal_bytes = T2T_BLOCK_LEN - block_boundary;
+    count = 1;
+
+    while (count <= num_internal_bytes) {
+      offset++;
+      if (offset >= lower_offset && offset < upper_offset) {
+        /* Calculate offset in the current segment as p_t2t->attr is prepared
+         * for one segment only */
+        offset_in_seg = offset % RW_T2T_SEGMENT_BYTES;
+        /* Every bit in p_t2t->attr indicates one byte of the tag is either a
+         * lock/reserved/internal byte or not
+         * So, each array element in p_t2t->attr covers two blocks in the tag as
+         * T2 block size is 4 and array element size is 8
+         * Set the corresponding bit in attr to indicate - reserved byte */
+        p_t2t->attr[offset_in_seg / TAG_BITS_PER_BYTE] |=
+            rw_t2t_mask_bits[offset_in_seg % TAG_BITS_PER_BYTE];
+      }
+      count++;
+    }
+  }
   /* Search reserved bytes identified by all memory tlvs present in the tag */
   count = 0;
   while (count < p_t2t->num_mem_tlvs) {
@@ -2055,7 +2089,7 @@
   uint16_t lower_offset, upper_offset;
   uint8_t num_dynamic_locks = 0;
   uint8_t bit_count = 0;
-  uint8_t bytes_locked_per_bit;
+  uint16_t bytes_locked_per_bit;
   uint8_t num_bits;
   tRW_T2T_CB* p_t2t = &rw_cb.tcb.t2t;
   bool b_all_bits_are_locks = true;
@@ -2189,10 +2223,10 @@
   uint8_t num_static_lock_bytes = 0;
   uint8_t num_dyn_lock_bytes = 0;
   uint8_t bits_covered = 0;
-  uint8_t bytes_covered = 0;
+  uint16_t bytes_covered = 0;
   uint8_t block_count = 0;
   bool b_all_bits_are_locks = true;
-  uint8_t bytes_locked_per_lock_bit;
+  uint16_t bytes_locked_per_lock_bit;
   uint8_t start_lock_byte;
   uint8_t start_lock_bit;
   uint8_t end_lock_byte;
@@ -2464,6 +2498,9 @@
         status = NFC_STATUS_FAILED;
 
       break;
+
+    } else {
+      status = NFC_STATUS_CONTINUE;
     }
     num_locks++;
   }
diff --git a/src/nfc/tags/rw_t3t.cc b/src/nfc/tags/rw_t3t.cc
index 58b84fd..0e91498 100644
--- a/src/nfc/tags/rw_t3t.cc
+++ b/src/nfc/tags/rw_t3t.cc
@@ -1729,6 +1729,7 @@
   /* Validate response for NDEF poll */
   if ((nci_status == NCI_STATUS_OK) && (num_responses > 0)) {
     /* Tag responded for NDEF poll */
+    p_cb->cur_active_sc = T3T_SYSTEM_CODE_NDEF;
 
     /* Read NDEF attribute block */
     p_cmd_buf = rw_t3t_get_cmd_buf();
@@ -1851,6 +1852,7 @@
   /* Validate response for poll response */
   if ((nci_status == NCI_STATUS_OK) && (num_responses > 0)) {
     /* Tag responded for Felica-Lite poll */
+    p_cb->cur_active_sc = T3T_SYSTEM_CODE_FELICA_LITE;
     /* Get MemoryControl block */
     DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
         "Felica-Lite tag detected...getting Memory Control block.");
@@ -2298,7 +2300,7 @@
                                (p_data->data.status == NFC_STATUS_CONTINUE))) {
         rw_t3t_data_cback(conn_id, &(p_data->data));
         break;
-      } else if (p_data->data.p_data != nullptr) {
+      } else if (p_data && p_data->data.p_data != nullptr) {
         /* Free the response buffer in case of error response */
         GKI_freebuf((NFC_HDR*)(p_data->data.p_data));
         p_data->data.p_data = nullptr;
@@ -2588,6 +2590,14 @@
   } else if (p_cb->ndef_attrib.ln == 0) {
     LOG(ERROR) << StringPrintf("Type 3 tag contains empty NDEF message");
     return (NFC_STATUS_FAILED);
+  } else if (p_cb->ndef_attrib.writef ==
+             T3T_MSG_NDEF_WRITEF_ON) /* Tag's NDEF memory write in progress? */
+  {
+    LOG(ERROR) << StringPrintf(
+        "%s - WriteFlag ON: NDEF data may be inconsistent, "
+        "conclude NDEF Read procedure",
+        __func__);
+    return (NFC_STATUS_FAILED);
   }
 
   /* Check number of blocks needed for this update */
@@ -2792,7 +2802,7 @@
     }
   } else {
     /* IDLE state: send POLL command */
-    retval = (tNFC_STATUS)nci_snd_t3t_polling(0xFFFF, T3T_POLL_RC_SC, 0);
+    retval = (tNFC_STATUS)nci_snd_t3t_polling(0xFFFF, T3T_POLL_RC_SC, 0x03);
     if (retval == NCI_STATUS_OK) {
       p_rw_cb->tcb.t3t.flags |= RW_T3T_FL_W4_PRESENCE_CHECK_POLL_RSP;
       p_rw_cb->tcb.t3t.rw_state = RW_T3T_STATE_COMMAND_PENDING;
@@ -2918,7 +2928,12 @@
                                p_cb->rw_state);
     return (NFC_STATUS_FAILED);
   } else {
-    retval = (tNFC_STATUS)nci_snd_t3t_polling(0xFFFF, T3T_POLL_RC_SC, 0);
+    /* Until the card answers properly to SC=12FCh, by default, consider
+       the card as a Felica card not NDEF compatible, answering to SC=0x88B4
+       possibly */
+    p_cb->cur_active_sc = T3T_SYSTEM_CODE_FELICA_LITE;
+
+    retval = (tNFC_STATUS)nci_snd_t3t_polling(0xFFFF, T3T_POLL_RC_SC, 0x0F);
     if (retval == NCI_STATUS_OK) {
       p_cb->cur_cmd = RW_T3T_CMD_GET_SYSTEM_CODES;
       p_cb->cur_tout = RW_T3T_DEFAULT_CMD_TIMEOUT_TICKS;
@@ -2987,7 +3002,8 @@
 ** Function         RW_T3tSetReadOnly
 **
 ** Description      This function performs NDEF read-only procedure
-**                  Note: Only Felica-Lite tags are supported by this API.
+**                  Note: Both NFC Forum and Felica-Lite tags are supported by
+**                        this API.
 **                        RW_T3tDetectNDef() must be called before using this
 **
 **                  The RW_T3T_SET_READ_ONLY_CPLT_EVT event will be returned.
@@ -3000,6 +3016,11 @@
   tNFC_STATUS retval = NFC_STATUS_OK;
   tRW_T3T_CB* p_cb = &rw_cb.tcb.t3t;
   tRW_DATA evt_data;
+  uint8_t rw_t3t_ndef_attrib_info[T3T_MSG_BLOCKSIZE];
+  uint8_t* p;
+  uint32_t tempU32 = 0;
+  uint16_t checksum, i;
+  uint8_t tempU8;
 
   DLOG_IF(INFO, nfc_debug_enabled)
       << StringPrintf("b_hard_lock=%d", b_hard_lock);
@@ -3026,22 +3047,71 @@
     (*(rw_cb.p_cback))(RW_T3T_SET_READ_ONLY_CPLT_EVT, &evt_data);
     return (retval);
   } else {
-    /* Poll tag, to see if Felica-Lite system is supported */
-    retval = (tNFC_STATUS)nci_snd_t3t_polling(T3T_SYSTEM_CODE_FELICA_LITE,
-                                              T3T_POLL_RC_SC, 0);
-    if (retval == NCI_STATUS_OK) {
-      if (b_hard_lock)
-        p_cb->cur_cmd = RW_T3T_CMD_SET_READ_ONLY_HARD;
-      else
+    if (p_cb->cur_active_sc == T3T_SYSTEM_CODE_NDEF) {
+      /* Tag previously responded for NDEF poll */
+      if (p_cb->ndef_attrib.rwflag != T3T_MSG_NDEF_RWFLAG_RO) {
+        /* First update attribute information block */
+        DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+            "%s - NDEF tag detected...update NDef attribution block.",
+            __func__);
         p_cb->cur_cmd = RW_T3T_CMD_SET_READ_ONLY_SOFT;
-      p_cb->cur_tout = RW_T3T_DEFAULT_CMD_TIMEOUT_TICKS;
-      p_cb->cur_poll_rc = T3T_POLL_RC_SC;
-      p_cb->rw_state = RW_T3T_STATE_COMMAND_PENDING;
-      p_cb->rw_substate = RW_T3T_SRO_SST_POLL_FELICA_LITE;
-      p_cb->flags |= RW_T3T_FL_W4_SRO_FELICA_LITE_POLL_RSP;
 
-      /* start timer for waiting for responses */
-      rw_t3t_start_poll_timer(p_cb);
+        p_cb->rw_substate = RW_T3T_SRO_SST_UPDATE_NDEF_ATTRIB;
+
+        p = rw_t3t_ndef_attrib_info;
+
+        UINT8_TO_STREAM(p, p_cb->ndef_attrib.version);
+
+        /* Update NDEF info */
+        UINT8_TO_STREAM(
+            p, p_cb->ndef_attrib.nbr); /* NBr: number of blocks that can be read
+                                          using one Check command */
+        UINT8_TO_STREAM(p, p_cb->ndef_attrib.nbw); /* Nbw: number of blocks that
+                                                      can be written using one
+                                                      Update command */
+        UINT16_TO_BE_STREAM(
+            p, p_cb->ndef_attrib.nmaxb); /* Nmaxb: maximum number of blocks
+                                            available for NDEF data */
+        UINT32_TO_BE_STREAM(p, tempU32);
+        UINT8_TO_STREAM(
+            p, p_cb->ndef_attrib.writef); /* WriteFlag: 00h if writing
+                                             data finished; 0Fh if
+                                             writing data in progress */
+        UINT8_TO_STREAM(p, 0x00);         /* RWFlag: 00h NDEF is read-only */
+
+        tempU8 = (uint8_t)(p_cb->ndef_attrib.ln >> 16);
+        /* Get length (3-byte, big-endian) */
+        UINT8_TO_STREAM(p, tempU8);                   /* Ln: high-byte */
+        UINT16_TO_BE_STREAM(p, p_cb->ndef_attrib.ln); /* Ln: lo-word */
+
+        /* Calculate and append Checksum */
+        checksum = 0;
+        for (i = 0; i < T3T_MSG_NDEF_ATTR_INFO_SIZE; i++) {
+          checksum += rw_t3t_ndef_attrib_info[i];
+        }
+        UINT16_TO_BE_STREAM(p, checksum);
+
+        retval =
+            rw_t3t_update_block(p_cb, 0, (uint8_t*)rw_t3t_ndef_attrib_info);
+      }
+    } else {
+      /* Poll tag, to see if Felica-Lite system is supported */
+      retval = (tNFC_STATUS)nci_snd_t3t_polling(T3T_SYSTEM_CODE_FELICA_LITE,
+                                                T3T_POLL_RC_SC, 0);
+      if (retval == NCI_STATUS_OK) {
+        if (b_hard_lock)
+          p_cb->cur_cmd = RW_T3T_CMD_SET_READ_ONLY_HARD;
+        else
+          p_cb->cur_cmd = RW_T3T_CMD_SET_READ_ONLY_SOFT;
+        p_cb->cur_tout = RW_T3T_DEFAULT_CMD_TIMEOUT_TICKS;
+        p_cb->cur_poll_rc = T3T_POLL_RC_SC;
+        p_cb->rw_state = RW_T3T_STATE_COMMAND_PENDING;
+        p_cb->rw_substate = RW_T3T_SRO_SST_POLL_FELICA_LITE;
+        p_cb->flags |= RW_T3T_FL_W4_SRO_FELICA_LITE_POLL_RSP;
+
+        /* start timer for waiting for responses */
+        rw_t3t_start_poll_timer(p_cb);
+      }
     }
   }
   return (retval);
diff --git a/src/nfc/tags/rw_t4t.cc b/src/nfc/tags/rw_t4t.cc
index b7b6144..e5d3ef2 100644
--- a/src/nfc/tags/rw_t4t.cc
+++ b/src/nfc/tags/rw_t4t.cc
@@ -39,6 +39,7 @@
 using android::base::StringPrintf;
 
 extern bool nfc_debug_enabled;
+extern unsigned char appl_dta_mode_flag;
 
 /* main state */
 /* T4T is not activated                 */
@@ -78,7 +79,8 @@
 #define RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN 0x07
 /* waiting for response of updating CC      */
 #define RW_T4T_SUBSTATE_WAIT_UPDATE_CC 0x08
-
+/* waiting for response of reading CC       */
+#define RW_T4T_SUBSTATE_WAIT_ENDEF_FILE_CTRL_TLV 0x11
 #define RW_T4T_SUBSTATE_WAIT_GET_HW_VERSION 0x09
 #define RW_T4T_SUBSTATE_WAIT_GET_SW_VERSION 0x0A
 #define RW_T4T_SUBSTATE_WAIT_GET_UID 0x0B
@@ -93,9 +95,9 @@
 
 static bool rw_t4t_send_to_lower(NFC_HDR* p_c_apdu);
 static bool rw_t4t_select_file(uint16_t file_id);
-static bool rw_t4t_read_file(uint16_t offset, uint16_t length,
+static bool rw_t4t_read_file(uint32_t offset, uint32_t length,
                              bool is_continue);
-static bool rw_t4t_update_nlen(uint16_t ndef_len);
+static bool rw_t4t_update_nlen(uint32_t ndef_len);
 static bool rw_t4t_update_file(void);
 static bool rw_t4t_update_cc_to_readonly(void);
 static bool rw_t4t_select_application(uint8_t version);
@@ -141,6 +143,159 @@
 
 /*******************************************************************************
 **
+** Function         rw_t4t_set_ber_tlv
+**
+** Description      Send UpdateBinary Command with ODO and DDO
+**
+** Returns          TRUE if success
+**
+*******************************************************************************/
+static bool rw_t4t_set_ber_tlv(NFC_HDR* p_c_apdu, uint8_t* p, uint32_t length) {
+  tRW_T4T_CB* p_t4t = &rw_cb.tcb.t4t;
+  uint32_t data_length, tmp_length, tmp_offset;
+  uint8_t length_size, data_header = 0;
+
+  p_c_apdu->len = T4T_CMD_MIN_EXT_HDR_SIZE + 1; /* tag 53 */
+  /* Remove min data header for encoding offset and data length */
+  /* length is Lc data length */
+  /* data_length is the length of the data to be written to the ENDEF
+   * File */
+  data_length = length;
+  if (length <= 0x7F) {
+    /* Default Short Field Coding can be used */
+    /* BER-TLV length coded on one byte */
+    length_size = RW_T4T_BER_TLV_LENGTH_1_BYTE;
+
+  } else if ((length + RW_T4T_ODO_DDO_HEADER_2BYTES_LENGTH) <= 0xFF) {
+    /* Default Short Field Coding can be used */
+    /* BER-TLV length coded on two bytes: (81h+N) with N=0 to 255 */
+    length_size = RW_T4T_BER_TLV_LENGTH_2_BYTES;
+
+  } else {
+    if (p_t4t->intl_flags & RW_T4T_EXT_FIELD_CODING) {
+      /* Extended Field Coding can be used */
+      if (length <= 0xFF) {
+        DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+            "%s - Extended Field Coding used, 2-byte coding "
+            "for BER-TLV",
+            __func__);
+        /* BER-TLV length coded on two bytes still possible */
+        length_size = RW_T4T_BER_TLV_LENGTH_2_BYTES;
+
+      } else {
+        DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+            "%s - Extended Field Coding used, 3-byte coding "
+            "for BER-TLV",
+            __func__);
+        /* BER-TLV length coded on three bytes:
+         * (82h+N) with N=0 to 65535 */
+        length_size = RW_T4T_BER_TLV_LENGTH_3_BYTES;
+      }
+    } else {
+      DLOG_IF(INFO, nfc_debug_enabled)
+          << StringPrintf("%s - Short Field Coding used", __func__);
+      /* Only Short Field Coding can be used */
+      /* Write a max of 255 bytes in data field,
+       * as Lc=00 is reserved for Extended Field coding */
+      /* BER-TLV length coded on two bytes */
+      length_size = RW_T4T_BER_TLV_LENGTH_2_BYTES;
+      length = 0;
+    }
+  }
+
+  data_header = RW_T4T_ODO_DDO_HEADER_MIN_LENGTH + length_size;
+  if (length == 0) {
+    length = T4T_MAX_LENGTH_LC;
+    if (length <= p_t4t->max_update_size) {
+      data_length = T4T_MAX_LENGTH_LC - data_header;
+    } else {
+      /* Realign with MLc (taking into account header now) */
+      length = p_t4t->max_update_size;
+      data_length = p_t4t->max_update_size - data_header;
+    }
+  } else {
+    if ((length + data_header) <= p_t4t->max_update_size) {
+      length += data_header;
+    } else {
+      /* Realign with MLc (taking into account header now) */
+      length = p_t4t->max_update_size;
+      data_length = p_t4t->max_update_size - data_header;
+    }
+  }
+
+  UINT8_TO_BE_STREAM(p, T4T_CMD_CLASS);
+  UINT8_TO_BE_STREAM(p, T4T_CMD_INS_UPDATE_BINARY_ODO);
+  /* P1 P2 field */
+  UINT16_TO_BE_STREAM(p, 0x0000);
+  /* Lc field */
+  if (p_t4t->intl_flags & RW_T4T_EXT_FIELD_CODING) {
+    /* Coded over three bytes */
+    UINT8_TO_BE_STREAM(p, 0x00);
+    tmp_length = length;
+    tmp_length >>= 8;
+    UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_length));
+    tmp_length = length;
+    UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_length));
+    p_c_apdu->len += 3;
+  } else {
+    /* Coded over 1 byte */
+    UINT8_TO_BE_STREAM(p, ((uint8_t)length));
+    p_c_apdu->len += 1;
+  }
+
+  /* Data field containing data offset coded over 3 bytes
+   * followed by data to be written to the ENDEF File */
+  UINT16_TO_BE_STREAM(p, 0x5403);
+  tmp_offset = p_t4t->rw_offset;
+  tmp_offset >>= 16;
+  UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_offset));
+  tmp_offset = p_t4t->rw_offset;
+  tmp_offset >>= 8;
+  UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_offset));
+  tmp_offset = p_t4t->rw_offset;
+  UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_offset));
+
+  UINT8_TO_BE_STREAM(p, 0x53);
+  /* Data length */
+  if (length_size == RW_T4T_BER_TLV_LENGTH_1_BYTE) {
+    /* Length coded over 1 byte */
+    UINT8_TO_BE_STREAM(p, data_length);
+    p_c_apdu->len += 1;
+  } else if (length_size == RW_T4T_BER_TLV_LENGTH_2_BYTES) {
+    UINT8_TO_BE_STREAM(p, 0x81);
+    UINT8_TO_BE_STREAM(p, data_length);
+    p_c_apdu->len += 2;
+  } else if ((length_size == RW_T4T_BER_TLV_LENGTH_3_BYTES) &&
+             (data_length <= 0xFFFF)) {
+    /* Length coded over 3 bytes */
+    UINT8_TO_BE_STREAM(p, 0x82);
+    UINT16_TO_BE_STREAM(p, (uint16_t)data_length);
+    p_c_apdu->len += 3;
+  } else {
+    LOG(ERROR) << StringPrintf(
+        "%s - Data to be written to MV3.0 tag exceeds 0xFFFF", __func__);
+    return false;
+  }
+
+  memcpy(p, p_t4t->p_update_data, data_length);
+
+  p_c_apdu->len += data_length;
+
+  if (!rw_t4t_send_to_lower(p_c_apdu)) {
+    return false;
+  }
+  /* Le field not present */
+
+  /* adjust offset, length and pointer for remaining data */
+  p_t4t->rw_offset += data_length;
+  p_t4t->rw_length -= data_length;
+  p_t4t->p_update_data += data_length;
+
+  return true;
+}
+
+/*******************************************************************************
+**
 ** Function         rw_t4t_get_hw_version
 **
 ** Description      Send get hw version cmd to peer
@@ -610,12 +765,13 @@
   NFC_HDR* p_c_apdu;
   uint8_t* p;
 
-  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("File ID:0x%04X", file_id);
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("%s - File ID:0x%04X", __func__, file_id);
 
   p_c_apdu = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
 
   if (!p_c_apdu) {
-    LOG(ERROR) << StringPrintf("Cannot allocate buffer");
+    LOG(ERROR) << StringPrintf("%s - Cannot allocate buffer", __func__);
     return false;
   }
 
@@ -627,7 +783,8 @@
   UINT8_TO_BE_STREAM(p, T4T_CMD_P1_SELECT_BY_FILE_ID);
 
   /* if current version mapping is V2.0 */
-  if (rw_cb.tcb.t4t.version == T4T_VERSION_2_0) {
+  if ((rw_cb.tcb.t4t.version == T4T_VERSION_2_0) ||
+      (rw_cb.tcb.t4t.version == T4T_VERSION_3_0)) {
     UINT8_TO_BE_STREAM(p, T4T_CMD_P2_FIRST_OR_ONLY_0CH);
   } else /* version 1.0 */
   {
@@ -655,19 +812,21 @@
 ** Returns          TRUE if success
 **
 *******************************************************************************/
-static bool rw_t4t_read_file(uint16_t offset, uint16_t length,
+static bool rw_t4t_read_file(uint32_t offset, uint32_t length,
                              bool is_continue) {
   tRW_T4T_CB* p_t4t = &rw_cb.tcb.t4t;
   NFC_HDR* p_c_apdu;
   uint8_t* p;
+  uint32_t tmp_offset;
 
-  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-      "offset:%d, length:%d, is_continue:%d, ", offset, length, is_continue);
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("%s - offset:%d, length:%d, is_continue:%d, ", __func__,
+                      offset, length, is_continue);
 
   p_c_apdu = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
 
   if (!p_c_apdu) {
-    LOG(ERROR) << StringPrintf("Cannot allocate buffer");
+    LOG(ERROR) << StringPrintf("%s - Cannot allocate buffer", __func__);
     return false;
   }
 
@@ -682,18 +841,97 @@
   /* adjust reading length if payload is bigger than max size per single command
    */
   if (length > p_t4t->max_read_size) {
-    length = (uint8_t)(p_t4t->max_read_size);
+    length = (uint32_t)(p_t4t->max_read_size);
   }
 
   p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
   p = (uint8_t*)(p_c_apdu + 1) + p_c_apdu->offset;
 
   UINT8_TO_BE_STREAM(p, (T4T_CMD_CLASS | rw_cb.tcb.t4t.channel));
-  UINT8_TO_BE_STREAM(p, T4T_CMD_INS_READ_BINARY);
-  UINT16_TO_BE_STREAM(p, offset);
-  UINT8_TO_BE_STREAM(p, length); /* Le */
+  if ((p_t4t->rw_offset + p_t4t->rw_length) > 0x7FFF) {
+    /* ReadBinary with ODO must be used */
+    if (p_t4t->cc_file.version >= T4T_VERSION_3_0) {
+      /* MV 3.0 tag */
+      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+          "%s - Read above 0x7FFF address offset detected", __func__);
 
-  p_c_apdu->len = T4T_CMD_MIN_HDR_SIZE + 1; /* adding Le */
+      p_c_apdu->len = T4T_CMD_MIN_EXT_HDR_SIZE;
+
+      UINT8_TO_BE_STREAM(p, T4T_CMD_INS_READ_BINARY_ODO);
+      /* P1 P2 field */
+      UINT16_TO_BE_STREAM(p, 0x0000);
+      /* Lc field */
+      if (p_t4t->intl_flags & RW_T4T_EXT_FIELD_CODING) {
+        /* Coded over three bytes */
+        UINT16_TO_BE_STREAM(p, 0x0000);
+        UINT8_TO_BE_STREAM(p, 0x05);
+        p_c_apdu->len += 3;
+      } else {
+        /* Coded over 1 byte */
+        UINT8_TO_BE_STREAM(p, 0x05);
+        p_c_apdu->len += 1;
+      }
+      p_t4t->intl_flags |= RW_T4T_DDO_LC_FIELD_CODING;
+
+      /* Data field containing address offset */
+      UINT16_TO_BE_STREAM(p, 0x5403);
+      tmp_offset = offset;
+      tmp_offset >>= 16;
+      UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_offset));
+      tmp_offset = offset;
+      tmp_offset >>= 8;
+      UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_offset));
+      tmp_offset = offset;
+      UINT8_TO_BE_STREAM(p, ((uint8_t)tmp_offset));
+
+      /* Le field */
+      if (length < p_t4t->max_read_size) {
+        /* For the last R-APDU, must consider the DDO '53h' tag and data length
+         * size in the response. As difficult to know which coding will be used
+         * for BER-TLV, safer to request the remaining maximum number of bytes
+         * the tag can send */
+        length = 0x0000;
+      }
+      if (p_t4t->intl_flags & RW_T4T_EXT_FIELD_CODING) {
+        /* If Lc is coded over 3 bytes, Le is coded over 2 bytes */
+        p_c_apdu->len += 2;
+        UINT16_TO_BE_STREAM(p, length);
+      } else {
+        /* Coded over 1 byte */
+        p_c_apdu->len += 1;
+        UINT8_TO_BE_STREAM(p, length);
+      }
+    } else {
+      LOG(ERROR) << StringPrintf("%s - Cannot read above 0x7FFF for MV2.0",
+                                 __func__);
+      return false;
+    }
+  } else {
+    /* MV 2.0 tag or MV 3.0 tag read below 32kB */
+    DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+        "%s - Read below 0x8000 address offset detected", __func__);
+
+    UINT8_TO_BE_STREAM(p, T4T_CMD_INS_READ_BINARY);
+    /* Lc and Data fields absent */
+    UINT16_TO_BE_STREAM(p, offset);
+    if (p_t4t->intl_flags & RW_T4T_EXT_FIELD_CODING) {
+      /* Coded over three bytes with first one null */
+      p_c_apdu->len = T4T_CMD_MIN_HDR_SIZE + 3; /* adding Le */
+      UINT8_TO_BE_STREAM(p, 0x00);
+      UINT16_TO_BE_STREAM(p, length); /* Le */
+    } else {
+      /* If MLe=256 bytes, using UINT8_TO_BE_STREAM casts the length
+       * to Le=0x00 which is accepted by the specifications but not
+       * by all tags in the field. Force Le to 255 bytes to read the
+       * remaining bytes in two times
+       */
+      if (length == (T4T_MAX_LENGTH_LE + 1)) {
+        length = T4T_MAX_LENGTH_LE;
+      }
+      p_c_apdu->len = T4T_CMD_MIN_HDR_SIZE + 1; /* adding Le */
+      UINT8_TO_BE_STREAM(p, length);            /* Le */
+    }
+  }
 
   if (!rw_t4t_send_to_lower(p_c_apdu)) {
     return false;
@@ -711,16 +949,18 @@
 ** Returns          TRUE if success
 **
 *******************************************************************************/
-static bool rw_t4t_update_nlen(uint16_t ndef_len) {
+static bool rw_t4t_update_nlen(uint32_t ndef_len) {
+  tRW_T4T_CB* p_t4t = &rw_cb.tcb.t4t;
   NFC_HDR* p_c_apdu;
   uint8_t* p;
 
-  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("NLEN:%d", ndef_len);
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("%s - NLEN:%d", __func__, ndef_len);
 
   p_c_apdu = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
 
   if (!p_c_apdu) {
-    LOG(ERROR) << StringPrintf("Cannot allocate buffer");
+    LOG(ERROR) << StringPrintf("%s - Cannot allocate buffer", __func__);
     return false;
   }
 
@@ -730,10 +970,14 @@
   UINT8_TO_BE_STREAM(p, T4T_CMD_CLASS);
   UINT8_TO_BE_STREAM(p, T4T_CMD_INS_UPDATE_BINARY);
   UINT16_TO_BE_STREAM(p, 0x0000); /* offset for NLEN */
-  UINT8_TO_BE_STREAM(p, T4T_FILE_LENGTH_SIZE);
-  UINT16_TO_BE_STREAM(p, ndef_len);
+  UINT8_TO_BE_STREAM(p, p_t4t->cc_file.ndef_fc.nlen_size);
+  if (p_t4t->cc_file.ndef_fc.nlen_size == T4T_FILE_LENGTH_SIZE) {
+    UINT16_TO_BE_STREAM(p, ndef_len);
+  } else {
+    UINT32_TO_BE_STREAM(p, ndef_len);
+  }
 
-  p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + T4T_FILE_LENGTH_SIZE;
+  p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + p_t4t->cc_file.ndef_fc.nlen_size;
 
   if (!rw_t4t_send_to_lower(p_c_apdu)) {
     return false;
@@ -755,48 +999,83 @@
   tRW_T4T_CB* p_t4t = &rw_cb.tcb.t4t;
   NFC_HDR* p_c_apdu;
   uint8_t* p;
-  uint16_t length;
+  uint32_t length;
 
-  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-      "rw_offset:%d, rw_length:%d", p_t4t->rw_offset, p_t4t->rw_length);
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("%s - rw_offset:%d, rw_length:%d", __func__,
+                      p_t4t->rw_offset, p_t4t->rw_length);
 
   p_c_apdu = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
 
   if (!p_c_apdu) {
-    LOG(ERROR) << StringPrintf("Cannot allocate buffer");
+    LOG(ERROR) << StringPrintf("%s - Cannot allocate buffer", __func__);
     return false;
   }
 
   /* try to send all of remaining data */
   length = p_t4t->rw_length;
 
+  if (length == 0) {
+    LOG(ERROR) << StringPrintf("%s - Length to write can not be null",
+                               __func__);
+    return false;
+  }
+
   /* adjust updating length if payload is bigger than max size per single
    * command */
   if (length > p_t4t->max_update_size) {
-    length = (uint8_t)(p_t4t->max_update_size);
+    length = (uint32_t)(p_t4t->max_update_size);
   }
 
   p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
   p = (uint8_t*)(p_c_apdu + 1) + p_c_apdu->offset;
 
-  UINT8_TO_BE_STREAM(p, T4T_CMD_CLASS);
-  UINT8_TO_BE_STREAM(p, T4T_CMD_INS_UPDATE_BINARY);
-  UINT16_TO_BE_STREAM(p, p_t4t->rw_offset);
-  UINT8_TO_BE_STREAM(p, length);
+  if ((p_t4t->rw_offset + p_t4t->rw_length) > 0x7FFF) {
+    /* UpdateBinary with ODO and DDO */
+    if (p_t4t->cc_file.version >= T4T_VERSION_3_0) {
+      /* MV 3.0 tag */
+      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+          "%s - MV 3.0 detected, update NDEF Message size > 0x7FFF", __func__);
 
-  memcpy(p, p_t4t->p_update_data, length);
+      return rw_t4t_set_ber_tlv(p_c_apdu, p, length);
 
-  p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + length;
+    } else {
+      LOG(ERROR) << StringPrintf("%s - Cannot write above 0x7FFF for MV2.0",
+                                 __func__);
+      return false;
+    }
+  } else {
+    /* MV 2.0 or MV 3.0 tag */
+    /* ReadBinary with Standard Data structure used */
+    DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+        "%s - NDEF Message to write < 0x8000, MV2.0 or MV3.0 tag", __func__);
 
-  if (!rw_t4t_send_to_lower(p_c_apdu)) {
-    return false;
+    UINT8_TO_BE_STREAM(p, T4T_CMD_CLASS);
+    UINT8_TO_BE_STREAM(p, T4T_CMD_INS_UPDATE_BINARY);
+    UINT16_TO_BE_STREAM(p, p_t4t->rw_offset);
+
+    /* Lc field encoded using Short Field Coding */
+    if (length > T4T_MAX_LENGTH_LC) {
+      /* Write a max of 255 bytes,
+       * as Lc=00 is reserved for Extended Field coding */
+      length = T4T_MAX_LENGTH_LC;
+    }
+    UINT8_TO_BE_STREAM(p, length);
+
+    memcpy(p, p_t4t->p_update_data, length);
+
+    p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + length;
+
+    if (!rw_t4t_send_to_lower(p_c_apdu)) {
+      return false;
+    }
+
+    /* adjust offset, length and pointer for remaining data */
+    p_t4t->rw_offset += length;
+    p_t4t->rw_length -= length;
+    p_t4t->p_update_data += length;
   }
 
-  /* adjust offset, length and pointer for remaining data */
-  p_t4t->rw_offset += length;
-  p_t4t->rw_length -= length;
-  p_t4t->p_update_data += length;
-
   return true;
 }
 
@@ -814,12 +1093,12 @@
   uint8_t* p;
 
   DLOG_IF(INFO, nfc_debug_enabled)
-      << StringPrintf("Remove Write access from CC");
+      << StringPrintf("%s - Remove Write access from CC", __func__);
 
   p_c_apdu = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
 
   if (!p_c_apdu) {
-    LOG(ERROR) << StringPrintf("Cannot allocate buffer");
+    LOG(ERROR) << StringPrintf("%s - Cannot allocate buffer", __func__);
     return false;
   }
 
@@ -859,6 +1138,7 @@
 **                        CLA INS P1 P2 Lc Data(AID)      Le
 **                  V1.0: 00  A4  04 00 07 D2760000850100 -
 **                  V2.0: 00  A4  04 00 07 D2760000850101 00
+**                  V3.0: 00  A4  04 00 07 D2760000850101 00
 **
 ** Returns          TRUE if success
 **
@@ -867,12 +1147,13 @@
   NFC_HDR* p_c_apdu;
   uint8_t* p;
 
-  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("version:0x%X", version);
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("%s - version:0x%X", __func__, version);
 
   p_c_apdu = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
 
   if (!p_c_apdu) {
-    LOG(ERROR) << StringPrintf("Cannot allocate buffer");
+    LOG(ERROR) << StringPrintf("%s - Cannot allocate buffer", __func__);
     return false;
   }
 
@@ -891,7 +1172,8 @@
     memcpy(p, t4t_v10_ndef_tag_aid, T4T_V10_NDEF_TAG_AID_LEN);
 
     p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + T4T_V10_NDEF_TAG_AID_LEN;
-  } else if (version == T4T_VERSION_2_0) /* this is for V2.0 */
+  } else if ((version == T4T_VERSION_2_0) || /* this is for V2.0 */
+             (version == T4T_VERSION_3_0))   /* this is for V3.0 */
   {
     UINT8_TO_BE_STREAM(p, T4T_V20_NDEF_TAG_AID_LEN);
 
@@ -927,61 +1209,71 @@
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
   if (p_t4t->cc_file.cclen < T4T_CC_FILE_MIN_LEN) {
-    LOG(ERROR) << StringPrintf("CCLEN (%d) is too short", p_t4t->cc_file.cclen);
+    LOG(ERROR) << StringPrintf("%s - CCLEN (%d) is too short", __func__,
+                               p_t4t->cc_file.cclen);
     return false;
   }
 
-  if (T4T_GET_MAJOR_VERSION(p_t4t->cc_file.version) !=
+  if (T4T_GET_MAJOR_VERSION(p_t4t->cc_file.version) >
       T4T_GET_MAJOR_VERSION(p_t4t->version)) {
     LOG(ERROR) << StringPrintf(
-        "Peer version (0x%02X) is matched to ours "
+        "%s - Peer version (0x%02X) mismatched to ours "
         "(0x%02X)",
-        p_t4t->cc_file.version, p_t4t->version);
+        __func__, p_t4t->cc_file.version, p_t4t->version);
+
     return false;
   }
 
   if (p_t4t->cc_file.max_le < 0x000F) {
-    LOG(ERROR) << StringPrintf("MaxLe (%d) is too small",
+    LOG(ERROR) << StringPrintf("%s - MaxLe (%d) is too small", __func__,
                                p_t4t->cc_file.max_le);
     return false;
   }
 
-  if (p_t4t->cc_file.max_lc < 0x0001) {
-    LOG(ERROR) << StringPrintf("MaxLc (%d) is too small",
+  if (p_t4t->cc_file.max_lc < 0x0001 ||
+      ((p_t4t->cc_file.max_lc < 0x000D) && appl_dta_mode_flag)) {
+    LOG(ERROR) << StringPrintf("%s - MaxLc (%d) is too small", __func__,
                                p_t4t->cc_file.max_lc);
     return false;
   }
 
   if ((p_t4t->cc_file.ndef_fc.file_id == T4T_CC_FILE_ID) ||
       (p_t4t->cc_file.ndef_fc.file_id == 0xE102) ||
-      (p_t4t->cc_file.ndef_fc.file_id == 0xE103) ||
       ((p_t4t->cc_file.ndef_fc.file_id == 0x0000) &&
-       (p_t4t->cc_file.version == 0x20)) ||
+       ((p_t4t->cc_file.version == 0x20) ||
+        (p_t4t->cc_file.version == 0x30))) ||
       (p_t4t->cc_file.ndef_fc.file_id == 0x3F00) ||
       (p_t4t->cc_file.ndef_fc.file_id == 0x3FFF) ||
       (p_t4t->cc_file.ndef_fc.file_id == 0xFFFF)) {
-    LOG(ERROR) << StringPrintf("File ID (0x%04X) is invalid",
+    LOG(ERROR) << StringPrintf("%s - File ID (0x%04X) is invalid", __func__,
                                p_t4t->cc_file.ndef_fc.file_id);
     return false;
   }
 
-  if ((p_t4t->cc_file.ndef_fc.max_file_size < 0x0005) ||
-      (p_t4t->cc_file.ndef_fc.max_file_size == 0xFFFF)) {
-    LOG(ERROR) << StringPrintf("max_file_size (%d) is reserved",
+  if (((p_t4t->cc_file.version == 0x20) &&
+       ((p_t4t->cc_file.ndef_fc.max_file_size < 0x0005) ||
+        (p_t4t->cc_file.ndef_fc.max_file_size > 0x7FFF))) ||
+      ((p_t4t->cc_file.version == 0x30) &&
+       ((p_t4t->cc_file.ndef_fc.max_file_size < 0x00000007) ||
+        (p_t4t->cc_file.ndef_fc.max_file_size == 0xFFFFFFFF)))) {
+    LOG(ERROR) << StringPrintf("%s - max_file_size (%d) is reserved", __func__,
                                p_t4t->cc_file.ndef_fc.max_file_size);
     return false;
   }
 
-  if (p_t4t->cc_file.ndef_fc.read_access != T4T_FC_READ_ACCESS) {
-    LOG(ERROR) << StringPrintf("Read Access (0x%02X) is invalid",
+  if (((p_t4t->cc_file.ndef_fc.read_access > T4T_FC_READ_ACCESS) &&
+       (p_t4t->cc_file.ndef_fc.read_access < T4T_FC_READ_ACCESS_PROP_START)) ||
+      (p_t4t->cc_file.ndef_fc.read_access == T4T_FC_NO_READ_ACCESS)) {
+    LOG(ERROR) << StringPrintf("%s - Read Access (0x%02X) is invalid", __func__,
                                p_t4t->cc_file.ndef_fc.read_access);
     return false;
   }
 
-  if ((p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS) &&
-      (p_t4t->cc_file.ndef_fc.write_access < T4T_FC_WRITE_ACCESS_PROP_START)) {
-    LOG(ERROR) << StringPrintf("Write Access (0x%02X) is invalid",
-                               p_t4t->cc_file.ndef_fc.write_access);
+  if (((p_t4t->cc_file.ndef_fc.write_access > T4T_FC_WRITE_ACCESS) &&
+       (p_t4t->cc_file.ndef_fc.write_access <
+        T4T_FC_WRITE_ACCESS_PROP_START))) {
+    LOG(ERROR) << StringPrintf("%s - Write Access (0x%02X) is invalid",
+                               __func__, p_t4t->cc_file.ndef_fc.write_access);
     return false;
   }
 
@@ -1003,9 +1295,9 @@
   tRW_EVENT event;
 
   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-      "status:0x%02X, sw1:0x%02X, sw2:0x%02X, "
+      "%s - status:0x%02X, sw1:0x%02X, sw2:0x%02X, "
       "state:0x%X",
-      status, sw1, sw2, p_t4t->state);
+      __func__, status, sw1, sw2, p_t4t->state);
 
   nfc_stop_quick_timer(&p_t4t->timer);
 
@@ -1252,12 +1544,15 @@
 static void rw_t4t_sm_detect_ndef(NFC_HDR* p_r_apdu) {
   tRW_T4T_CB* p_t4t = &rw_cb.tcb.t4t;
   uint8_t *p, type, length;
-  uint16_t status_words, nlen;
+  uint32_t nlen;
+  uint32_t cc_file_offset = 0x00;
+  uint16_t status_words;
+  uint8_t cc_file_rsp_len = T4T_CC_FILE_MIN_LEN;
   tRW_DATA rw_data;
 
   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-      "sub_state:%s (%d)", rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(),
-      p_t4t->sub_state);
+      "%s - sub_state:%s (%d)", __func__,
+      rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(), p_t4t->sub_state);
 
   /* get status words */
   p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
@@ -1265,13 +1560,14 @@
   BE_STREAM_TO_UINT16(status_words, p);
 
   if (status_words != T4T_RSP_CMD_CMPLTED) {
-    /* try V1.0 after failing of V2.0 */
+    /* try V1.0 after failing of V2.0 or V3.0 */
     if ((p_t4t->sub_state == RW_T4T_SUBSTATE_WAIT_SELECT_APP) &&
-        (p_t4t->version == T4T_VERSION_2_0)) {
+        ((p_t4t->version == T4T_VERSION_2_0) ||
+         (p_t4t->version == T4T_VERSION_3_0))) {
       p_t4t->version = T4T_VERSION_1_0;
 
-      DLOG_IF(INFO, nfc_debug_enabled)
-          << StringPrintf("retry with version=0x%02X", p_t4t->version);
+      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+          "%s - retry with version=0x%02X", __func__, p_t4t->version);
 
       if (!rw_t4t_select_application(T4T_VERSION_1_0)) {
         rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
@@ -1298,7 +1594,8 @@
     case RW_T4T_SUBSTATE_WAIT_SELECT_CC:
 
       /* CC file has been selected then read mandatory part of CC file */
-      if (!rw_t4t_read_file(0x00, T4T_CC_FILE_MIN_LEN, false)) {
+      cc_file_offset = 0x00;
+      if (!rw_t4t_read_file(cc_file_offset, cc_file_rsp_len, false)) {
         rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
       } else {
         p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_CC_FILE;
@@ -1308,7 +1605,7 @@
     case RW_T4T_SUBSTATE_WAIT_CC_FILE:
 
       /* CC file has been read then validate and select mandatory NDEF file */
-      if (p_r_apdu->len >= T4T_CC_FILE_MIN_LEN + T4T_RSP_STATUS_WORDS_SIZE) {
+      if (p_r_apdu->len >= cc_file_rsp_len + T4T_RSP_STATUS_WORDS_SIZE) {
         p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
 
         BE_STREAM_TO_UINT16(p_t4t->cc_file.cclen, p);
@@ -1327,34 +1624,107 @@
           BE_STREAM_TO_UINT8(p_t4t->cc_file.ndef_fc.write_access, p);
 
           DLOG_IF(INFO, nfc_debug_enabled)
-              << StringPrintf("Capability Container (CC) file");
-          DLOG_IF(INFO, nfc_debug_enabled)
-              << StringPrintf("  CCLEN:  0x%04X", p_t4t->cc_file.cclen);
-          DLOG_IF(INFO, nfc_debug_enabled)
-              << StringPrintf("  Version:0x%02X", p_t4t->cc_file.version);
-          DLOG_IF(INFO, nfc_debug_enabled)
-              << StringPrintf("  MaxLe:  0x%04X", p_t4t->cc_file.max_le);
-          DLOG_IF(INFO, nfc_debug_enabled)
-              << StringPrintf("  MaxLc:  0x%04X", p_t4t->cc_file.max_lc);
-          DLOG_IF(INFO, nfc_debug_enabled)
-              << StringPrintf("  NDEF File Control TLV");
+              << StringPrintf("%s - Capability Container (CC) file", __func__);
           DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-              "    FileID:      0x%04X", p_t4t->cc_file.ndef_fc.file_id);
+              "%s -   CCLEN:  0x%04X", __func__, p_t4t->cc_file.cclen);
           DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-              "    MaxFileSize: 0x%04X", p_t4t->cc_file.ndef_fc.max_file_size);
+              "%s -   Version:0x%02X", __func__, p_t4t->cc_file.version);
           DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-              "    ReadAccess:  0x%02X", p_t4t->cc_file.ndef_fc.read_access);
+              "%s -  MaxLe:  0x%04X", __func__, p_t4t->cc_file.max_le);
           DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-              "    WriteAccess: 0x%02X", p_t4t->cc_file.ndef_fc.write_access);
+              "%s -   MaxLc:  0x%04X", __func__, p_t4t->cc_file.max_lc);
+          DLOG_IF(INFO, nfc_debug_enabled)
+              << StringPrintf("%s -  NDEF File Control TLV", __func__);
+          DLOG_IF(INFO, nfc_debug_enabled)
+              << StringPrintf("%s -    FileID:      0x%04X", __func__,
+                              p_t4t->cc_file.ndef_fc.file_id);
+          DLOG_IF(INFO, nfc_debug_enabled)
+              << StringPrintf("%s -    MaxFileSize: 0x%04X", __func__,
+                              p_t4t->cc_file.ndef_fc.max_file_size);
+          DLOG_IF(INFO, nfc_debug_enabled)
+              << StringPrintf("%s -     ReadAccess:  0x%02X", __func__,
+                              p_t4t->cc_file.ndef_fc.read_access);
+          DLOG_IF(INFO, nfc_debug_enabled)
+              << StringPrintf("%s -    WriteAccess: 0x%02X", __func__,
+                              p_t4t->cc_file.ndef_fc.write_access);
 
           if (rw_t4t_validate_cc_file()) {
             if (!rw_t4t_select_file(p_t4t->cc_file.ndef_fc.file_id)) {
               rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
             } else {
+              p_t4t->cc_file.ndef_fc.nlen_size = T4T_FILE_LENGTH_SIZE;
               p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE;
             }
             break;
           }
+        } else if ((type == T4T_ENDEF_FILE_CONTROL_TYPE) &&
+                   (length == T4T_ENDEF_FILE_CONTROL_LENGTH)) {
+          DLOG_IF(INFO, nfc_debug_enabled)
+              << StringPrintf("%s - Capability Container (CC) file", __func__);
+          DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+              "%s -   CCLEN:  0x%04X", __func__, p_t4t->cc_file.cclen);
+          DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+              "%s -   Version:0x%02X", __func__, p_t4t->cc_file.version);
+          DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+              "%s -   MaxLe:  0x%04X", __func__, p_t4t->cc_file.max_le);
+          DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+              "%s -   MaxLc:  0x%04X", __func__, p_t4t->cc_file.max_lc);
+
+          cc_file_offset = T4T_ENDEF_FC_V_FIELD_OFFSET;
+          cc_file_rsp_len = T4T_ENDEF_FILE_CONTROL_TLV_SIZE - 2;
+
+          /* CC file has been selected then now read from control TLV area part
+           * of CC file */
+          /* assume ENDEF Ctrl TLV is the first one */
+          /* read again the TLV as 2 bytes missing */
+          if (!rw_t4t_read_file(cc_file_offset, cc_file_rsp_len, false)) {
+            rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
+          } else {
+            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_ENDEF_FILE_CTRL_TLV;
+          }
+          break;
+        }
+      }
+
+      /* invalid response or CC file */
+      p_t4t->ndef_status &= ~(RW_T4T_NDEF_STATUS_NDEF_DETECTED);
+      rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+      break;
+
+    case RW_T4T_SUBSTATE_WAIT_ENDEF_FILE_CTRL_TLV:
+
+      if (p_r_apdu->len >=
+          T4T_ENDEF_FILE_CONTROL_LENGTH + T4T_RSP_STATUS_WORDS_SIZE) {
+        p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
+
+        BE_STREAM_TO_UINT16(p_t4t->cc_file.ndef_fc.file_id, p);
+        BE_STREAM_TO_UINT32(p_t4t->cc_file.ndef_fc.max_file_size, p);
+        BE_STREAM_TO_UINT8(p_t4t->cc_file.ndef_fc.read_access, p);
+        BE_STREAM_TO_UINT8(p_t4t->cc_file.ndef_fc.write_access, p);
+
+        DLOG_IF(INFO, nfc_debug_enabled)
+            << StringPrintf("%s -  ENDEF File Control TLV", __func__);
+        DLOG_IF(INFO, nfc_debug_enabled)
+            << StringPrintf("%s -    FileID:      0x%04X", __func__,
+                            p_t4t->cc_file.ndef_fc.file_id);
+        DLOG_IF(INFO, nfc_debug_enabled)
+            << StringPrintf("%s -    MaxFileSize: 0x%08X", __func__,
+                            p_t4t->cc_file.ndef_fc.max_file_size);
+        DLOG_IF(INFO, nfc_debug_enabled)
+            << StringPrintf("%s -    ReadAccess:  0x%02X", __func__,
+                            p_t4t->cc_file.ndef_fc.read_access);
+        DLOG_IF(INFO, nfc_debug_enabled)
+            << StringPrintf("%s -    WriteAccess: 0x%02X", __func__,
+                            p_t4t->cc_file.ndef_fc.write_access);
+
+        if (rw_t4t_validate_cc_file()) {
+          if (!rw_t4t_select_file(p_t4t->cc_file.ndef_fc.file_id)) {
+            rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
+          } else {
+            p_t4t->cc_file.ndef_fc.nlen_size = T4T_EFILE_LENGTH_SIZE;
+            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE;
+          }
+          break;
         }
       }
 
@@ -1366,7 +1736,7 @@
     case RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE:
 
       /* NDEF file has been selected then read the first 2 bytes (NLEN) */
-      if (!rw_t4t_read_file(0, T4T_FILE_LENGTH_SIZE, false)) {
+      if (!rw_t4t_read_file(0, p_t4t->cc_file.ndef_fc.nlen_size, false)) {
         rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
       } else {
         p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_READ_NLEN;
@@ -1376,16 +1746,21 @@
     case RW_T4T_SUBSTATE_WAIT_READ_NLEN:
 
       /* NLEN has been read then report upper layer */
-      if (p_r_apdu->len == T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE) {
+      if (p_r_apdu->len ==
+          p_t4t->cc_file.ndef_fc.nlen_size + T4T_RSP_STATUS_WORDS_SIZE) {
         /* get length of NDEF */
         p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
-        BE_STREAM_TO_UINT16(nlen, p);
+        if (p_t4t->cc_file.ndef_fc.nlen_size == T4T_FILE_LENGTH_SIZE) {
+          BE_STREAM_TO_UINT16(nlen, p);
+        } else {
+          BE_STREAM_TO_UINT32(nlen, p);
+        }
 
-        if (nlen <=
-            p_t4t->cc_file.ndef_fc.max_file_size - T4T_FILE_LENGTH_SIZE) {
+        if (nlen <= p_t4t->cc_file.ndef_fc.max_file_size -
+                        p_t4t->cc_file.ndef_fc.nlen_size) {
           p_t4t->ndef_status = RW_T4T_NDEF_STATUS_NDEF_DETECTED;
 
-          if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS) {
+          if (p_t4t->cc_file.ndef_fc.write_access == T4T_FC_NO_WRITE_ACCESS) {
             p_t4t->ndef_status |= RW_T4T_NDEF_STATUS_NDEF_READ_ONLY;
           }
 
@@ -1396,9 +1771,14 @@
             p_t4t->max_read_size = p_t4t->cc_file.max_le;
           }
 
-          /* Le: valid range is 0x01 to 0xFF */
-          if (p_t4t->max_read_size >= T4T_MAX_LENGTH_LE) {
-            p_t4t->max_read_size = T4T_MAX_LENGTH_LE;
+          DLOG_IF(INFO, nfc_debug_enabled)
+              << StringPrintf("%s -    max_read_size:      0x%04X", __func__,
+                              p_t4t->max_read_size);
+
+          /* Le: valid range is 0x0001 to 0xFFFF */
+          if (p_t4t->max_read_size > T4T_MAX_LENGTH_LE + 1) {
+            /* Extended Field Coding supported by the tag */
+            p_t4t->intl_flags |= RW_T4T_EXT_FIELD_CODING;
           }
 
           /* Get max bytes to update per command */
@@ -1408,9 +1788,10 @@
             p_t4t->max_update_size = p_t4t->cc_file.max_lc;
           }
 
-          /* Lc: valid range is 0x01 to 0xFF */
-          if (p_t4t->max_update_size >= T4T_MAX_LENGTH_LC) {
-            p_t4t->max_update_size = T4T_MAX_LENGTH_LC;
+          /* Lc: valid range is 0x0001 to 0xFFFF */
+          if (p_t4t->max_update_size > T4T_MAX_LENGTH_LC) {
+            /* Extended Field Coding supported by the tag */
+            p_t4t->intl_flags |= RW_T4T_EXT_FIELD_CODING;
           }
 
           p_t4t->ndef_length = nlen;
@@ -1421,7 +1802,7 @@
             rw_data.ndef.protocol = NFC_PROTOCOL_ISO_DEP;
             rw_data.ndef.max_size =
                 (uint32_t)(p_t4t->cc_file.ndef_fc.max_file_size -
-                           (uint16_t)T4T_FILE_LENGTH_SIZE);
+                           (uint16_t)p_t4t->cc_file.ndef_fc.nlen_size);
             rw_data.ndef.cur_size = nlen;
             rw_data.ndef.flags = RW_NDEF_FL_SUPPORTED | RW_NDEF_FL_FORMATED;
             if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS) {
@@ -1431,23 +1812,23 @@
             (*(rw_cb.p_cback))(RW_T4T_NDEF_DETECT_EVT, &rw_data);
 
             DLOG_IF(INFO, nfc_debug_enabled)
-                << StringPrintf("Sent RW_T4T_NDEF_DETECT_EVT");
+                << StringPrintf("%s - Sent RW_T4T_NDEF_DETECT_EVT", __func__);
           }
         } else {
           /* NLEN should be less than max file size */
           LOG(ERROR) << StringPrintf(
-              "NLEN (%d) + 2 must be <= max file "
+              "%s - NLEN (%d) + 2 must be <= max file "
               "size (%d)",
-              nlen, p_t4t->cc_file.ndef_fc.max_file_size);
+              __func__, nlen, p_t4t->cc_file.ndef_fc.max_file_size);
 
           p_t4t->ndef_status &= ~(RW_T4T_NDEF_STATUS_NDEF_DETECTED);
           rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
         }
       } else {
-        /* response payload size should be T4T_FILE_LENGTH_SIZE */
+        /* response payload size should be T4T_(E)FILE_LENGTH_SIZE */
         LOG(ERROR) << StringPrintf(
-            "Length (%d) of R-APDU must be %d", p_r_apdu->len,
-            T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE);
+            "%s - Length (%d) of R-APDU must be %d", __func__, p_r_apdu->len,
+            p_t4t->cc_file.ndef_fc.nlen_size + T4T_RSP_STATUS_WORDS_SIZE);
 
         p_t4t->ndef_status &= ~(RW_T4T_NDEF_STATUS_NDEF_DETECTED);
         rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
@@ -1455,7 +1836,8 @@
       break;
 
     default:
-      LOG(ERROR) << StringPrintf("unknown sub_state=%d", p_t4t->sub_state);
+      LOG(ERROR) << StringPrintf("%s - unknown sub_state=%d", __func__,
+                                 p_t4t->sub_state);
       rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
       break;
   }
@@ -1474,11 +1856,12 @@
   tRW_T4T_CB* p_t4t = &rw_cb.tcb.t4t;
   uint8_t* p;
   uint16_t status_words;
+  uint16_t r_apdu_len;
   tRW_DATA rw_data;
 
   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-      "sub_state:%s (%d)", rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(),
-      p_t4t->sub_state);
+      "%s - sub_state:%s (%d)", __func__,
+      rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(), p_t4t->sub_state);
 
   /* get status words */
   p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
@@ -1497,46 +1880,141 @@
       /* Read partial or complete data */
       p_r_apdu->len -= T4T_RSP_STATUS_WORDS_SIZE;
 
-      if ((p_r_apdu->len > 0) && (p_r_apdu->len <= p_t4t->rw_length)) {
-        p_t4t->rw_length -= p_r_apdu->len;
-        p_t4t->rw_offset += p_r_apdu->len;
-
-        if (rw_cb.p_cback) {
-          rw_data.data.status = NFC_STATUS_OK;
-          rw_data.data.p_data = p_r_apdu;
-
-          /* if need to read more data */
-          if (p_t4t->rw_length > 0) {
-            (*(rw_cb.p_cback))(RW_T4T_NDEF_READ_EVT, &rw_data);
-
-            if (!rw_t4t_read_file(p_t4t->rw_offset, p_t4t->rw_length, true)) {
-              rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
+      p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
+      if (p_t4t->intl_flags & RW_T4T_DDO_LC_FIELD_CODING) {
+        if (*p == 0x53) {
+          /* ReadBinary command with ODO */
+          if (*(p + 1) <= 0x7F) {
+            p_r_apdu->len -= 2;
+            p_r_apdu->offset += 2;
+            /* Content read length coded over 1 byte in 1st byte
+             * of BER-TLV length field */
+            DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+                "%s - Content read length expected: 0x%02X, returned: 0x%02X",
+                __func__, *(p + 1), p_r_apdu->len);
+            if (*(p + 1) == p_r_apdu->len) {
+              if ((p_r_apdu->len > 0) && (p_r_apdu->len <= p_t4t->rw_length)) {
+                p_t4t->rw_length -= p_r_apdu->len;
+                p_t4t->rw_offset += p_r_apdu->len;
+              }
+            } else {
+              LOG(ERROR) << StringPrintf(
+                  "%s - invalid payload length (%d), rw_length (%d)", __func__,
+                  p_r_apdu->len, p_t4t->rw_length);
+              rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+              break;
+            }
+          } else if (*(p + 1) == 0x81) {
+            if (*(p + 2) <= 0xFD) {
+              p_r_apdu->len -= 3;
+              p_r_apdu->offset += 3;
+              /* Content read length coded over 1 byte in 2nd byte
+               * of BER-TLV length field */
+              DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+                  "%s - Content read length expected: 0x%02X, returned: 0x%02X",
+                  __func__, *(p + 2), p_r_apdu->len);
+              if (*(p + 2) == p_r_apdu->len) {
+                if ((p_r_apdu->len > 0) &&
+                    (p_r_apdu->len <= p_t4t->rw_length)) {
+                  p_t4t->rw_length -= p_r_apdu->len;
+                  p_t4t->rw_offset += p_r_apdu->len;
+                }
+              } else {
+                LOG(ERROR) << StringPrintf(
+                    "%s - invalid payload length (%d), rw_length "
+                    "(%d)",
+                    __func__, p_r_apdu->len, p_t4t->rw_length);
+                rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+                break;
+              }
+            } else {
+              LOG(ERROR) << StringPrintf(
+                  "%s - invalid DDO length content length received (1)",
+                  __func__);
+              rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+              break;
+            }
+          } else if (*(p + 1) == 0x82) {
+            /* Content read length coded over 2 bytes in 2nd and 3rd bytes
+             * of BER-TLV length field*/
+            r_apdu_len = (uint16_t)(*(p + 2) << 8);
+            r_apdu_len |= (uint8_t) * (p + 3);
+            if (r_apdu_len <= (p_t4t->max_read_size - 4)) {
+              p_r_apdu->len -= 4;
+              p_r_apdu->offset += 4;
+              DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+                  "%s - Content read length expected: 0x%02X%02X, returned: "
+                  "0x%02X%02X ",
+                  __func__, *(p + 3), *(p + 2), (uint8_t)(p_r_apdu->len >> 8),
+                  (uint8_t)p_r_apdu->len);
+              if (r_apdu_len == p_r_apdu->len) {
+                if ((p_r_apdu->len > 0) &&
+                    (p_r_apdu->len <= p_t4t->rw_length)) {
+                  p_t4t->rw_length -= p_r_apdu->len;
+                  p_t4t->rw_offset += p_r_apdu->len;
+                }
+              } else {
+                LOG(ERROR) << StringPrintf(
+                    "%s - invalid payload length (%d), rw_length "
+                    "(%d)",
+                    __func__, p_r_apdu->len, p_t4t->rw_length);
+                rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+                break;
+              }
             }
           } else {
-            p_t4t->state = RW_T4T_STATE_IDLE;
-
-            (*(rw_cb.p_cback))(RW_T4T_NDEF_READ_CPLT_EVT, &rw_data);
-
-            DLOG_IF(INFO, nfc_debug_enabled)
-                << StringPrintf("Sent RW_T4T_NDEF_READ_CPLT_EVT");
+            LOG(ERROR) << StringPrintf(
+                "%s - invalid DDO length content length received (2)",
+                __func__);
+            rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+            break;
           }
-
-          p_r_apdu = nullptr;
         } else {
-          p_t4t->rw_length = 0;
-          p_t4t->state = RW_T4T_STATE_IDLE;
+          LOG(ERROR) << StringPrintf("%s - invalid DDO tag", __func__);
+          rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+          break;
         }
+      } else if ((p_r_apdu->len > 0) && (p_r_apdu->len <= p_t4t->rw_length)) {
+        p_t4t->rw_length -= p_r_apdu->len;
+        p_t4t->rw_offset += p_r_apdu->len;
       } else {
         LOG(ERROR) << StringPrintf(
-            "invalid payload length (%d), rw_length "
+            "%s - invalid payload length (%d), rw_length "
             "(%d)",
-            p_r_apdu->len, p_t4t->rw_length);
+            __func__, p_r_apdu->len, p_t4t->rw_length);
         rw_t4t_handle_error(NFC_STATUS_BAD_RESP, 0, 0);
+        break;
+      }
+      if (rw_cb.p_cback) {
+        rw_data.data.status = NFC_STATUS_OK;
+        rw_data.data.p_data = p_r_apdu;
+
+        /* if need to read more data */
+        if (p_t4t->rw_length > 0) {
+          (*(rw_cb.p_cback))(RW_T4T_NDEF_READ_EVT, &rw_data);
+
+          if (!rw_t4t_read_file(p_t4t->rw_offset, p_t4t->rw_length, true)) {
+            rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
+          }
+        } else {
+          p_t4t->state = RW_T4T_STATE_IDLE;
+
+          (*(rw_cb.p_cback))(RW_T4T_NDEF_READ_CPLT_EVT, &rw_data);
+
+          DLOG_IF(INFO, nfc_debug_enabled)
+              << StringPrintf("%s - Sent RW_T4T_NDEF_READ_CPLT_EVT", __func__);
+        }
+
+        p_r_apdu = nullptr;
+      } else {
+        p_t4t->rw_length = 0;
+        p_t4t->state = RW_T4T_STATE_IDLE;
       }
       break;
 
     default:
-      LOG(ERROR) << StringPrintf("unknown sub_state = %d", p_t4t->sub_state);
+      LOG(ERROR) << StringPrintf("%s - unknown sub_state = %d", __func__,
+                                 p_t4t->sub_state);
       rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
       break;
   }
@@ -1560,8 +2038,8 @@
   tRW_DATA rw_data;
 
   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-      "sub_state:%s (%d)", rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(),
-      p_t4t->sub_state);
+      "%s - sub_state:%s (%d)", __func__,
+      rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(), p_t4t->sub_state);
 
   /* Get status words */
   p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
@@ -1593,8 +2071,8 @@
           rw_data.status = NFC_STATUS_OK;
 
           (*(rw_cb.p_cback))(RW_T4T_NDEF_UPDATE_CPLT_EVT, &rw_data);
-          DLOG_IF(INFO, nfc_debug_enabled)
-              << StringPrintf("Sent RW_T4T_NDEF_UPDATE_CPLT_EVT");
+          DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+              "%s - Sent RW_T4T_NDEF_UPDATE_CPLT_EVT", __func__);
         }
       }
       break;
@@ -1620,7 +2098,8 @@
       break;
 
     default:
-      LOG(ERROR) << StringPrintf("unknown sub_state = %d", p_t4t->sub_state);
+      LOG(ERROR) << StringPrintf("%s - unknown sub_state = %d", __func__,
+                                 p_t4t->sub_state);
       rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
       break;
   }
@@ -1642,8 +2121,8 @@
   tRW_DATA rw_data;
 
   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-      "sub_state:%s (%d)", rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(),
-      p_t4t->sub_state);
+      "%s - sub_state:%s (%d)", __func__,
+      rw_t4t_get_sub_state_name(p_t4t->sub_state).c_str(), p_t4t->sub_state);
 
   /* Get status words */
   p = (uint8_t*)(p_r_apdu + 1) + p_r_apdu->offset;
@@ -1687,13 +2166,14 @@
         rw_data.status = NFC_STATUS_OK;
 
         DLOG_IF(INFO, nfc_debug_enabled)
-            << StringPrintf("Sent RW_T4T_SET_TO_RO_EVT");
+            << StringPrintf("%s - Sent RW_T4T_SET_TO_RO_EVT", __func__);
         (*(rw_cb.p_cback))(RW_T4T_SET_TO_RO_EVT, &rw_data);
       }
       break;
 
     default:
-      LOG(ERROR) << StringPrintf("unknown sub_state = %d", p_t4t->sub_state);
+      LOG(ERROR) << StringPrintf("%s - unknown sub_state = %d", __func__,
+                                 p_t4t->sub_state);
       rw_t4t_handle_error(NFC_STATUS_FAILED, 0, 0);
       break;
   }
@@ -1757,7 +2237,8 @@
 
   uint8_t begin_state = p_t4t->state;
 
-  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("event = 0x%X", event);
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("%s - event = 0x%X", __func__, event);
   nfc_stop_quick_timer(&p_t4t->timer);
 
   switch (event) {
@@ -1794,8 +2275,8 @@
   }
 
   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-      "RW T4T state: <%s (%d)>", rw_t4t_get_state_name(p_t4t->state).c_str(),
-      p_t4t->state);
+      "%s - RW T4T state: <%s (%d)>", __func__,
+      rw_t4t_get_state_name(p_t4t->state).c_str(), p_t4t->state);
 
   if (p_t4t->state != RW_T4T_STATE_IDLE &&
       p_t4t->state != RW_T4T_STATE_PRESENCE_CHECK &&
@@ -1812,8 +2293,8 @@
       /* Unexpected R-APDU, it should be raw frame response */
       /* forward to upper layer without parsing */
       DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-          "RW T4T Raw Frame: Len [0x%X] Status [%s]", p_r_apdu->len,
-          NFC_GetStatusName(p_data->data.status).c_str());
+          "%s - RW T4T Raw Frame: Len [0x%X] Status [%s]", __func__,
+          p_r_apdu->len, NFC_GetStatusName(p_data->data.status).c_str());
       if (rw_cb.p_cback) {
         rw_data.raw_frame.status = p_data->data.status;
         rw_data.raw_frame.p_data = p_r_apdu;
@@ -1851,14 +2332,15 @@
       GKI_freebuf(p_r_apdu);
       break;
     default:
-      LOG(ERROR) << StringPrintf("invalid state=%d", p_t4t->state);
+      LOG(ERROR) << StringPrintf("%s - invalid state=%d", __func__,
+                                 p_t4t->state);
       GKI_freebuf(p_r_apdu);
       break;
   }
 
   if (begin_state != p_t4t->state) {
     DLOG_IF(INFO, nfc_debug_enabled)
-        << StringPrintf("RW T4T state changed:<%s> -> <%s>",
+        << StringPrintf("%s - RW T4T state changed:<%s> -> <%s>", __func__,
                         rw_t4t_get_state_name(begin_state).c_str(),
                         rw_t4t_get_state_name(p_t4t->state).c_str());
   }
@@ -1939,8 +2421,8 @@
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
   if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE) {
-    LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
-                               rw_cb.tcb.t4t.state);
+    LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+                               __func__, rw_cb.tcb.t4t.state);
     return NFC_STATUS_FAILED;
   }
 
@@ -1984,16 +2466,16 @@
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
   if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE) {
-    LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
-                               rw_cb.tcb.t4t.state);
+    LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+                               __func__, rw_cb.tcb.t4t.state);
     return NFC_STATUS_FAILED;
   }
 
   /* if NDEF has been detected */
   if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED) {
     /* start reading NDEF */
-    if (!rw_t4t_read_file(T4T_FILE_LENGTH_SIZE, rw_cb.tcb.t4t.ndef_length,
-                          false)) {
+    if (!rw_t4t_read_file(rw_cb.tcb.t4t.cc_file.ndef_fc.nlen_size,
+                          rw_cb.tcb.t4t.ndef_length, false)) {
       return NFC_STATUS_FAILED;
     }
 
@@ -2002,7 +2484,7 @@
 
     return NFC_STATUS_OK;
   } else {
-    LOG(ERROR) << StringPrintf("No NDEF detected");
+    LOG(ERROR) << StringPrintf("%s - No NDEF detected", __func__);
     return NFC_STATUS_FAILED;
   }
 }
@@ -2024,12 +2506,13 @@
 **                  NFC_STATUS_FAILED if T4T is busy or other error
 **
 *******************************************************************************/
-tNFC_STATUS RW_T4tUpdateNDef(uint16_t length, uint8_t* p_data) {
-  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("length:%d", length);
+tNFC_STATUS RW_T4tUpdateNDef(uint32_t length, uint8_t* p_data) {
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << StringPrintf("%s - length:%d", __func__, length);
 
   if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE) {
-    LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
-                               rw_cb.tcb.t4t.state);
+    LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+                               __func__, rw_cb.tcb.t4t.state);
     return NFC_STATUS_FAILED;
   }
 
@@ -2037,16 +2520,16 @@
   if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED) {
     /* if read-only */
     if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_READ_ONLY) {
-      LOG(ERROR) << StringPrintf("NDEF is read-only");
+      LOG(ERROR) << StringPrintf("%s - NDEF is read-only", __func__);
       return NFC_STATUS_FAILED;
     }
 
     if (rw_cb.tcb.t4t.cc_file.ndef_fc.max_file_size <
-        length + T4T_FILE_LENGTH_SIZE) {
+        length + rw_cb.tcb.t4t.cc_file.ndef_fc.nlen_size) {
       LOG(ERROR) << StringPrintf(
-          "data (%d bytes) plus NLEN is more than max file "
+          "%s - data (%d bytes) plus NLEN is more than max file "
           "size (%d)",
-          length, rw_cb.tcb.t4t.cc_file.ndef_fc.max_file_size);
+          __func__, length, rw_cb.tcb.t4t.cc_file.ndef_fc.max_file_size);
       return NFC_STATUS_FAILED;
     }
 
@@ -2054,7 +2537,7 @@
     rw_cb.tcb.t4t.ndef_length = length;
     rw_cb.tcb.t4t.p_update_data = p_data;
 
-    rw_cb.tcb.t4t.rw_offset = T4T_FILE_LENGTH_SIZE;
+    rw_cb.tcb.t4t.rw_offset = rw_cb.tcb.t4t.cc_file.ndef_fc.nlen_size;
     rw_cb.tcb.t4t.rw_length = length;
 
     /* set NLEN to 0x0000 for the first step */
@@ -2067,7 +2550,7 @@
 
     return NFC_STATUS_OK;
   } else {
-    LOG(ERROR) << StringPrintf("No NDEF detected");
+    LOG(ERROR) << StringPrintf("%s - No NDEF detected", __func__);
     return NFC_STATUS_FAILED;
   }
 }
@@ -2096,7 +2579,7 @@
   bool status;
   NFC_HDR* p_data;
 
-  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%d", option);
+  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s - %d", __func__, option);
 
   /* If RW_SelectTagType was not called (no conn_callback) return failure */
   if (!rw_cb.p_cback) {
@@ -2158,8 +2641,8 @@
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
   if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE) {
-    LOG(ERROR) << StringPrintf("Unable to start command at state (0x%X)",
-                               rw_cb.tcb.t4t.state);
+    LOG(ERROR) << StringPrintf("%s - Unable to start command at state (0x%X)",
+                               __func__, rw_cb.tcb.t4t.state);
     return NFC_STATUS_FAILED;
   }
 
@@ -2168,7 +2651,7 @@
     /* if read-only */
     if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_READ_ONLY) {
       DLOG_IF(INFO, nfc_debug_enabled)
-          << StringPrintf("NDEF is already read-only");
+          << StringPrintf("%s - NDEF is already read-only", __func__);
 
       evt_data.status = NFC_STATUS_OK;
       (*rw_cb.p_cback)(RW_T4T_SET_TO_RO_EVT, &evt_data);
@@ -2185,7 +2668,7 @@
 
     return NFC_STATUS_OK;
   } else {
-    LOG(ERROR) << StringPrintf("No NDEF detected");
+    LOG(ERROR) << StringPrintf("%s - No NDEF detected", __func__);
     return NFC_STATUS_FAILED;
   }
   return (retval);
@@ -2268,6 +2751,8 @@
       return "WAIT_WRITE_CC";
     case RW_T4T_SUBSTATE_WAIT_WRITE_NDEF:
       return "WAIT_WRITE_NDEF";
+    case RW_T4T_SUBSTATE_WAIT_ENDEF_FILE_CTRL_TLV:
+      return "WAIT_ENDEF_FILE_CTRL_TLV";
     default:
       return "???? UNKNOWN SUBSTATE";
   }
diff --git a/src/nfc/tags/rw_t5t.cc b/src/nfc/tags/rw_t5t.cc
new file mode 100644
index 0000000..06df3c9
--- /dev/null
+++ b/src/nfc/tags/rw_t5t.cc
@@ -0,0 +1,865 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2020 STMicroelectronics
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains the implementation for specific NFC Forum T5T operations
+ *  in Reader/Writer mode.
+ *
+ ******************************************************************************/
+
+#include <log/log.h>
+#include <string.h>
+
+#include <android-base/stringprintf.h>
+#include <base/logging.h>
+
+#include "nfc_target.h"
+
+#include "bt_types.h"
+#include "nfc_api.h"
+#include "nfc_int.h"
+#include "rw_api.h"
+#include "rw_int.h"
+
+using android::base::StringPrintf;
+
+extern void rw_i93_handle_error(tNFC_STATUS);
+extern tNFC_STATUS rw_i93_get_next_blocks(uint16_t);
+extern tNFC_STATUS rw_i93_send_cmd_read_single_block(uint16_t, bool);
+extern tNFC_STATUS rw_i93_send_cmd_write_single_block(uint16_t, uint8_t*);
+extern tNFC_STATUS rw_i93_send_cmd_lock_block(uint16_t);
+
+extern bool nfc_debug_enabled;
+
+/*******************************************************************************
+**
+** Function         rw_t5t_sm_detect_ndef
+**
+** Description      Process NDEF detection procedure
+**
+**                  1. Get UID if not having yet
+**                  2. Get System Info if not having yet
+**                  3. Read first block for CC
+**                  4. Search NDEF Type and length
+**                  5. Get block status to get max NDEF size and read-only
+**                     status
+**
+** Returns          void
+**
+*******************************************************************************/
+void rw_t5t_sm_detect_ndef(NFC_HDR* p_resp) {
+  uint8_t* p = (uint8_t*)(p_resp + 1) + p_resp->offset;
+  uint8_t flags, cc[8];
+  uint32_t t5t_area_len = 0;
+  uint16_t length = p_resp->len, xx;
+  tRW_I93_CB* p_i93 = &rw_cb.tcb.i93;
+  tRW_DATA rw_data;
+  tNFC_STATUS status = NFC_STATUS_FAILED;
+
+  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+      "%s - sub_state:%s (0x%x)", __func__,
+      rw_i93_get_sub_state_name(p_i93->sub_state).c_str(), p_i93->sub_state);
+
+  if (length == 0) {
+    android_errorWriteLog(0x534e4554, "121260197");
+    rw_i93_handle_error(NFC_STATUS_FAILED);
+    return;
+  }
+  STREAM_TO_UINT8(flags, p);
+  length--;
+
+  if (flags & I93_FLAG_ERROR_DETECTED) {
+    DLOG_IF(INFO, nfc_debug_enabled)
+        << StringPrintf("%s - Got error flags (0x%02x)", __func__, flags);
+    rw_i93_handle_error(NFC_STATUS_FAILED);
+    return;
+  }
+
+  switch (p_i93->sub_state) {
+    case RW_I93_SUBSTATE_WAIT_CC_EXT:
+
+      /* assume block size is 4 */
+      STREAM_TO_ARRAY(cc, p, 4);
+
+      status = NFC_STATUS_FAILED;
+
+      /*
+      ** Capability Container (CC) second block
+      **
+      ** CC[4] : RFU
+      ** CC[5] : RFU
+      ** CC[6] : MSB MLEN
+      ** CC[7] : LSB MLEN
+      */
+
+      DLOG_IF(INFO, nfc_debug_enabled)
+          << StringPrintf("%s - cc[4-7]: 0x%02X 0x%02X 0x%02X 0x%02X", __func__,
+                          cc[0], cc[1], cc[2], cc[3]);
+
+      /* T5T_Area length = 8 * MLEN */
+      /* CC is 8-byte, MLEN is defined by bytes 6 & 7 */
+      t5t_area_len = cc[3] + (cc[2] << 8);
+      t5t_area_len <<= 3;
+      p_i93->max_ndef_length = t5t_area_len;
+
+      p_i93->t5t_area_last_offset = t5t_area_len + 8 - 1;
+      memcpy((uint8_t*)&rw_cb.tcb.i93.gre_cc_content[4], (uint8_t*)cc, 4);
+      p_i93->num_block = t5t_area_len / p_i93->block_size;
+      p_i93->t5t_area_start_block = 2;
+
+      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+          "%s - T5T Area size:%d, Nb blocks:0x%04X, Block size:0x%02X, "
+          "T5T Area last offset:%d",
+          __func__, t5t_area_len, p_i93->num_block, p_i93->block_size,
+          p_i93->t5t_area_last_offset);
+
+      status = NFC_STATUS_OK;
+
+      /* search NDEF TLV from offset 8 when CC file coded on 8 bytes NFC Forum
+       */
+      p_i93->rw_offset = 8;
+
+      if (p_i93->gre_cc_content[0] == I93_ICODE_CC_MAGIC_NUMER_E2) {
+        p_i93->intl_flags |= RW_I93_FLAG_EXT_COMMANDS;
+      }
+
+      if (rw_i93_get_next_blocks(p_i93->rw_offset) == NFC_STATUS_OK) {
+        p_i93->sub_state = RW_I93_SUBSTATE_SEARCH_NDEF_TLV;
+        p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_TYPE;
+      } else {
+        rw_i93_handle_error(NFC_STATUS_FAILED);
+      }
+      break;
+
+    case RW_I93_SUBSTATE_WAIT_CC:
+
+      if (length < RW_I93_CC_SIZE) {
+        android_errorWriteLog(0x534e4554, "139188579");
+        rw_i93_handle_error(NFC_STATUS_FAILED);
+        return;
+      }
+
+      /* assume block size is more than RW_I93_CC_SIZE 4 */
+      STREAM_TO_ARRAY(cc, p, RW_I93_CC_SIZE);
+
+      status = NFC_STATUS_FAILED;
+
+      /*
+      ** Capability Container (CC)
+      **
+      ** CC[0] : magic number (0xE1)
+      ** CC[1] : Bit 7-6:Major version number
+      **       : Bit 5-4:Minor version number
+      **       : Bit 3-2:Read access condition (00b: read access granted
+      **         without any security)
+      **       : Bit 1-0:Write access condition (00b: write access granted
+      **         without any security)
+      ** CC[2] : Memory size in 8 bytes (Ex. 0x04 is 32 bytes) [STM, set to
+      **         0xFF if more than 2040bytes]
+      ** CC[3] : Bit 0:Read multiple blocks is supported [NXP, STM]
+      **       : Bit 1:Inventory page read is supported [NXP]
+      **       : Bit 2:More than 2040 bytes are supported [STM]
+      */
+
+      DLOG_IF(INFO, nfc_debug_enabled)
+          << StringPrintf("%s - cc[0-3]: 0x%02X 0x%02X 0x%02X 0x%02X", __func__,
+                          cc[0], cc[1], cc[2], cc[3]);
+
+      if ((cc[0] == I93_ICODE_CC_MAGIC_NUMER_E1) ||
+          (cc[0] == I93_ICODE_CC_MAGIC_NUMER_E2)) {
+        if ((cc[1] & 0xC0) > I93_VERSION_1_x) {
+          DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+              "%s - Major mapping version above 1 %d.x", __func__, cc[1] >> 6);
+          /* major mapping version above 1 not supported */
+          rw_i93_handle_error(NFC_STATUS_FAILED);
+          break;
+        }
+
+        if ((cc[1] & I93_ICODE_CC_READ_ACCESS_MASK) ==
+            I93_ICODE_CC_READ_ACCESS_GRANTED) {
+          if ((cc[1] & I93_ICODE_CC_WRITE_ACCESS_MASK) !=
+              I93_ICODE_CC_WRITE_ACCESS_GRANTED) {
+            /* read-only or password required to write */
+            p_i93->intl_flags |= RW_I93_FLAG_READ_ONLY;
+          }
+          if (cc[3] & I93_ICODE_CC_MBREAD_MASK) {
+            /* tag supports read multiple blocks command */
+            p_i93->intl_flags |= RW_I93_FLAG_READ_MULTI_BLOCK;
+          }
+
+          if (cc[3] & I93_ICODE_CC_SPECIAL_FRAME_MASK) {
+            /* tag supports Special Frame for Write-Alike commands */
+            p_i93->intl_flags |= RW_I93_FLAG_SPECIAL_FRAME;
+          }
+
+          /* get block size from length of the first READ_SINGLE_BLOCK response
+           */
+          if (length == I93_BLEN_4BYTES)
+            p_i93->block_size = I93_BLEN_4BYTES;
+          else if (length == I93_BLEN_8BYTES)
+            p_i93->block_size = I93_BLEN_8BYTES;
+          else if (length == I93_BLEN_16BYTES)
+            p_i93->block_size = I93_BLEN_16BYTES;
+          else if (length == I93_BLEN_32BYTES)
+            p_i93->block_size = I93_BLEN_32BYTES;
+          else {
+            rw_i93_handle_error(NFC_STATUS_FAILED);
+            break;
+          }
+
+          /* T5T_Area length = 8 * MLEN */
+          if (cc[2] == 0) {
+            /* CC is 8-byte, MLEN is defined by bytes 6 & 7 */
+            if (length >= I93_BLEN_8BYTES) {
+              STREAM_TO_ARRAY(&cc[4], p, 4);
+              DLOG_IF(INFO, nfc_debug_enabled)
+                  << StringPrintf("%s - cc[4-7]: 0x%02X 0x%02X 0x%02X 0x%02X",
+                                  __func__, cc[4], cc[5], cc[6], cc[7]);
+              t5t_area_len = cc[7] + (cc[6] << 8);
+              t5t_area_len <<= 3;
+
+              p_i93->t5t_area_last_offset = t5t_area_len + 8 - 1;
+              p_i93->max_ndef_length = t5t_area_len;
+              p_i93->t5t_area_start_block = 1;
+
+              memcpy(p_i93->gre_cc_content, cc, 8);
+            } else {
+              /* require an additional read to get the second half of the
+               * CC from block 1 */
+              if (rw_i93_send_cmd_read_single_block(0x0001, false) ==
+                  NFC_STATUS_OK) {
+                p_i93->sub_state = RW_I93_SUBSTATE_WAIT_CC_EXT;
+              } else {
+                rw_i93_handle_error(NFC_STATUS_FAILED);
+              }
+              memcpy(p_i93->gre_cc_content, cc, 4);
+              break;
+            }
+          } else {
+            /* CC is 4-byte, MLEN is defined by byte 2 */
+            t5t_area_len = cc[2] << 3;
+            p_i93->t5t_area_last_offset = t5t_area_len + 4 - 1;
+            p_i93->t5t_area_start_block = 1;
+
+            memcpy(p_i93->gre_cc_content, cc, 4);
+          }
+
+          p_i93->num_block = t5t_area_len / p_i93->block_size;
+
+          p_i93->max_ndef_length = t5t_area_len;
+
+          if (cc[0] == I93_ICODE_CC_MAGIC_NUMER_E2) {
+            /* can only be done here if CC is coded over 4 bytes */
+            p_i93->intl_flags |= RW_I93_FLAG_EXT_COMMANDS;
+          }
+
+          DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+              "%s - T5T Area size:%d, Nb blocks:0x%04X, "
+              "Block size:0x%02X, T5T Area last offset:%d",
+              __func__, t5t_area_len, p_i93->num_block, p_i93->block_size,
+              p_i93->t5t_area_last_offset);
+
+          status = NFC_STATUS_OK;
+        }
+      }
+
+      if (status == NFC_STATUS_OK) {
+        /* search NDEF TLV from offset 4 when CC file coded on 4 bytes
+         * NFC Forum during the next block reading, if CC file is coded
+         * on more than 4 bytes, start searching for NDEF TLV in the current
+         * block read except if the CC
+         */
+        if (cc[2] == 0) {
+          /* 8-byte CC length */
+          p_i93->rw_offset = 8;
+
+          if (length > I93_BLEN_8BYTES) {
+            /* Rest of the block contains T5T_Area, look for NDEF TLV */
+            p_i93->sub_state = RW_I93_SUBSTATE_SEARCH_NDEF_TLV;
+            p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_TYPE;
+            /* start TLV search after CC in the first block */
+          } else {
+            /* 8-byte block length, NDEF TLV search must continue
+             * in the next block */
+            if (rw_i93_get_next_blocks(p_i93->rw_offset) == NFC_STATUS_OK) {
+              p_i93->sub_state = RW_I93_SUBSTATE_SEARCH_NDEF_TLV;
+              p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_TYPE;
+            } else {
+              rw_i93_handle_error(NFC_STATUS_FAILED);
+            }
+            break;
+          }
+        } else {
+          /* 4-byte CC length */
+          p_i93->rw_offset = 4;
+
+          if (length > I93_BLEN_4BYTES) {
+            /* Rest of the block contains T5T_Area, look for NDEF TLV */
+            p_i93->sub_state = RW_I93_SUBSTATE_SEARCH_NDEF_TLV;
+            p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_TYPE;
+            /* start TLV search after CC in the first block */
+          } else {
+            if (rw_i93_get_next_blocks(p_i93->rw_offset) == NFC_STATUS_OK) {
+              p_i93->sub_state = RW_I93_SUBSTATE_SEARCH_NDEF_TLV;
+              p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_TYPE;
+            } else {
+              rw_i93_handle_error(NFC_STATUS_FAILED);
+            }
+            break;
+          }
+        }
+      } else {
+        rw_i93_handle_error(NFC_STATUS_FAILED);
+        break;
+      }
+
+      FALLTHROUGH_INTENDED;
+
+    case RW_I93_SUBSTATE_SEARCH_NDEF_TLV:
+      /* search TLV within read blocks */
+      for (xx = 0; xx < length; xx++) {
+        /* if looking for type */
+        if (p_i93->tlv_detect_state == RW_I93_TLV_DETECT_STATE_TYPE) {
+          if (*(p + xx) == I93_ICODE_TLV_TYPE_NDEF) {
+            /* store found type and get length field */
+            p_i93->tlv_type = *(p + xx);
+            p_i93->ndef_tlv_start_offset = p_i93->rw_offset + xx;
+
+            p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_LENGTH_1;
+
+          } else if (*(p + xx) == I93_ICODE_TLV_TYPE_TERM) {
+            /* no NDEF TLV found */
+            p_i93->tlv_type = I93_ICODE_TLV_TYPE_TERM;
+            break;
+          } else {
+            /* TLV with Tag field set as RFU are not interpreted */
+            p_i93->tlv_type = *(p + xx);
+            p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_LENGTH_1;
+          }
+        } else if (p_i93->tlv_detect_state ==
+                   RW_I93_TLV_DETECT_STATE_LENGTH_1) {
+          /* if 3 bytes length field */
+          if (*(p + xx) == 0xFF) {
+            /* need 2 more bytes for length field */
+            p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_LENGTH_2;
+          } else {
+            p_i93->tlv_length = *(p + xx);
+            p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_VALUE;
+
+            if (p_i93->tlv_type == I93_ICODE_TLV_TYPE_NDEF) {
+              p_i93->ndef_tlv_last_offset =
+                  p_i93->ndef_tlv_start_offset + 1 + p_i93->tlv_length;
+              break;
+            }
+          }
+        } else if (p_i93->tlv_detect_state ==
+                   RW_I93_TLV_DETECT_STATE_LENGTH_2) {
+          /* the second byte of 3 bytes length field */
+          p_i93->tlv_length = *(p + xx);
+          p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_LENGTH_3;
+
+        } else if (p_i93->tlv_detect_state ==
+                   RW_I93_TLV_DETECT_STATE_LENGTH_3) {
+          /* the last byte of 3 bytes length field */
+          p_i93->tlv_length = (p_i93->tlv_length << 8) + *(p + xx);
+          p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_VALUE;
+
+          if (p_i93->tlv_type == I93_ICODE_TLV_TYPE_NDEF) {
+            p_i93->ndef_tlv_last_offset =
+                p_i93->ndef_tlv_start_offset + 3 + p_i93->tlv_length;
+            break;
+          }
+        } else if (p_i93->tlv_detect_state == RW_I93_TLV_DETECT_STATE_VALUE) {
+          /* this is other than NDEF TLV */
+          if (p_i93->tlv_length <= length - xx) {
+            /* skip value field */
+            xx += (uint8_t)p_i93->tlv_length - 1;
+            p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_TYPE;
+          } else {
+            /* read more data */
+            p_i93->tlv_length -= (length - xx);
+            break;
+          }
+        }
+      }
+
+      /* found NDEF TLV and read length field */
+      if ((p_i93->tlv_type == I93_ICODE_TLV_TYPE_NDEF) &&
+          (p_i93->tlv_detect_state == RW_I93_TLV_DETECT_STATE_VALUE)) {
+        p_i93->ndef_length = p_i93->tlv_length;
+
+        rw_data.ndef.status = NFC_STATUS_OK;
+        rw_data.ndef.protocol = NFC_PROTOCOL_T5T;
+        rw_data.ndef.flags = 0;
+        rw_data.ndef.flags |= RW_NDEF_FL_SUPPORTED;
+        rw_data.ndef.flags |= RW_NDEF_FL_FORMATED;  // NOTYPO
+        rw_data.ndef.flags |= RW_NDEF_FL_FORMATABLE;
+        rw_data.ndef.cur_size = p_i93->ndef_length;
+
+        if (p_i93->intl_flags & RW_I93_FLAG_READ_ONLY) {
+          rw_data.ndef.flags |= RW_NDEF_FL_READ_ONLY;
+          rw_data.ndef.max_size = p_i93->ndef_length;
+        } else {
+          rw_data.ndef.flags |= RW_NDEF_FL_HARD_LOCKABLE;
+          /* Assume tag is already in INITIALIZED or READ-WRITE state */
+          p_i93->max_ndef_length =
+              p_i93->t5t_area_last_offset - p_i93->ndef_tlv_start_offset + 1;
+          if (p_i93->max_ndef_length >= 0xFF) {
+            /* 3 bytes length field can be used */
+            p_i93->max_ndef_length -= 4;
+          } else {
+            /* 1 byte length field can be used */
+            p_i93->max_ndef_length -= 2;
+          }
+          rw_data.ndef.max_size = p_i93->max_ndef_length;
+        }
+
+        /* Complete the greedy collection */
+        p_i93->gre_ndef_tlv_pos = p_i93->ndef_tlv_start_offset;
+        p_i93->gre_ndef_tlv_length = p_i93->ndef_length;
+        p_i93->gre_validity = 1;
+        p_i93->state = RW_I93_STATE_IDLE;
+        p_i93->sent_cmd = 0;
+
+        DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+            "%s - NDEF cur_size (%d), max_size (%d), flags (0x%x)", __func__,
+            rw_data.ndef.cur_size, rw_data.ndef.max_size, rw_data.ndef.flags);
+
+        (*(rw_cb.p_cback))(RW_I93_NDEF_DETECT_EVT, &rw_data);
+        break;
+      } else {
+        /* read more data */
+        p_i93->rw_offset += length;
+
+        if (p_i93->rw_offset > p_i93->t5t_area_last_offset) {
+          rw_i93_handle_error(NFC_STATUS_FAILED);
+        } else {
+          if (rw_i93_get_next_blocks(p_i93->rw_offset) == NFC_STATUS_OK) {
+            p_i93->sub_state = RW_I93_SUBSTATE_SEARCH_NDEF_TLV;
+          } else {
+            rw_i93_handle_error(NFC_STATUS_FAILED);
+          }
+        }
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+/*******************************************************************************
+**
+** Function         rw_t5t_sm_update_ndef
+**
+** Description      Process NDEF update procedure
+**
+**                  1. Set length field to zero
+**                  2. Write NDEF and Terminator TLV
+**                  3. Set length field to NDEF length
+**
+** Returns          void
+**
+*******************************************************************************/
+void rw_t5t_sm_update_ndef(NFC_HDR* p_resp) {
+  uint8_t* p = (uint8_t*)(p_resp + 1) + p_resp->offset;
+  uint8_t flags, xx, buff[I93_MAX_BLOCK_LENGH];
+  uint16_t length_offset;
+  uint16_t length = p_resp->len, block_number;
+  tRW_I93_CB* p_i93 = &rw_cb.tcb.i93;
+  tRW_DATA rw_data;
+
+  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+      "%s - sub_state:%s (0x%x)", __func__,
+      rw_i93_get_sub_state_name(p_i93->sub_state).c_str(), p_i93->sub_state);
+
+  if (length == 0 || p_i93->block_size > I93_MAX_BLOCK_LENGH) {
+    android_errorWriteLog(0x534e4554, "122320256");
+    rw_i93_handle_error(NFC_STATUS_FAILED);
+    return;
+  }
+
+  STREAM_TO_UINT8(flags, p);
+  length--;
+
+  if (flags & I93_FLAG_ERROR_DETECTED) {
+    DLOG_IF(INFO, nfc_debug_enabled)
+        << StringPrintf("%s - Got error flags (0x%02x)", __func__, flags);
+    rw_i93_handle_error(NFC_STATUS_FAILED);
+    return;
+  }
+
+  switch (p_i93->sub_state) {
+    case RW_I93_SUBSTATE_RESET_LEN:
+
+      /* get offset of length field */
+      length_offset = (p_i93->ndef_tlv_start_offset + 1) % p_i93->block_size;
+
+      if (length < length_offset) {
+        android_errorWriteLog(0x534e4554, "122320256");
+        rw_i93_handle_error(NFC_STATUS_FAILED);
+        return;
+      }
+
+      /* set length to zero */
+      *(p + length_offset) = 0x00;
+
+      if (p_i93->ndef_length > 0) {
+        /* if 3 bytes length field is needed */
+        if (p_i93->ndef_length >= 0xFF) {
+          xx = length_offset + 3;
+        } else {
+          xx = length_offset + 1;
+        }
+
+        if (p_i93->ndef_length >= 0xFF) {
+          p_i93->ndef_tlv_last_offset = p_i93->ndef_tlv_start_offset + 3;
+        } else {
+          p_i93->ndef_tlv_last_offset = p_i93->ndef_tlv_start_offset + 1;
+        }
+
+        /* write the first part of NDEF in the same block */
+        for (; xx < p_i93->block_size; xx++) {
+          if (xx > length || p_i93->rw_length > p_i93->ndef_length) {
+            android_errorWriteLog(0x534e4554, "122320256");
+            rw_i93_handle_error(NFC_STATUS_FAILED);
+            return;
+          }
+          if (p_i93->rw_length < p_i93->ndef_length) {
+            *(p + xx) = *(p_i93->p_update_data + p_i93->rw_length++);
+            p_i93->ndef_tlv_last_offset++;
+          } else {
+            *(p + xx) = I93_ICODE_TLV_TYPE_NULL;
+          }
+        }
+      }
+
+      block_number = (p_i93->ndef_tlv_start_offset + 1) / p_i93->block_size;
+
+      if (rw_i93_send_cmd_write_single_block(block_number, p) ==
+          NFC_STATUS_OK) {
+        /* update next writing offset */
+        p_i93->rw_offset = (block_number + 1) * p_i93->block_size;
+        p_i93->sub_state = RW_I93_SUBSTATE_WRITE_NDEF;
+      } else {
+        rw_i93_handle_error(NFC_STATUS_FAILED);
+      }
+      break;
+
+    case RW_I93_SUBSTATE_WRITE_NDEF:
+
+      /* if it's not the end of tag memory */
+      if (p_i93->rw_offset <= p_i93->t5t_area_last_offset) {
+        // Note: Needed to write in the last block of the memory
+        block_number = p_i93->rw_offset / p_i93->block_size;
+
+        /* if we have more data to write */
+        if (p_i93->rw_length < p_i93->ndef_length) {
+          p = p_i93->p_update_data + p_i93->rw_length;
+
+          p_i93->rw_offset += p_i93->block_size;
+          p_i93->rw_length += p_i93->block_size;
+
+          /* if this is the last block of NDEF TLV */
+          if (p_i93->rw_length >= p_i93->ndef_length) {
+            /* length of NDEF TLV in the block */
+            xx = (uint8_t)(p_i93->block_size -
+                           (p_i93->rw_length - p_i93->ndef_length));
+            /* set NULL TLV in the unused part of block */
+            memset(buff, I93_ICODE_TLV_TYPE_NULL, p_i93->block_size);
+            memcpy(buff, p, xx);
+            p = buff;
+
+            /* if it's the end of tag memory */
+            if (((p_i93->rw_offset - p_i93->block_size + xx) <=
+                 p_i93->t5t_area_last_offset) &&
+                (xx < p_i93->block_size)) {
+              buff[xx] = I93_ICODE_TLV_TYPE_TERM;
+            }
+            // Note: Needed to write Terminator TLV in block following
+            // the NDEF Message ending in byte 3 of the previous block
+            p_i93->ndef_tlv_last_offset =
+                p_i93->rw_offset - p_i93->block_size + xx - 1;
+
+          } else {
+            p_i93->ndef_tlv_last_offset += p_i93->block_size;
+          }
+
+          if (rw_i93_send_cmd_write_single_block(block_number, p) !=
+              NFC_STATUS_OK) {
+            rw_i93_handle_error(NFC_STATUS_FAILED);
+          }
+        } else {
+          /* if this is the very next block of NDEF TLV */
+          // Note: Needed to write Terminator TLV in block following
+          // the NDEF Message ending in byte 3 of the previous block
+          if ((block_number ==
+               (p_i93->ndef_tlv_last_offset / p_i93->block_size) + 1) &&
+              (((p_i93->ndef_tlv_last_offset + 1) % p_i93->block_size) == 0)) {
+            /* write Terminator TLV and NULL TLV */
+            memset(buff, I93_ICODE_TLV_TYPE_NULL, p_i93->block_size);
+            buff[0] = I93_ICODE_TLV_TYPE_TERM;
+            p = buff;
+
+            if (rw_i93_send_cmd_write_single_block(block_number, p) !=
+                NFC_STATUS_OK) {
+              rw_i93_handle_error(NFC_STATUS_FAILED);
+            }
+
+            block_number =
+                (p_i93->ndef_tlv_start_offset + 1) / p_i93->block_size;
+
+            /* set offset to length field */
+            p_i93->rw_offset = p_i93->ndef_tlv_start_offset + 1;
+
+            /* get size of length field */
+            if (p_i93->ndef_length >= 0xFF) {
+              p_i93->rw_length = 3;
+            } else if (p_i93->ndef_length > 0) {
+              p_i93->rw_length = 1;
+            } else {
+              p_i93->rw_length = 0;
+            }
+            p_i93->sub_state = RW_I93_SUBSTATE_UPDATE_LEN;
+
+          } else {
+            /* finished writing NDEF and Terminator TLV */
+            /* read length field to update length       */
+            block_number =
+                (p_i93->ndef_tlv_start_offset + 1) / p_i93->block_size;
+
+            if (rw_i93_send_cmd_read_single_block(block_number, false) ==
+                NFC_STATUS_OK) {
+              /* set offset to length field */
+              p_i93->rw_offset = p_i93->ndef_tlv_start_offset + 1;
+
+              /* get size of length field */
+              if (p_i93->ndef_length >= 0xFF) {
+                p_i93->rw_length = 3;
+              } else if (p_i93->ndef_length > 0) {
+                p_i93->rw_length = 1;
+              } else {
+                p_i93->rw_length = 0;
+              }
+              p_i93->sub_state = RW_I93_SUBSTATE_UPDATE_LEN;
+            } else {
+              rw_i93_handle_error(NFC_STATUS_FAILED);
+            }
+          }
+        }
+      } /* (p_i93->rw_offset <= p_i93->t5t_area_last_offset) */
+
+      else {
+        /* if we have no more data to write */
+        if (p_i93->rw_length >= p_i93->ndef_length) {
+          /* finished writing NDEF and Terminator TLV */
+          /* read length field to update length       */
+          block_number = (p_i93->ndef_tlv_start_offset + 1) / p_i93->block_size;
+
+          if (rw_i93_send_cmd_read_single_block(block_number, false) ==
+              NFC_STATUS_OK) {
+            /* set offset to length field */
+            p_i93->rw_offset = p_i93->ndef_tlv_start_offset + 1;
+
+            /* get size of length field */
+            if (p_i93->ndef_length >= 0xFF) {
+              p_i93->rw_length = 3;
+            } else if (p_i93->ndef_length > 0) {
+              p_i93->rw_length = 1;
+            } else {
+              p_i93->rw_length = 0;
+            }
+
+            p_i93->sub_state = RW_I93_SUBSTATE_UPDATE_LEN;
+            break;
+          }
+        }
+        rw_i93_handle_error(NFC_STATUS_FAILED);
+      }
+      break;
+
+    case RW_I93_SUBSTATE_UPDATE_LEN:
+      /* if we have more length field to write */
+      if (p_i93->rw_length > 0) {
+        /* if we got ack for writing, read next block to update rest of length
+         * field */
+        if (length == 0) {
+          block_number = p_i93->rw_offset / p_i93->block_size;
+
+          if (rw_i93_send_cmd_read_single_block(block_number, false) !=
+              NFC_STATUS_OK) {
+            rw_i93_handle_error(NFC_STATUS_FAILED);
+          }
+        } else {
+          length_offset = p_i93->rw_offset % p_i93->block_size;
+
+          /* update length field within the read block */
+          for (xx = length_offset; xx < p_i93->block_size; xx++) {
+            if (xx > length) {
+              android_errorWriteLog(0x534e4554, "122320256");
+              rw_i93_handle_error(NFC_STATUS_FAILED);
+              return;
+            }
+
+            if (p_i93->rw_length == 3)
+              *(p + xx) = 0xFF;
+            else if (p_i93->rw_length == 2)
+              *(p + xx) = (uint8_t)((p_i93->ndef_length >> 8) & 0xFF);
+            else if (p_i93->rw_length == 1)
+              *(p + xx) = (uint8_t)(p_i93->ndef_length & 0xFF);
+
+            p_i93->rw_length--;
+            if (p_i93->rw_length == 0) break;
+          }
+
+          block_number = (p_i93->rw_offset / p_i93->block_size);
+
+          if (rw_i93_send_cmd_write_single_block(block_number, p) ==
+              NFC_STATUS_OK) {
+            /* set offset to the beginning of next block */
+            p_i93->rw_offset +=
+                p_i93->block_size - (p_i93->rw_offset % p_i93->block_size);
+          } else {
+            rw_i93_handle_error(NFC_STATUS_FAILED);
+          }
+        }
+      } else {
+        DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+            "%s - NDEF update complete, %d bytes, (%d-%d)", __func__,
+            p_i93->ndef_length, p_i93->ndef_tlv_start_offset,
+            p_i93->ndef_tlv_last_offset);
+
+        p_i93->state = RW_I93_STATE_IDLE;
+        p_i93->sent_cmd = 0;
+        p_i93->p_update_data = nullptr;
+
+        rw_data.status = NFC_STATUS_OK;
+        (*(rw_cb.p_cback))(RW_I93_NDEF_UPDATE_CPLT_EVT, &rw_data);
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+/*******************************************************************************
+**
+** Function         rw_i93_sm_set_read_only
+**
+** Description      Process read-only procedure
+**
+**                  1. Update CC as read-only
+**                  2. Lock all block of NDEF TLV
+**                  3. Lock block of CC
+**
+** Returns          void
+**
+*******************************************************************************/
+void rw_t5t_sm_set_read_only(NFC_HDR* p_resp) {
+  uint8_t* p = (uint8_t*)(p_resp + 1) + p_resp->offset;
+  uint16_t block_number;
+  uint8_t flags;
+
+  uint16_t length = p_resp->len;
+  tRW_I93_CB* p_i93 = &rw_cb.tcb.i93;
+  tRW_DATA rw_data;
+
+  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+      "%s - sub_state:%s (0x%x)", __func__,
+      rw_i93_get_sub_state_name(p_i93->sub_state).c_str(), p_i93->sub_state);
+
+  if (length == 0) {
+    android_errorWriteLog(0x534e4554, "122322613");
+    rw_i93_handle_error(NFC_STATUS_FAILED);
+    return;
+  }
+
+  STREAM_TO_UINT8(flags, p);
+  length--;
+
+  if (flags & I93_FLAG_ERROR_DETECTED) {
+    DLOG_IF(INFO, nfc_debug_enabled)
+        << StringPrintf("%s - Got error flags (0x%02x)", __func__, flags);
+    rw_i93_handle_error(NFC_STATUS_FAILED);
+    return;
+  }
+
+  switch (p_i93->sub_state) {
+    case RW_I93_SUBSTATE_WAIT_CC:
+
+      if (length < RW_I93_CC_SIZE) {
+        android_errorWriteLog(0x534e4554, "139188579");
+        rw_i93_handle_error(NFC_STATUS_FAILED);
+        return;
+      }
+      /* mark CC as read-only */
+      *(p + 1) |= I93_ICODE_CC_READ_ONLY;
+
+      if (rw_i93_send_cmd_write_single_block(0, p) == NFC_STATUS_OK) {
+        p_i93->sub_state = RW_I93_SUBSTATE_WAIT_UPDATE_CC;
+      } else {
+        rw_i93_handle_error(NFC_STATUS_FAILED);
+      }
+      break;
+
+    case RW_I93_SUBSTATE_WAIT_UPDATE_CC:
+
+      /* successfully write CC then lock CC and all blocks of T5T Area */
+      p_i93->rw_offset = 0;
+
+      if (rw_i93_send_cmd_lock_block(0) == NFC_STATUS_OK) {
+        p_i93->rw_offset += p_i93->block_size;
+        p_i93->sub_state = RW_I93_SUBSTATE_LOCK_T5T_AREA;
+      } else {
+        rw_i93_handle_error(NFC_STATUS_FAILED);
+      }
+      break;
+
+    case RW_I93_SUBSTATE_LOCK_T5T_AREA:
+
+      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+          "%s - rw_offset:0x%02x, t5t_area_last_offset:0x%02x", __func__,
+          p_i93->rw_offset, p_i93->t5t_area_last_offset);
+
+      /* 2nd block to be locked can be the last 4 bytes of CC in case CC
+       * is 8byte long, then T5T_Area starts */
+      if (p_i93->rw_offset <= p_i93->t5t_area_last_offset) {
+        /* get the next block of NDEF TLV */
+        block_number = (uint16_t)(p_i93->rw_offset / p_i93->block_size);
+
+        if (rw_i93_send_cmd_lock_block(block_number) == NFC_STATUS_OK) {
+          p_i93->rw_offset += p_i93->block_size;
+        } else {
+          rw_i93_handle_error(NFC_STATUS_FAILED);
+        }
+      } else {
+        p_i93->intl_flags |= RW_I93_FLAG_READ_ONLY;
+        p_i93->state = RW_I93_STATE_IDLE;
+        p_i93->sent_cmd = 0;
+
+        rw_data.status = NFC_STATUS_OK;
+        (*(rw_cb.p_cback))(RW_I93_SET_TAG_RO_EVT, &rw_data);
+      }
+      break;
+
+    default:
+      break;
+  }
+}
diff --git a/utils/Android.bp b/utils/Android.bp
index e8021aa..d8a5e9d 100644
--- a/utils/Android.bp
+++ b/utils/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "system_nfc_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_nfc_license"],
+}
+
 cc_defaults {
     name: "nfc_utils_defaults",
     include_dirs: [
@@ -18,6 +27,7 @@
     sanitize: {
         integer_overflow: true,
         misc_undefined: ["bounds"],
+        scs: true,
     },
 
 }
@@ -49,6 +59,7 @@
     static_libs: [
         "libnfcutils",
         "libgmock",
+        "libc++fs"
     ],
     shared_libs: [
         "libbase",
diff --git a/utils/test/config_test.cc b/utils/test/config_test.cc
index b2fde71..62e324c 100644
--- a/utils/test/config_test.cc
+++ b/utils/test/config_test.cc
@@ -16,9 +16,12 @@
 #include <gtest/gtest.h>
 
 #include <config.h>
+#include <filesystem>
 
 namespace {
-const char SIMPLE_CONFIG_FILE[] = "/data/local/tmp/test_config.conf";
+const std::filesystem::path kConfigFile =
+    std::filesystem::temp_directory_path() / "test_config.conf";
+const char* SIMPLE_CONFIG_FILE = kConfigFile.c_str();
 const char SIMPLE_CONFIG[] =
     "# Simple config file test\n\
 STRING_VALUE=\"Hello World!\"\n\
@@ -60,6 +63,9 @@
     fwrite(SIMPLE_CONFIG, 1, sizeof(SIMPLE_CONFIG), fp);
     fclose(fp);
   }
+  void TearDown() override {
+    std::filesystem::remove(kConfigFile);
+  }
 };
 
 TEST(ConfigTestFromString, test_simple_config) {